Skip to content

Commit

Permalink
Add dialogue illustrations
Browse files Browse the repository at this point in the history
  • Loading branch information
SekoiaTree committed Feb 11, 2024
1 parent 75d22df commit 6468bfa
Show file tree
Hide file tree
Showing 15 changed files with 507 additions and 20 deletions.
14 changes: 14 additions & 0 deletions src/main/java/org/ladysnake/blabber/Blabber.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,16 @@
import org.apache.logging.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import org.ladysnake.blabber.api.DialogueActionV2;
import org.ladysnake.blabber.api.DialogueIllustrationType;
import org.ladysnake.blabber.impl.common.BlabberCommand;
import org.ladysnake.blabber.impl.common.BlabberRegistrar;
import org.ladysnake.blabber.impl.common.CommandDialogueAction;
import org.ladysnake.blabber.impl.common.DialogueInitializationException;
import org.ladysnake.blabber.impl.common.PlayerDialogueTracker;
import org.ladysnake.blabber.impl.common.machine.DialogueStateMachine;
import org.ladysnake.blabber.impl.common.model.DialogueIllustrationItem;
import org.ladysnake.blabber.impl.common.model.DialogueIllustrationNbtEntity;
import org.ladysnake.blabber.impl.common.model.DialogueIllustrationSelectorEntity;

public final class Blabber implements ModInitializer {
public static final String MOD_ID = "blabber";
Expand Down Expand Up @@ -137,10 +141,20 @@ public static void registerAction(Identifier actionId, Codec<? extends DialogueA
Registry.register(BlabberRegistrar.ACTION_REGISTRY, actionId, codec);
}

/**
* TODO DOCUMENT
*/
public static void registerIllustration(Identifier illustrationId, DialogueIllustrationType<?> type) {
Registry.register(BlabberRegistrar.ILLUSTRATION_REGISTRY, illustrationId, type);
}

@Override
public void onInitialize() {
BlabberRegistrar.init();
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> BlabberCommand.register(dispatcher));
registerAction(id("command"), CommandDialogueAction.CODEC);
registerIllustration(id("item"), DialogueIllustrationItem.IllustrationType.INSTANCE);
registerIllustration(id("entity_nbt"), DialogueIllustrationNbtEntity.IllustrationType.INSTANCE);
registerIllustration(id("entity"), DialogueIllustrationSelectorEntity.IllustrationType.INSTANCE);
}
}
46 changes: 46 additions & 0 deletions src/main/java/org/ladysnake/blabber/api/DialogueIllustration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.ladysnake.blabber.api;

import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.entity.Entity;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.server.command.ServerCommandSource;
import org.jetbrains.annotations.Nullable;

public interface DialogueIllustration {
/**
* Draw this illustration to the screen.
*
* @param context a context to draw in
* @param textRenderer a text renderer
* @param x the x position it should be drawn relative to
* @param y the y position it should be drawn relative to
* @param mouseX the current x mouse position
* @param mouseY the current y mouse position
* @param tickDelta how much time has passed since last frame
*/
void render(DrawContext context, TextRenderer textRenderer, int x, int y, int mouseX, int mouseY, float tickDelta);

/**
* Write the data this illustration needs to be drawn client-side to a packet
* @param packetByteBuf the packet to write to
*/
void writeToPacket(PacketByteBuf packetByteBuf);

/**
* @return the DialogueIllustrationType that corresponds to this illustration
*/
DialogueIllustrationType<?> getType();

/**
* If this illustration contains some text, this will be parsed *server-side*.
* @param source the context in which this is parsed
* @param sender the player that is going to dialogue
* @return a DialogueIllustration with the required text parsed (often, simply this)
* @throws CommandSyntaxException if the parsing fails
*/
default DialogueIllustration parseText(@Nullable ServerCommandSource source, @Nullable Entity sender) throws CommandSyntaxException {
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.ladysnake.blabber.api;

import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.serialization.Codec;
import net.minecraft.entity.Entity;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.server.command.ServerCommandSource;
import org.jetbrains.annotations.Nullable;
import org.ladysnake.blabber.impl.common.BlabberRegistrar;

import java.util.List;

public abstract class DialogueIllustrationType<T extends DialogueIllustration> {
public static final Codec<DialogueIllustration> CODEC = BlabberRegistrar.ILLUSTRATION_REGISTRY.getCodec()
.dispatch("type", DialogueIllustration::getType, DialogueIllustrationType::getCodec);

public static List<DialogueIllustration> readIllustrationList(PacketByteBuf buf) {
return buf.readList(b -> {
int rawId = b.readInt();
DialogueIllustrationType<?> type = BlabberRegistrar.ILLUSTRATION_REGISTRY.getEntry(rawId).orElseThrow().value();
assert type != null;
return type.readFromPacket(b);
});
}

public static void writeIllustrationList(PacketByteBuf buf, List<DialogueIllustration> illustrations) {
buf.writeCollection(illustrations, (b, i) -> {
// Write the raw ID, then the packet itself.
b.writeInt(BlabberRegistrar.ILLUSTRATION_REGISTRY.getRawId(i.getType()));
i.writeToPacket(b);
});
}

/**
* @return A codec to serialize and deserialize this DialogueIllustration
*/
public abstract Codec<T> getCodec();

/**
* 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
*/

public abstract T readFromPacket(PacketByteBuf buf);
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,20 @@
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ConfirmScreen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
import net.minecraft.client.option.GameOptions;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.registry.Registries;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
import org.ladysnake.blabber.Blabber;
import org.ladysnake.blabber.api.DialogueIllustration;
import org.ladysnake.blabber.impl.common.DialogueScreenHandler;
import org.ladysnake.blabber.impl.common.machine.AvailableChoice;
import org.ladysnake.blabber.impl.common.model.ChoiceResult;
Expand Down Expand Up @@ -218,6 +224,11 @@ public void render(DrawContext context, int mouseX, int mouseY, float tickDelta)
assert client != null;

int y = mainTextMinY;

for (DialogueIllustration illustration : this.handler.getCurrentIllustrations()) {
illustration.render(context, this.textRenderer, mainTextMinX, y, mouseX, mouseY, tickDelta);
}

Text mainText = this.handler.getCurrentText();

context.drawTextWrapped(this.textRenderer, mainText, mainTextMinX, y, mainTextMaxWidth, mainTextColor);
Expand All @@ -230,6 +241,11 @@ public void render(DrawContext context, int mouseX, int mouseY, float tickDelta)
boolean selected = i == this.selectedChoice;
int choiceColor = choice.unavailabilityMessage().isPresent() ? lockedChoiceColor : selected ? selectedChoiceColor : this.choiceColor;
context.drawTextWrapped(this.textRenderer, choice.text(), choiceListMinX, y, choiceListMaxWidth, choiceColor);

for (DialogueIllustration illustration : choice.illustrations()) {
illustration.render(context, this.textRenderer, choiceListMinX, y, mouseX, mouseY, tickDelta);
}

if (selected) {
if (choice.unavailabilityMessage().isPresent()) {
context.drawGuiTexture(lockIconTexture, selectionIconMinX, y + selectionIconMarginTop, selectionIconSize, selectionIconSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import net.minecraft.util.Identifier;
import org.ladysnake.blabber.Blabber;
import org.ladysnake.blabber.api.DialogueActionV2;
import org.ladysnake.blabber.api.DialogueIllustration;
import org.ladysnake.blabber.api.DialogueIllustrationType;
import org.ladysnake.blabber.impl.common.machine.DialogueStateMachine;
import org.ladysnake.blabber.impl.common.packets.ChoiceAvailabilityPacket;
import org.ladysnake.blabber.impl.common.packets.DialogueListPacket;
Expand All @@ -62,6 +64,12 @@ public final class BlabberRegistrar implements EntityComponentInitializer {
public static final Registry<Codec<? extends DialogueActionV2>> ACTION_REGISTRY = FabricRegistryBuilder.from(
new SimpleRegistry<>(ACTION_REGISTRY_KEY, Lifecycle.stable(), false)
).buildAndRegister();

public static final RegistryKey<Registry<DialogueIllustrationType<?>>> ILLUSTRATION_REGISTRY_KEY = RegistryKey.ofRegistry(Blabber.id("dialogue_illustrations"));
public static final Registry<DialogueIllustrationType<?>> ILLUSTRATION_REGISTRY = FabricRegistryBuilder.from(
new SimpleRegistry<>(ILLUSTRATION_REGISTRY_KEY, Lifecycle.stable(), false)
).buildAndRegister();

public static final SuggestionProvider<ServerCommandSource> ALL_DIALOGUES = SuggestionProviders.register(
Blabber.id("available_dialogues"),
(context, builder) -> CommandSource.suggestIdentifiers(DialogueRegistry.getIds(), builder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import org.ladysnake.blabber.Blabber;
import org.ladysnake.blabber.api.DialogueIllustration;
import org.ladysnake.blabber.impl.client.BlabberClient;
import org.ladysnake.blabber.impl.common.machine.AvailableChoice;
import org.ladysnake.blabber.impl.common.machine.DialogueStateMachine;
import org.ladysnake.blabber.impl.common.model.ChoiceResult;
import org.ladysnake.blabber.impl.common.model.DialogueLayout;
import org.ladysnake.blabber.impl.common.packets.ChoiceAvailabilityPacket;

import java.util.List;

public class DialogueScreenHandler extends ScreenHandler {
private final DialogueStateMachine dialogue;
private final @Nullable Entity interlocutor;
Expand Down Expand Up @@ -67,6 +70,10 @@ public Text getCurrentText() {
return this.dialogue.getCurrentText();
}

public List<DialogueIllustration> getCurrentIllustrations() {
return this.dialogue.getCurrentIllustrations();
}

public ImmutableList<AvailableChoice> getAvailableChoices() {
return this.dialogue.getAvailableChoices();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
package org.ladysnake.blabber.impl.common.machine;

import net.minecraft.text.Text;
import org.ladysnake.blabber.api.DialogueIllustration;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

public record AvailableChoice(int originalChoiceIndex, Text text, Optional<Text> unavailabilityMessage) {
public static final AvailableChoice ESCAPE_HATCH = new AvailableChoice(-1, Text.translatable("blabber:dialogue.escape_hatch"), Optional.empty());
public record AvailableChoice(int originalChoiceIndex, Text text, List<DialogueIllustration> illustrations, Optional<Text> unavailabilityMessage) {
public static final AvailableChoice ESCAPE_HATCH = new AvailableChoice(-1, Text.translatable("blabber:dialogue.escape_hatch"), Collections.emptyList(), Optional.empty());
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,9 @@
import org.jetbrains.annotations.Nullable;
import org.ladysnake.blabber.Blabber;
import org.ladysnake.blabber.api.DialogueActionV2;
import org.ladysnake.blabber.api.DialogueIllustration;
import org.ladysnake.blabber.impl.common.InstancedDialogueAction;
import org.ladysnake.blabber.impl.common.model.ChoiceResult;
import org.ladysnake.blabber.impl.common.model.DialogueChoice;
import org.ladysnake.blabber.impl.common.model.DialogueChoiceCondition;
import org.ladysnake.blabber.impl.common.model.DialogueLayout;
import org.ladysnake.blabber.impl.common.model.DialogueState;
import org.ladysnake.blabber.impl.common.model.DialogueTemplate;
import org.ladysnake.blabber.impl.common.model.UnavailableAction;
import org.ladysnake.blabber.impl.common.model.UnavailableDisplay;
import org.ladysnake.blabber.impl.common.model.*;
import org.ladysnake.blabber.impl.common.packets.ChoiceAvailabilityPacket;

import java.util.HashMap;
Expand Down Expand Up @@ -112,6 +106,10 @@ public Text getCurrentText() {
return this.getCurrentState().text();
}

public List<DialogueIllustration> getCurrentIllustrations() {
return this.getCurrentState().illustrations();
}

public ImmutableList<AvailableChoice> getAvailableChoices() {
return this.availableChoices;
}
Expand Down Expand Up @@ -210,6 +208,7 @@ private ImmutableList<AvailableChoice> rebuildAvailableChoices() {
newChoices.add(new AvailableChoice(
i,
c.text(),
c.illustrations(),
whenUnavailable.filter(t -> !available).flatMap(a -> a.message().or(DialogueStateMachine::defaultLockedMessage))
));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,40 @@
import net.minecraft.util.dynamic.Codecs;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;
import org.ladysnake.blabber.api.DialogueIllustration;
import org.ladysnake.blabber.api.DialogueIllustrationType;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

public record DialogueChoice(Text text, String next, Optional<DialogueChoiceCondition> condition) {
public record DialogueChoice(Text text, List<DialogueIllustration> illustrations, String next, Optional<DialogueChoiceCondition> condition) {
public static final Codec<DialogueChoice> CODEC = RecordCodecBuilder.create(instance -> instance.group(
TextCodecs.CODEC.fieldOf("text").forGetter(DialogueChoice::text),
Codecs.createStrictOptionalFieldCodec(Codec.list(DialogueIllustrationType.CODEC), "illustrations", Collections.emptyList()).forGetter(DialogueChoice::illustrations),
Codec.STRING.fieldOf("next").forGetter(DialogueChoice::next),
Codecs.createStrictOptionalFieldCodec(DialogueChoiceCondition.CODEC, "only_if").forGetter(DialogueChoice::condition)
).apply(instance, DialogueChoice::new));

public static void writeToPacket(PacketByteBuf buf, DialogueChoice choice) {
buf.writeText(choice.text());
DialogueIllustrationType.writeIllustrationList(buf, choice.illustrations());
buf.writeString(choice.next());
buf.writeOptional(choice.condition(), DialogueChoiceCondition::writeToPacket);
}

public DialogueChoice(PacketByteBuf buf) {
this(buf.readText(), buf.readString(), buf.readOptional(DialogueChoiceCondition::new));
this(buf.readText(), DialogueIllustrationType.readIllustrationList(buf), buf.readString(), buf.readOptional(DialogueChoiceCondition::new));
}

public DialogueChoice parseText(@Nullable ServerCommandSource source, @Nullable Entity sender) throws CommandSyntaxException {
Optional<DialogueChoiceCondition> parsedCondition = condition().isEmpty() ? Optional.empty() : Optional.of(condition().get().parseText(source, sender));
return new DialogueChoice(Texts.parse(source, text(), sender, 0), next(), parsedCondition);
List<DialogueIllustration> parsed_illustrations = new ArrayList<>(illustrations().size());
for (DialogueIllustration illustration : illustrations()) {
parsed_illustrations.add(illustration.parseText(source, sender));
}
return new DialogueChoice(Texts.parse(source, text(), sender, 0), parsed_illustrations, next(), parsedCondition);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.ladysnake.blabber.impl.common.model;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.client.font.TextRenderer;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.PacketByteBuf;
import org.ladysnake.blabber.api.DialogueIllustration;
import org.ladysnake.blabber.api.DialogueIllustrationType;

public record DialogueIllustrationItem(ItemStack stack, int x, int y) implements DialogueIllustration {
private static final Codec<DialogueIllustrationItem> CODEC = RecordCodecBuilder.create(instance -> instance.group(
ItemStack.CODEC.fieldOf("item").forGetter(DialogueIllustrationItem::stack),
Codec.INT.fieldOf("x").forGetter(DialogueIllustrationItem::x),
Codec.INT.fieldOf("y").forGetter(DialogueIllustrationItem::y)
).apply(instance, DialogueIllustrationItem::new));

@Override
public void render(DrawContext context, TextRenderer textRenderer, int x, int y, int mouseX, int mouseY, float tickDelta) {
// We draw the actual item, then the count and bar and such.
context.drawItem(stack, this.x + x, this.y + y);
context.drawItemInSlot(textRenderer, stack, this.x + x, this.y + y);
}

@Override
public void writeToPacket(PacketByteBuf buf) {
buf.writeNbt(stack.writeNbt(new NbtCompound()));
buf.writeInt(x);
buf.writeInt(y);
}

@Override
public DialogueIllustrationType<?> getType() {
return IllustrationType.INSTANCE;
}

public static class IllustrationType extends DialogueIllustrationType<DialogueIllustrationItem> {
public static final IllustrationType INSTANCE = new IllustrationType();

private IllustrationType() {}

@Override
public Codec<DialogueIllustrationItem> getCodec() {
return DialogueIllustrationItem.CODEC;
}

@Override
public DialogueIllustrationItem readFromPacket(PacketByteBuf buf) {
return new DialogueIllustrationItem(ItemStack.fromNbt(buf.readNbt()), buf.readInt(), buf.readInt());
}
}
}

0 comments on commit 6468bfa

Please sign in to comment.