Skip to content

Commit

Permalink
Add customizable parameters to dialogue layout
Browse files Browse the repository at this point in the history
  • Loading branch information
Pyrofab committed May 20, 2024
1 parent 6c706c3 commit 4e55375
Show file tree
Hide file tree
Showing 24 changed files with 271 additions and 118 deletions.
17 changes: 16 additions & 1 deletion src/main/java/org/ladysnake/blabber/Blabber.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
import net.minecraft.util.Identifier;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.ladysnake.blabber.api.DialogueActionV2;
import org.ladysnake.blabber.api.DialogueIllustrationType;
import org.ladysnake.blabber.api.illustration.DialogueIllustrationType;
import org.ladysnake.blabber.api.layout.DialogueLayoutType;
import org.ladysnake.blabber.impl.common.BlabberRegistrar;
import org.ladysnake.blabber.impl.common.CommandDialogueAction;
import org.ladysnake.blabber.impl.common.DialogueInitializationException;
Expand Down Expand Up @@ -154,11 +156,24 @@ public static void registerIllustration(Identifier illustrationId, DialogueIllus
Registry.register(BlabberRegistrar.ILLUSTRATION_REGISTRY, illustrationId, type);
}

/**
* Register a configurable {@link DialogueLayoutType} to handle the general look of a dialogue.
*
* @param layoutId the identifier used to reference the layout type in dialogue definition files
* @param type the dialogue layout type
*/
@ApiStatus.Experimental
public static void registerLayout(Identifier layoutId, DialogueLayoutType<?> type) {
Registry.register(BlabberRegistrar.LAYOUT_REGISTRY, layoutId, type);
}

@Override
public void onInitialize() {
BlabberRegistrar.init();
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> BlabberCommand.register(dispatcher));
registerAction(id("command"), CommandDialogueAction.CODEC);
registerLayout(id("classic"), BlabberRegistrar.CLASSIC_LAYOUT);
registerLayout(id("rpg"), BlabberRegistrar.RPG_LAYOUT);
registerIllustration(id("group"), DialogueIllustrationCollection.TYPE);
registerIllustration(id("item"), DialogueIllustrationItem.TYPE);
registerIllustration(id("fake_entity"), DialogueIllustrationNbtEntity.TYPE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
import org.jetbrains.annotations.Nullable;
import org.joml.Vector2i;
import org.ladysnake.blabber.Blabber;
import org.ladysnake.blabber.api.DialogueIllustration;
import org.ladysnake.blabber.api.illustration.DialogueIllustration;
import org.ladysnake.blabber.api.layout.DialogueLayout;
import org.ladysnake.blabber.impl.common.DialogueScreenHandler;
import org.ladysnake.blabber.impl.common.illustrations.PositionTransform;
import org.ladysnake.blabber.impl.common.machine.AvailableChoice;
Expand All @@ -48,7 +49,7 @@
import java.util.stream.IntStream;

@ApiStatus.Experimental // half internal, expect some things to change
public class BlabberDialogueScreen extends HandledScreen<DialogueScreenHandler> {
public class BlabberDialogueScreen<P extends DialogueLayout.Params> extends HandledScreen<DialogueScreenHandler> {
public static final List<Identifier> DIALOGUE_ARROWS = IntStream.range(1, 6).mapToObj(i -> Blabber.id("container/dialogue/dialogue_arrow_" + i)).toList();
public static final List<Identifier> DIALOGUE_LOCKS = IntStream.range(1, 4).mapToObj(i -> Blabber.id("container/dialogue/dialogue_lock_" + i)).toList();
public static final int DEFAULT_TITLE_GAP = 20;
Expand Down Expand Up @@ -121,6 +122,11 @@ public BlabberDialogueScreen(DialogueScreenHandler handler, PlayerInventory inve
}
}

@SuppressWarnings("unchecked")
protected P params() {
return (P) this.handler.getLayout().params();
}

@Override
protected void init() {
super.init();
Expand All @@ -129,7 +135,7 @@ protected void init() {

protected void layout() {
this.computeMargins();
this.layoutIllustrationSlots();
this.layoutIllustrationAnchors();
}

protected void computeMargins() {
Expand All @@ -138,7 +144,8 @@ protected void computeMargins() {
this.choiceListMinY = mainTextMinY + this.textRenderer.getWrappedLinesHeight(text, mainTextMaxWidth) + DEFAULT_TITLE_GAP;
}

protected void layoutIllustrationSlots() {
protected void layoutIllustrationAnchors() {
this.illustrationSlots.get(IllustrationAnchor.TEXT_START).set(this.mainTextMinX, this.mainTextMinY);
this.illustrationSlots.get(IllustrationAnchor.SLOT_1).set(this.width * 3/4, this.choiceListMinY);
this.illustrationSlots.get(IllustrationAnchor.SLOT_2).set(this.width * 2/5, this.height * 2/3);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,21 @@
package org.ladysnake.blabber.api.client;

import net.minecraft.client.gui.screen.ingame.HandledScreens;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.ApiStatus;
import org.ladysnake.blabber.api.layout.DialogueLayout;
import org.ladysnake.blabber.api.layout.DialogueLayoutType;
import org.ladysnake.blabber.impl.client.BlabberClient;
import org.ladysnake.blabber.impl.common.DialogueScreenHandler;

@ApiStatus.Experimental
public final class BlabberScreenRegistry {
/**
* Registers a custom screen provider for a {@link org.ladysnake.blabber.impl.common.model.DialogueLayout}.
* Registers a custom screen provider for a {@link org.ladysnake.blabber.api.layout.DialogueLayoutType}.
*/
public static void register(
Identifier layoutId,
HandledScreens.Provider<DialogueScreenHandler, BlabberDialogueScreen> screenProvider
public static <P extends DialogueLayout.Params> void register(
DialogueLayoutType<P> layoutType,
HandledScreens.Provider<DialogueScreenHandler, BlabberDialogueScreen<P>> screenProvider
) {
BlabberClient.registerLayoutScreen(layoutId, screenProvider);
BlabberClient.registerLayoutScreen(layoutType, screenProvider);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <https://www.gnu.org/licenses>.
*/
package org.ladysnake.blabber.api;
package org.ladysnake.blabber.api.illustration;

import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.client.font.TextRenderer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <https://www.gnu.org/licenses>.
*/
package org.ladysnake.blabber.api;
package org.ladysnake.blabber.api.illustration;

import com.mojang.serialization.Codec;
import net.minecraft.network.PacketByteBuf;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Blabber
* Copyright (C) 2022-2024 Ladysnake
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <https://www.gnu.org/licenses>.
*/
package org.ladysnake.blabber.api.layout;

import com.mojang.serialization.Codec;
import net.minecraft.network.PacketByteBuf;
import org.jetbrains.annotations.ApiStatus;

@ApiStatus.Experimental
public record DefaultLayoutParams() implements DialogueLayout.Params {
public static final DefaultLayoutParams DEFAULT = new DefaultLayoutParams();
public static final Codec<DefaultLayoutParams> CODEC = Codec.unit(() -> DefaultLayoutParams.DEFAULT);

public DefaultLayoutParams(PacketByteBuf buf) {
this();
}

public static void writeToPacket(PacketByteBuf buf, DefaultLayoutParams params) {
// NO-OP
}
}
28 changes: 28 additions & 0 deletions src/main/java/org/ladysnake/blabber/api/layout/DialogueLayout.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Blabber
* Copyright (C) 2022-2024 Ladysnake
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <https://www.gnu.org/licenses>.
*/
package org.ladysnake.blabber.api.layout;

import org.jetbrains.annotations.ApiStatus;
import org.ladysnake.blabber.impl.common.BlabberRegistrar;

@ApiStatus.Experimental
public record DialogueLayout<P extends DialogueLayout.Params>(DialogueLayoutType<P> type, P params) {
public static final DialogueLayout<DefaultLayoutParams> DEFAULT = new DialogueLayout<>(BlabberRegistrar.CLASSIC_LAYOUT, DefaultLayoutParams.DEFAULT);

public interface Params { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Blabber
* Copyright (C) 2022-2024 Ladysnake
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; If not, see <https://www.gnu.org/licenses>.
*/
package org.ladysnake.blabber.api.layout;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.util.dynamic.Codecs;
import org.jetbrains.annotations.ApiStatus;
import org.ladysnake.blabber.impl.common.BlabberRegistrar;

import java.util.function.BiConsumer;
import java.util.function.Function;

@ApiStatus.Experimental
public class DialogueLayoutType<P extends DialogueLayout.Params> {
public static final Codec<DialogueLayout<?>> CODEC = BlabberRegistrar.LAYOUT_REGISTRY.getCodec().dispatch(
"type", DialogueLayout::type, DialogueLayoutType::getCodec
);

private final Codec<DialogueLayout<P>> codec;
private final Function<PacketByteBuf, P> read;
private final BiConsumer<PacketByteBuf, P> write;

public DialogueLayoutType(Codec<P> paramsCodec, P defaultParams, Function<PacketByteBuf, P> read, BiConsumer<PacketByteBuf, P> write) {
this.codec = RecordCodecBuilder.create(instance -> instance.group(
Codecs.createStrictOptionalFieldCodec(paramsCodec, "params", defaultParams).forGetter(DialogueLayout::params)
).apply(instance, p -> new DialogueLayout<>(this, p)));
this.read = read;
this.write = write;
}

/**
* @return A codec to serialize and deserialize this layout's parameters
*/
public Codec<DialogueLayout<P>> getCodec() {
return codec;
}

/**
* Parses this type of DialogueIllustration from a packet. The data within should be everything the client needs to render this
* @param buf the packet's data
* @return a newly parsed DialogueIllustration corresponding to this type
*/
@ApiStatus.Experimental
public static <P extends DialogueLayout.Params> DialogueLayout<P> readFromPacket(PacketByteBuf buf) {
@SuppressWarnings("unchecked") DialogueLayoutType<P> type = (DialogueLayoutType<P>) buf.readRegistryValue(BlabberRegistrar.LAYOUT_REGISTRY);
assert type != null;
return new DialogueLayout<>(type, type.read.apply(buf));
}

/**
* Write the data this illustration needs to be drawn client-side to a packet
* @param buf the packet to write to
* @param toWrite the illustration to write
*/
@ApiStatus.Experimental
public static <P extends DialogueLayout.Params> void writeToPacket(PacketByteBuf buf, DialogueLayout<P> toWrite) {
buf.writeRegistryValue(BlabberRegistrar.LAYOUT_REGISTRY, toWrite.type());
toWrite.type().write.accept(buf, toWrite.params());
}
}
29 changes: 16 additions & 13 deletions src/main/java/org/ladysnake/blabber/impl/client/BlabberClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import org.ladysnake.blabber.Blabber;
import org.ladysnake.blabber.api.client.BlabberDialogueScreen;
import org.ladysnake.blabber.api.client.BlabberScreenRegistry;
import org.ladysnake.blabber.api.layout.DialogueLayout;
import org.ladysnake.blabber.api.layout.DialogueLayoutType;
import org.ladysnake.blabber.impl.common.BlabberRegistrar;
import org.ladysnake.blabber.impl.common.DialogueRegistry;
import org.ladysnake.blabber.impl.common.DialogueScreenHandler;
import org.ladysnake.blabber.impl.common.model.DialogueLayout;
import org.ladysnake.blabber.impl.common.packets.ChoiceAvailabilityPacket;
import org.ladysnake.blabber.impl.common.packets.DialogueListPacket;
import org.ladysnake.blabber.impl.common.packets.SelectedDialogueStatePacket;
Expand All @@ -42,13 +42,13 @@
import static io.netty.buffer.Unpooled.buffer;

public final class BlabberClient implements ClientModInitializer {
private static final Map<Identifier, HandledScreens.Provider<DialogueScreenHandler, BlabberDialogueScreen>> screenRegistry = new HashMap<>();
private static final Map<DialogueLayoutType<?>, HandledScreens.Provider<?, ?>> screenRegistry = new HashMap<>();

@Override
public void onInitializeClient() {
BlabberScreenRegistry.register(DialogueLayout.CLASSIC_LAYOUT_ID, BlabberDialogueScreen::new);
BlabberScreenRegistry.register(DialogueLayout.RPG_LAYOUT_ID, BlabberRpgDialogueScreen::new);
HandledScreens.register(BlabberRegistrar.DIALOGUE_SCREEN_HANDLER, BlabberClient::createDialogueScreen);
BlabberScreenRegistry.register(BlabberRegistrar.CLASSIC_LAYOUT, BlabberDialogueScreen::new);
BlabberScreenRegistry.register(BlabberRegistrar.RPG_LAYOUT, BlabberRpgDialogueScreen::new);
HandledScreens.register(BlabberRegistrar.DIALOGUE_SCREEN_HANDLER, (HandledScreens.Provider<DialogueScreenHandler, BlabberDialogueScreen<?>>) BlabberClient::createDialogueScreen);
ClientConfigurationNetworking.registerGlobalReceiver(DialogueListPacket.TYPE, (packet, responseSender) -> DialogueRegistry.setClientIds(packet.dialogueIds()));
ClientPlayNetworking.registerGlobalReceiver(DialogueListPacket.TYPE, (packet, player, responseSender) -> DialogueRegistry.setClientIds(packet.dialogueIds()));
ClientPlayNetworking.registerGlobalReceiver(ChoiceAvailabilityPacket.TYPE, (packet, player, responseSender) -> {
Expand All @@ -63,21 +63,24 @@ public void onInitializeClient() {
});
}

public static void registerLayoutScreen(
Identifier layoutId,
HandledScreens.Provider<DialogueScreenHandler, BlabberDialogueScreen> screenProvider
public static <P extends DialogueLayout.Params> void registerLayoutScreen(
DialogueLayoutType<P> layoutId,
HandledScreens.Provider<DialogueScreenHandler, BlabberDialogueScreen<P>> screenProvider
) {
screenRegistry.put(layoutId, screenProvider);
}

private static BlabberDialogueScreen createDialogueScreen(DialogueScreenHandler handler, PlayerInventory inventory, Text title) {
Identifier layoutType = handler.getLayout().type();
var provider = screenRegistry.get(layoutType);
private static <P extends DialogueLayout.Params> BlabberDialogueScreen<P> createDialogueScreen(DialogueScreenHandler handler, PlayerInventory inventory, Text title) {
@SuppressWarnings("unchecked") DialogueLayoutType<P> layoutType = (DialogueLayoutType<P>) handler.getLayout().type();
@SuppressWarnings("unchecked") HandledScreens.Provider<DialogueScreenHandler, BlabberDialogueScreen<P>> provider =
(HandledScreens.Provider<DialogueScreenHandler, BlabberDialogueScreen<P>>) screenRegistry.get(layoutType);

if (provider != null) {
return provider.create(handler, inventory, title);
}

Blabber.LOGGER.error("(Blabber) No screen provider found for {}", layoutType);
return new BlabberDialogueScreen(handler, inventory, title);
return new BlabberDialogueScreen<>(handler, inventory, title);
}

public static void sendDialogueActionMessage(int choice) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@
import net.minecraft.util.math.ColorHelper;
import org.joml.Matrix4f;
import org.ladysnake.blabber.api.client.BlabberDialogueScreen;
import org.ladysnake.blabber.api.layout.DefaultLayoutParams;
import org.ladysnake.blabber.impl.common.DialogueScreenHandler;
import org.ladysnake.blabber.impl.common.machine.AvailableChoice;
import org.ladysnake.blabber.impl.common.model.IllustrationAnchor;

public class BlabberRpgDialogueScreen extends BlabberDialogueScreen {
public class BlabberRpgDialogueScreen extends BlabberDialogueScreen<DefaultLayoutParams> {
public static final int INSTRUCTIONS_BOTTOM_MARGIN = 6;
public static final int TEXT_TOP_MARGIN = 12;
protected int choiceListMaxY;
Expand All @@ -48,7 +49,7 @@ public BlabberRpgDialogueScreen(DialogueScreenHandler handler, PlayerInventory i
protected void computeMargins() {
super.computeMargins();
this.choiceListMaxWidth = 150;
this.mainTextMaxWidth = 400;
this.mainTextMaxWidth = Math.min(400, this.width);
this.instructionsMinY = this.height - INSTRUCTIONS_BOTTOM_MARGIN - this.textRenderer.getWrappedLinesHeight(instructions, this.width - 5);
this.mainTextMinY = this.height - 60;
this.mainTextMinX = (this.width / 2) - (Math.min(textRenderer.getWidth(handler.getCurrentText()), mainTextMaxWidth) / 2);
Expand All @@ -62,7 +63,8 @@ protected void computeMargins() {
}

@Override
protected void layoutIllustrationSlots() {
protected void layoutIllustrationAnchors() {
super.layoutIllustrationAnchors();
this.illustrationSlots.get(IllustrationAnchor.SLOT_1).set(
this.width / 4,
this.mainTextMinY - TEXT_TOP_MARGIN
Expand Down
Loading

0 comments on commit 4e55375

Please sign in to comment.