feat(redstoner): rechercher dans les boîtes de Shulker #138

Merged
koka merged 1 commits from feature/storage-terminal-shulker-search into main 2026-09-01 16:14:21 +00:00
6 changed files with 45 additions and 12 deletions
+2 -1
View File
@@ -8,9 +8,10 @@ Ce journal suit les **versions du modpack**. Lorsqu'un seul module change, sa ve
## Non publié
Module modifié : **Red-Stoner `0.0.0-alpha.14`**.
Module modifié : **Red-Stoner `0.0.0-alpha.15`**.
- rend le champ de recherche du terminal inactif à louverture puis focalisable au clic, libère le focus au clic extérieur et laisse toujours la touche dinventaire fermer le terminal ;
- permet à la recherche du terminal de retrouver une boîte de Shulker par le nom ou lidentifiant dun objet quelle contient, tout en conservant la boîte comme résultat afin que son aperçu vanilla reste directement consultable ;
## `26.2.0-alpha.227`
+1 -1
View File
@@ -42,7 +42,7 @@ Lalpha.220 transforme le terminal de stockage en véritable menu de conteneur
Lalpha.219 porte l'île finie Minecraft Indev dans `sanctuary:alpha` : 128 × 128 × 64 blocs déterministes, plages, cavernes, minerais, fluides, végétation et maison historique, le tout borné sans chunks parasites. Le cadre 4 × 5 en cobblestone moussue est maintenant actif et crée une paire persistante à une arrivée sûre hors de la maison. Ambiance peut enfin composer localement Golden Days Base puis Alpha uniquement dans cette dimension, sans redistribuer leurs textures et en restaurant exactement la pile précédente. Voir le [contrat Alpha](sanctuary/ALPHA.md), le [contrat des portails](iliketomoveit/PORTALS.md) et le [guide Golden Days](ambiance/GOLDEN_DAYS.md).
Lalpha.218 ajoute le terminal de stockage Red-Stoner : cette demi-dalle verticale se fixe sur un coffre, un coffre piégé ou un baril et donne accès, par pages défilantes de 54 types, à un réseau contigu borné à 128 conteneurs chargés. Les retraits et dépôts sont validés par le serveur, les composants ditems restent strictement séparés et le terminal endgame est exclu du Shop, du Black Market et des récompenses Only Fun.
Lalpha.218 ajoute le terminal de stockage Red-Stoner : cette demi-dalle verticale se fixe sur un coffre, un coffre piégé ou un baril et donne accès, par pages défilantes de 54 types, à un réseau contigu borné à 128 conteneurs chargés. Les retraits et dépôts sont validés par le serveur, les composants ditems restent strictement séparés et le terminal endgame est exclu du Shop, du Black Market et des récompenses Only Fun. La recherche retrouve aussi une boîte de Shulker daprès son contenu direct ; la boîte reste affichée dans la grille afin que son aperçu vanilla soit consultable sans modifier les règles de retrait.
Lalpha.217 tentait de compenser la hauteur trop grave du disque blanc par un facteur OpenAL de `4/3`. Cette compensation est retirée par lalpha.221, qui corrige directement la conversion stéréo vers mono.
+5 -5
View File
@@ -3692,7 +3692,7 @@ tasks.register("verifyMirrorLavenderDrawerRelease") {
def drawerRecipe = file("redstoner/src/main/resources/data/redstoner/recipe/drawer.json")
if (rootProject.pack_version != "26.2.0-alpha.227"
|| rootProject.anotherworld_version != "0.0.0-alpha.57"
|| rootProject.redstoner_version != "0.0.0-alpha.14"
|| rootProject.redstoner_version != "0.0.0-alpha.15"
|| release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version
|| migration.source?.pack_version != "26.2.0-alpha.191"
|| migration.source?.modules != [anotherworld: "0.0.0-alpha.48", redstoner: "0.0.0-alpha.9"]
@@ -4310,7 +4310,7 @@ project(":redstoner") {
"src/main/resources/data/redstoner/recipe/controller.json"))
def terminalRecipe = new JsonSlurper().parse(file(
"src/main/resources/data/redstoner/recipe/storage_terminal.json"))
if (project.version.toString() != "0.0.0-alpha.14"
if (project.version.toString() != "0.0.0-alpha.15"
|| manifest.custom?.sanctuary26?.data_version != 3
|| manifest.custom?.sanctuary26?.network_protocol != 7
|| terminalMigration.source?.pack_version != "26.2.0-alpha.217"
@@ -6659,7 +6659,7 @@ tasks.register("verifyAlpha218Release") {
"file = \"mods/${id}-${version}.jar\""
}
if (rootProject.pack_version != "26.2.0-alpha.227"
|| rootProject.redstoner_version != "0.0.0-alpha.14"
|| rootProject.redstoner_version != "0.0.0-alpha.15"
|| currentModules.findAll { id, version ->
id != "redstoner" && id != "sanctuary" && id != "onlyfun" && id != "iliketomoveit"
}.any {
@@ -6848,7 +6848,7 @@ tasks.register("verifyAlpha220Release") {
def networking = file(
"redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/network/RedStonerNetworking.java").text
if (rootProject.pack_version != "26.2.0-alpha.227"
|| rootProject.redstoner_version != "0.0.0-alpha.14"
|| rootProject.redstoner_version != "0.0.0-alpha.15"
|| migration.source?.pack_version != "26.2.0-alpha.219"
|| migration.source?.modules != [redstoner: "0.0.0-alpha.11"]
|| migration.target?.pack_version != "26.2.0-alpha.220"
@@ -7077,7 +7077,7 @@ tasks.register("verifyAlpha222Release") {
it.path == "mods/jei-26.2-fabric-30.29.0.199.jar"
}
if (rootProject.pack_version != "26.2.0-alpha.227"
|| rootProject.redstoner_version != "0.0.0-alpha.14"
|| rootProject.redstoner_version != "0.0.0-alpha.15"
|| rootProject.sanctuary_version != "0.0.0-alpha.131"
|| migration.source?.pack_version != "26.2.0-alpha.221"
|| migration.source?.modules != [
+1 -1
View File
@@ -14,7 +14,7 @@ mod_version=0.0.0-alpha.0
module_lifecycle=standby
ambiance_version=0.0.0-alpha.22
ambiance_lifecycle=active
redstoner_version=0.0.0-alpha.14
redstoner_version=0.0.0-alpha.15
redstoner_lifecycle=active
anotherworld_version=0.0.0-alpha.57
anotherworld_lifecycle=active
@@ -5,12 +5,16 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.regex.Pattern;
import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.Identifier;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.ShulkerBoxBlock;
/** Server-side matching for the bounded terminal search field. */
public final class StorageTerminalSearch {
private static final int SHULKER_SLOT_COUNT = 27;
private static final Pattern COMBINING_MARKS = Pattern.compile("\\p{M}+");
private static final Pattern NON_ALPHANUMERIC = Pattern.compile("[^\\p{L}\\p{N}]+");
@@ -38,14 +42,27 @@ public final class StorageTerminalSearch {
}
private static boolean matches(ItemStack stack, String[] terms) {
StringBuilder searchable = new StringBuilder(stack.getHoverName().getString());
Identifier id = BuiltInRegistries.ITEM.getKey(stack.getItem());
if (id != null) searchable.append(' ').append(id);
searchable.append(' ').append(stack.getItem().getDescriptionId());
StringBuilder searchable = new StringBuilder();
appendSearchableText(searchable, stack);
if (stack.getItem() instanceof BlockItem blockItem
&& blockItem.getBlock() instanceof ShulkerBoxBlock) {
var contents = stack.get(DataComponents.CONTAINER);
if (contents != null) {
contents.nonEmptyItemCopyStream().limit(SHULKER_SLOT_COUNT).forEach(contained ->
appendSearchableText(searchable, contained));
}
}
String normalized = normalize(searchable.toString());
for (String term : terms) {
if (!normalized.contains(term)) return false;
}
return true;
}
private static void appendSearchableText(StringBuilder searchable, ItemStack stack) {
searchable.append(' ').append(stack.getHoverName().getString());
Identifier id = BuiltInRegistries.ITEM.getKey(stack.getItem());
if (id != null) searchable.append(' ').append(id);
searchable.append(' ').append(stack.getItem().getDescriptionId());
}
}
@@ -14,6 +14,7 @@ import net.minecraft.world.SimpleContainer;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.component.ItemContainerContents;
public final class StorageTerminalSmoke {
private StorageTerminalSmoke() {
@@ -115,6 +116,14 @@ public final class StorageTerminalSmoke {
ItemStack russian = new ItemStack(stackable(Items.REDSTONE), 3);
russian.set(DataComponents.CUSTOM_NAME, Component.literal("Красный камень"));
container.setItem(2, russian);
Holder<Item> shulkerItem = new Holder.Direct<>(Items.SHULKER_BOX, DataComponentMap.builder()
.set(DataComponents.MAX_STACK_SIZE, 1).build());
ItemStack shulker = new ItemStack(shulkerItem);
ItemStack nestedDiamond = new ItemStack(stackable(Items.DIAMOND), 7);
nestedDiamond.set(DataComponents.CUSTOM_NAME, Component.literal("Trésor intérieur"));
shulker.set(DataComponents.CONTAINER, ItemContainerContents.fromItems(List.of(
nestedDiamond, new ItemStack(stackable(Items.OAK_LOG), 32))));
container.setItem(3, shulker);
List<StorageTerminalInventory.Entry> entries = StorageTerminalInventory.aggregate(List.of(container));
require(StorageTerminalSearch.filter(entries, "minecraft:cobblestone").size() == 1,
@@ -125,6 +134,12 @@ public final class StorageTerminalSmoke {
"Terminal search did not ignore accents in a custom name");
require(StorageTerminalSearch.filter(entries, "красный камень").size() == 1,
"Terminal search did not preserve non-Latin keyboard input");
require(StorageTerminalSearch.filter(entries, "minecraft:oak_log").size() == 1,
"Terminal search did not find an item id inside a Shulker box");
require(StorageTerminalSearch.filter(entries, "tresor interieur oak log").size() == 1,
"Terminal search did not index the composed contents of a Shulker box");
require(StorageTerminalSearch.filter(entries, "shulker box").size() == 1,
"Searching Shulker contents broke matching against the box itself");
require(StorageTerminalSearch.filter(entries, "missing").isEmpty(),
"Terminal search retained an unrelated item");
}