Skip to content

Commit

Permalink
Merge pull request #24 from enjarai/1.21
Browse files Browse the repository at this point in the history
Backport two funny features to 1.21(.1)
  • Loading branch information
gliscowo authored Dec 12, 2024
2 parents 3205f28 + 71fe7fe commit 60f132d
Show file tree
Hide file tree
Showing 15 changed files with 237 additions and 47 deletions.
61 changes: 35 additions & 26 deletions src/main/java/io/wispforest/lavender/book/Book.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public final class Book {
private final @Nullable Identifier introEntry;
private final boolean displayUnreadEntryNotifications;
private final boolean displayCompletion;
private final @Nullable ToastSettings newEntriesToast;
private final Map<String, String> zeroArgMacros = new HashMap<>();
private final Map<Pattern, Macro> macros = new HashMap<>();

Expand All @@ -58,17 +59,18 @@ public final class Book {
private @Nullable Entry landingPage = null;

public Book(
Identifier id,
@Nullable Identifier extend,
@Nullable Identifier texture,
@Nullable Identifier dynamicBookModel,
@Nullable Text dynamicBookName,
@Nullable SoundEvent openSound,
@Nullable SoundEvent flippingSound,
@Nullable Identifier introEntry,
boolean displayUnreadEntryNotifications,
boolean displayCompletion,
Map<String, String> macros
Identifier id,
@Nullable Identifier extend,
@Nullable Identifier texture,
@Nullable Identifier dynamicBookModel,
@Nullable Text dynamicBookName,
@Nullable SoundEvent openSound,
@Nullable SoundEvent flippingSound,
@Nullable Identifier introEntry,
boolean displayUnreadEntryNotifications,
boolean displayCompletion,
@Nullable ToastSettings newEntriesToast,
Map<String, String> macros
) {
this.id = id;
this.extend = extend;
Expand All @@ -80,6 +82,7 @@ public Book(
this.introEntry = introEntry;
this.displayUnreadEntryNotifications = displayUnreadEntryNotifications;
this.displayCompletion = displayCompletion;
this.newEntriesToast = newEntriesToast;

macros.forEach((macro, replacement) -> {
int argCount = (int) MACRO_ARG_PATTERN.matcher(replacement).results().count();
Expand All @@ -104,8 +107,8 @@ public Book(

parts.add(result.toString());
this.macros.put(
Pattern.compile(Pattern.quote(macro) + "\\(" + Stream.generate(() -> "(.*)").limit(argCount).collect(Collectors.joining(",")) + "\\)"),
new Macro(parts, argIndices)
Pattern.compile(Pattern.quote(macro) + "\\(" + Stream.generate(() -> "(.*)").limit(argCount).collect(Collectors.joining(",")) + "\\)"),
new Macro(parts, argIndices)
);
} else {
this.zeroArgMacros.put(macro, replacement);
Expand Down Expand Up @@ -135,8 +138,8 @@ public Collection<Entry> orphanedEntries() {

public @Nullable Entry introEntry() {
return this.introEntry != null
? this.entryById(this.introEntry)
: null;
? this.entryById(this.introEntry)
: null;
}

public @Nullable Entry entryById(Identifier entryId) {
Expand Down Expand Up @@ -238,6 +241,10 @@ public SoundEvent flippingSound() {
return this.flippingSound;
}

public @Nullable ToastSettings newEntriesToast() {
return this.newEntriesToast;
}

public int countVisibleEntries(ClientPlayerEntity player) {
int visible = 0;
for (var entry : this.entriesById.values()) {
Expand Down Expand Up @@ -290,18 +297,18 @@ String expandMacros(Identifier entry, String input) {

if (scans >= 1000) {
Lavender.LOGGER.warn(
"Preprocessing of entry {} in book {} failed: Macro expansion proceeded for over 1000 scans, a circular macro invocation is likely",
entry,
this.id
"Preprocessing of entry {} in book {} failed: Macro expansion proceeded for over 1000 scans, a circular macro invocation is likely",
entry,
this.id
);

return """
{red}**Entry processing failed:**{}
Macro expansion proceeded for over 1000 scans without reaching
a result - this is almost definitely due to a circular macro invocation
""";
{red}**Entry processing failed:**{}
Macro expansion proceeded for over 1000 scans without reaching
a result - this is almost definitely due to a circular macro invocation
""";
} else {
return builder.toString();
}
Expand All @@ -322,8 +329,8 @@ void addEntry(Entry entry) {
for (var category : entry.categories()) {
if (this.categories.containsKey(category)) {
this.entriesByCategory
.computeIfAbsent(this.categories.get(category), $ -> new ArrayList<>())
.add(entry);
.computeIfAbsent(this.categories.get(category), $ -> new ArrayList<>())
.add(entry);
} else {
throw new RuntimeException("Could not load entry '" + entry.id() + "' because category '" + category + "' was not found in book '" + this.effectiveId() + "'");
}
Expand Down Expand Up @@ -372,4 +379,6 @@ String apply(List<String> args) {
return result.toString();
}
}

public record ToastSettings(ItemStack iconStack, Text bookName, @Nullable Identifier backgroundSprite) {}
}
24 changes: 22 additions & 2 deletions src/main/java/io/wispforest/lavender/book/BookContentLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,27 @@ public static void reloadContents(ResourceManager manager) {
requiredAdvancements.add(advancementId);
}

var entry = new Entry(identifier, entryCategories, title, icon, secret, ordinal, requiredAdvancements.build(), associatedItems.build(), markdown.content);
var additionalSearchTerms = new ImmutableSet.Builder<String>();
for (var termElement : JsonHelper.getArray(markdown.meta, "additional_search_terms", new JsonArray())) {
if (!termElement.isJsonPrimitive()) continue;

var term = termElement.getAsString();
// Lowercase the term in advance to save a little time when searching.
additionalSearchTerms.add(term.toLowerCase(Locale.ROOT));
}

var entry = new Entry(
identifier,
entryCategories,
title,
icon,
secret,
ordinal,
requiredAdvancements.build(),
associatedItems.build(),
additionalSearchTerms.build(),
markdown.content
);
if (entry.id().getPath().equals("landing_page")) {
book.setLandingPage(entry);
} else {
Expand Down Expand Up @@ -258,7 +278,7 @@ private static Collection<ItemStack> itemsFromString(String itemsString) {
return entryList.get().stream().map(RegistryEntry::value).map(Item::getDefaultStack).toList();
}

private static ItemStack itemStackFromString(String stackString) {
public static ItemStack itemStackFromString(String stackString) {
try {
var parsed = new ItemStringReader(MinecraftClient.getInstance().world.getRegistryManager()).consume(new StringReader(stackString));

Expand Down
33 changes: 30 additions & 3 deletions src/main/java/io/wispforest/lavender/book/BookLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@
import io.wispforest.lavender.Lavender;
import io.wispforest.lavender.client.BookBakedModel;
import net.fabricmc.fabric.api.client.model.loading.v1.ModelLoadingPlugin;
import net.minecraft.client.util.ModelIdentifier;
import net.minecraft.registry.Registries;
import net.minecraft.resource.ResourceFinder;
import net.minecraft.resource.ResourceManager;
import net.minecraft.text.Text;
import net.minecraft.text.TextCodecs;
import net.minecraft.util.Identifier;
import net.minecraft.util.JsonHelper;
import net.minecraft.util.Util;
import org.jetbrains.annotations.Nullable;

import java.io.IOException;
Expand Down Expand Up @@ -89,7 +87,36 @@ public static void reload(ResourceManager manager) {
var displayUnreadEntryNotifications = JsonHelper.getBoolean(bookObject, "display_unread_entry_notifications", true);
var macros = GSON.fromJson(JsonHelper.getObject(bookObject, "macros", new JsonObject()), MACROS_TOKEN);

var book = new Book(resourceId, extendId, textureId, dynamicBookModelId, dynamicBookName, openSoundEvent, flippingSoundEvent, introEntryId, displayUnreadEntryNotifications, displayCompletion, macros);
Book.ToastSettings newEntriesToast = null;
if (bookObject.has("new_entries_toast")) {
var toastObject = bookObject.getAsJsonObject("new_entries_toast");

Identifier backgroundSprite = null;
if (toastObject.has("background_sprite")) {
backgroundSprite = Identifier.of(JsonHelper.getString(toastObject, "background_sprite"));
}

newEntriesToast = new Book.ToastSettings(
BookContentLoader.itemStackFromString(JsonHelper.getString(toastObject, "icon_stack")),
TextCodecs.CODEC.parse(JsonOps.INSTANCE, toastObject.get("book_name")).getOrThrow(JsonParseException::new),
backgroundSprite
);
}

var book = new Book(
resourceId,
extendId,
textureId,
dynamicBookModelId,
dynamicBookName,
openSoundEvent,
flippingSoundEvent,
introEntryId,
displayUnreadEntryNotifications,
displayCompletion,
newEntriesToast,
macros
);
LOADED_BOOKS.put(resourceId, book);
if (extendId == null) VISIBLE_BOOKS.put(resourceId, book);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package io.wispforest.lavender.book;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.client.MinecraftClient;

@FunctionalInterface
public interface ClientNewEntriesUnlockedCallback {

Event<ClientNewEntriesUnlockedCallback> EVENT = EventFactory.createArrayBacked(ClientNewEntriesUnlockedCallback.class, callbacks -> (client, book, newEntryCount) -> {
for (var callback : callbacks) {
callback.newEntriesUnlocked(client, book, newEntryCount);
}
});

void newEntriesUnlocked(MinecraftClient client, Book book, int newEntryCount);
}
3 changes: 2 additions & 1 deletion src/main/java/io/wispforest/lavender/book/Entry.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package io.wispforest.lavender.book;

import com.google.common.collect.ImmutableSet;
import io.wispforest.lavender.mixin.ClientAdvancementManagerAccessor;
import io.wispforest.lavender.mixin.access.ClientAdvancementManagerAccessor;
import io.wispforest.owo.ui.core.Component;
import io.wispforest.owo.ui.core.Sizing;
import net.minecraft.client.network.ClientPlayerEntity;
Expand All @@ -20,6 +20,7 @@ public record Entry(
int ordinal,
ImmutableSet<Identifier> requiredAdvancements,
ImmutableSet<ItemStack> associatedItems,
ImmutableSet<String> additionalSearchTerms,
String content
) implements Book.BookmarkableElement {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -614,9 +614,10 @@ protected List<FlowLayout> buildEntryIndex(Collection<Entry> entries, boolean re
if (!entryVisible) return;

var entryTitle = entry.title().toLowerCase(Locale.ROOT);
for (var term : filter) {
if (!entryTitle.contains(term)) return;
}

var entryMatches = Arrays.stream(filter).allMatch(entryTitle::contains)
|| entry.additionalSearchTerms().stream().anyMatch(term -> Arrays.stream(filter).allMatch(term::contains));
if (!entryMatches) return;
}

FlowLayout indexItem;
Expand Down
20 changes: 11 additions & 9 deletions src/main/java/io/wispforest/lavender/client/LavenderClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

import io.wispforest.lavender.Lavender;
import io.wispforest.lavender.LavenderCommands;
import io.wispforest.lavender.book.Book;
import io.wispforest.lavender.book.BookContentLoader;
import io.wispforest.lavender.book.BookLoader;
import io.wispforest.lavender.book.LavenderBookItem;
import io.wispforest.lavender.book.*;
import io.wispforest.lavender.md.ItemListComponent;
import io.wispforest.lavender.structure.LavenderStructures;
import io.wispforest.owo.ui.component.Components;
Expand All @@ -28,7 +25,6 @@
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
import net.fabricmc.fabric.api.networking.v1.PayloadTypeRegistry;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.item.Items;
Expand Down Expand Up @@ -93,11 +89,11 @@ public void onInitializeClient() {
if (associatedEntry == null || !associatedEntry.canPlayerView(client.player)) return;

container.child(Containers.verticalFlow(Sizing.content(), Sizing.content())
.child(associatedEntry.iconFactory().apply(Sizing.fixed(16)).margins(Insets.of(0, 1, 0, 1)))
.child(Components.item(LavenderBookItem.itemOf(book)).sizing(Sizing.fixed(8)).positioning(Positioning.absolute(9, 9)).zIndex(50)));
.child(associatedEntry.iconFactory().apply(Sizing.fixed(16)).margins(Insets.of(0, 1, 0, 1)))
.child(Components.item(LavenderBookItem.itemOf(book)).sizing(Sizing.fixed(8)).positioning(Positioning.absolute(9, 9)).zIndex(50)));
container.child(Containers.verticalFlow(Sizing.content(), Sizing.content())
.child(Components.label(Text.literal(associatedEntry.title())).shadow(true))
.child(Components.label(Text.translatable(client.player.isSneaking() ? "text.lavender.entry_hud.click_to_view" : "text.lavender.entry_hud.sneak_to_view"))));
.child(Components.label(Text.literal(associatedEntry.title())).shadow(true))
.child(Components.label(Text.translatable(client.player.isSneaking() ? "text.lavender.entry_hud.click_to_view" : "text.lavender.entry_hud.sneak_to_view"))));
});
});

Expand All @@ -123,6 +119,12 @@ public void onInitializeClient() {
return ActionResult.FAIL;
});

ClientNewEntriesUnlockedCallback.EVENT.register((client, book, newEntryCount) -> {
if (book.newEntriesToast() != null) {
client.getToastManager().add(new NewEntriesToast(book.newEntriesToast()));
}
});

ClientPlayNetworking.registerGlobalReceiver(Lavender.WorldUUIDPayload.ID, (payload, context) -> {
currentWorldId = payload.worldUuid();
});
Expand Down
33 changes: 33 additions & 0 deletions src/main/java/io/wispforest/lavender/client/NewEntriesToast.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.wispforest.lavender.client;

import io.wispforest.lavender.Lavender;
import io.wispforest.lavender.book.Book;
import io.wispforest.owo.ui.base.BaseOwoToast;
import io.wispforest.owo.ui.component.Components;
import io.wispforest.owo.ui.container.Containers;
import io.wispforest.owo.ui.container.StackLayout;
import io.wispforest.owo.ui.core.Insets;
import io.wispforest.owo.ui.core.Sizing;
import io.wispforest.owo.ui.core.VerticalAlignment;
import net.minecraft.client.MinecraftClient;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;

@SuppressWarnings("UnstableApiUsage")
public class NewEntriesToast extends BaseOwoToast<StackLayout> {

public static final Identifier TEXTURE = Lavender.id("new_entries_toast");

public NewEntriesToast(Book.ToastSettings settings) {
super(
() -> Containers.stack(Sizing.content(), Sizing.content()).configure(component -> component
.child(Components.sprite(MinecraftClient.getInstance().getGuiAtlasManager().getSprite(settings.backgroundSprite() != null ? settings.backgroundSprite() : TEXTURE)))
.child(Containers.horizontalFlow(Sizing.content(), Sizing.content())
.child(Components.item(settings.iconStack()).margins(Insets.of(0, 0, 8, 6)))
.child(Components.label(Text.translatable("text.lavender.toast.new_entries", settings.bookName())))
.verticalAlignment(VerticalAlignment.CENTER))
.verticalAlignment(VerticalAlignment.CENTER)),
(baseOwoToast, time) -> time <= 5000 ? Visibility.SHOW : Visibility.HIDE
);
}
}
Loading

0 comments on commit 60f132d

Please sign in to comment.