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
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package xyz.nucleoid.plasmid.client.impl;

import com.mojang.serialization.Lifecycle;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.world.CreateWorldScreen;
import net.minecraft.client.gui.screen.world.InitialWorldOptions;
import net.minecraft.client.gui.screen.world.WorldCreator;
import net.minecraft.client.world.GeneratorOptionsHolder;
import net.minecraft.registry.ServerDynamicRegistryType;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.resource.featuretoggle.FeatureFlags;
import net.minecraft.world.Difficulty;
import net.minecraft.world.GameMode;
import net.minecraft.world.GameRules;
import net.minecraft.world.gen.FlatLevelGeneratorPresets;
import net.minecraft.world.level.LevelInfo;
import net.minecraft.world.level.LevelProperties;
import xyz.nucleoid.plasmid.api.game.config.GameConfig;
import xyz.nucleoid.plasmid.api.game.player.JoinIntent;
import xyz.nucleoid.plasmid.client.impl.screen.GamesScreen;
import xyz.nucleoid.plasmid.impl.game.manager.GameSpaceManagerImpl;
import xyz.nucleoid.plasmid.impl.game.manager.HasForcedGameSpace;

import java.util.Set;

public final class GameWorldCreator {
public static final String WORLD_NAME = "PlasmidGame";
public static final InitialWorldOptions OPTIONS = new InitialWorldOptions(WorldCreator.Mode.SURVIVAL, Set.of(), FlatLevelGeneratorPresets.THE_VOID);

private GameWorldCreator() {
}

public static void create(MinecraftClient client, GeneratorOptionsHolder generatorOptionsHolder, RegistryEntry<GameConfig<?>> game) {
var dimensionsConfig = generatorOptionsHolder.selectedDimensions()
.toConfig(generatorOptionsHolder.dimensionOptionsRegistry());

var registries = generatorOptionsHolder.combinedDynamicRegistries()
.with(ServerDynamicRegistryType.DIMENSIONS, dimensionsConfig.toDynamicRegistryManager());

var levelInfo = new LevelInfo(
WORLD_NAME,
GameMode.SURVIVAL,
false,
Difficulty.NORMAL,
false,
new GameRules(FeatureFlags.DEFAULT_ENABLED_FEATURES),
generatorOptionsHolder.dataConfiguration()
);

var levelProperties = new LevelProperties(
levelInfo,
generatorOptionsHolder.generatorOptions(),
dimensionsConfig.specialWorldProperty(),
Lifecycle.stable()
);

CreateWorldScreen.showMessage(client, GamesScreen.PREPARING_MESSAGE);

var session = CreateWorldScreen.createSession(client, levelInfo.getLevelName(), null);

client.createIntegratedServerLoader().startNewWorld(
session.orElseThrow(),
generatorOptionsHolder.dataPackContents(),
registries,
levelProperties
);

// Server is created by now, so a game space can be created
var server = client.getServer();
var gameSpace = GameSpaceManagerImpl.get().open(game).join();

((HasForcedGameSpace) server).setForcedGameSpace(gameSpace);

// Add existing players in the server to the game space just in case
var players = server.getPlayerManager().getPlayerList();
gameSpace.getPlayers().offer(players, JoinIntent.PLAY);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package xyz.nucleoid.plasmid.client.impl;

import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents;
import net.fabricmc.fabric.api.client.screen.v1.Screens;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.TitleScreen;
import net.minecraft.client.gui.widget.ButtonWidget;
import xyz.nucleoid.plasmid.client.impl.screen.GamesScreen;

public class PlasmidClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
ScreenEvents.AFTER_INIT.register((client, screen, width, height) -> {
if (screen instanceof TitleScreen) {
addTitleScreenButton(client, screen, width, height);
}
});
}

private static void addTitleScreenButton(MinecraftClient client, Screen screen, int width, int height) {
var buttons = Screens.getButtons(screen);

int x = (width - ButtonWidget.field_49479) / 2;
int y = 0;

int index = 0;
int insertIndex = 0;

for (var button : buttons) {
if (button.getX() == x && button.getWidth() == ButtonWidget.field_49479) {
if (button.getY() > y) {
y = button.getY();
insertIndex = index + 1;
}

button.setY(button.getY() - 24);
}

index += 1;
}

var gamesButton = ButtonWidget.builder(GamesScreen.TITLE, button -> {
GamesScreen.show(client, screen);
})
.position(x, y)
.width(ButtonWidget.field_49479)
.build();

buttons.add(insertIndex, gamesButton);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package xyz.nucleoid.plasmid.client.impl.screen;

import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.Element;
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
import net.minecraft.client.input.KeyCodes;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.sound.PositionedSoundInstance;
import net.minecraft.registry.entry.RegistryEntry;
import net.minecraft.screen.ScreenTexts;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.util.Colors;
import net.minecraft.util.Identifier;
import net.minecraft.util.Util;
import xyz.nucleoid.plasmid.api.game.config.GameConfig;

public class GameListEntry extends AlwaysSelectedEntryListWidget.Entry<GameListEntry> {
private static final Identifier SLOT_TEXTURE = Identifier.ofVanilla("container/slot");

protected final RegistryEntry<GameConfig<?>> game;

protected final Text name;
protected final Text description;

private final GamesScreen screen;
private final TextRenderer textRenderer;

private long lastClickTime;

public GameListEntry(RegistryEntry<GameConfig<?>> game, GamesScreen screen, TextRenderer textRenderer) {
this.game = game;
this.name = GameConfig.name(this.game);

var description = this.game.value().description();
this.description = description.isEmpty() ? null : ScreenTexts.joinLines(description);

this.screen = screen;
this.textRenderer = textRenderer;
}

private void activate() {
this.screen.client.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1));

this.screen.setSelectedGame(this.game);
this.screen.play();
}

@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
if (Util.getMeasuringTimeMs() - this.lastClickTime >= Element.MAX_DOUBLE_CLICK_INTERVAL) {
this.lastClickTime = Util.getMeasuringTimeMs();
return super.mouseClicked(mouseX, mouseY, button);
}

this.activate();
return true;
}

@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
if (KeyCodes.isToggle(keyCode)) {
this.activate();
return true;
}

return super.keyPressed(keyCode, scanCode, modifiers);
}

@Override
public void render(DrawContext context, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
context.drawGuiTexture(RenderLayer::getGuiTextured, SLOT_TEXTURE, x + 1, y + 1, 18, 18);

context.drawItemWithoutEntity(this.game.value().icon(), x + 2, y + 2);
context.drawStackOverlay(this.textRenderer, this.game.value().icon(), x + 2, y + 2);

context.drawTextWithShadow(this.textRenderer, this.name, x + 18 + 5, y + 6, Colors.WHITE);
}

@Override
public Text getNarration() {
var contents = this.description == null ? this.name : ScreenTexts.joinSentences(this.name, this.description);
return Text.translatable("narrator.select", contents);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package xyz.nucleoid.plasmid.client.impl.screen;

import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.widget.AlwaysSelectedEntryListWidget;
import net.minecraft.registry.DynamicRegistryManager;
import net.minecraft.registry.Registry;
import net.minecraft.registry.entry.RegistryEntry;
import xyz.nucleoid.plasmid.api.game.config.GameConfig;
import xyz.nucleoid.plasmid.api.game.config.GameConfigs;

import java.util.Comparator;
import java.util.Locale;

public class GameListWidget extends AlwaysSelectedEntryListWidget<GameListEntry> {
private static final Comparator<RegistryEntry<GameConfig<?>>> ENTRY_ORDERING = Comparator.comparing(
entry -> GameConfig.name(entry).getString(),
String::compareToIgnoreCase
);

private final Registry<GameConfig<?>> registry;
private final GamesScreen screen;

private String search = "";

public GameListWidget(DynamicRegistryManager registryManager, GamesScreen screen) {
super(screen.client, screen.width, screen.height - 85, 48, 24);

this.registry = registryManager.getOrThrow(GameConfigs.REGISTRY_KEY);
this.screen = screen;

this.updateEntries();
}

public void setSearch(String search) {
if (!this.search.equalsIgnoreCase(search)) {
this.search = search.toLowerCase(Locale.ROOT);
this.updateEntries();
}
}

private void updateEntries() {
this.clearEntries();

this.registry.streamEntries()
.filter(entry -> {
String name = GameConfig.name(entry).getString().toLowerCase(Locale.ROOT);
return name.contains(this.search);
})
.sorted(ENTRY_ORDERING)
.map(entry -> new GameListEntry(entry, this.screen, this.client.textRenderer))
.forEachOrdered(this::addEntry);

this.refreshScroll();
}

@Override
public void setSelected(GameListEntry entry) {
super.setSelected(entry);
this.screen.setSelectedGame(entry == null ? null : entry.game);
}

@Override
public void renderWidget(DrawContext context, int mouseX, int mouseY, float delta) {
super.renderWidget(context, mouseX, mouseY, delta);

var entry = this.getHoveredEntry();

if (entry != null && entry.description != null) {
this.screen.setTooltip(entry.description);
}
}
}
Loading