diff --git a/CHANGELOG.md b/CHANGELOG.md index a2d2031..2d8a05c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,8 +8,10 @@ Ce journal suit les **versions du modpack**. Lorsqu'un seul module change, sa ve ## Non publié -Module modifié : **Sanctuary `0.0.0-alpha.137`**. +Modules modifiés : **Sanctuary `0.0.0-alpha.137`** et **Red-Stoner `0.0.0-alpha.18`**. +- transforme le panneau de trophées en plaque verticale de chêne, corrige le texte auparavant masqué et utilise les quatre lignes pour le titre paginé ainsi que les trois places du podium ; +- permet de passer à la page suivante d’un clic droit et de revenir à la précédente avec `Maj` + clic droit, sans changer les IDs, les sauvegardes Red-Stoner v4 ni le protocole réseau 7. - garantit sur chaque niveau de la Backroom un coffre par cellule de 3 × 3 chunks dans les nouveaux chunks, au lieu d’un coffre aléatoire réparti entre les cinq niveaux ; - resserre aussi la grille des lits de sortie de 10 × 10 à 3 × 3 chunks sur chacun des cinq niveaux afin qu’ils soient réellement trouvables ; - ne change ni le butin ordinaire des coffres, ni les données Sanctuary v15, ni le protocole réseau 24 ; les nouveaux coffres et lits apparaissent dans les chunks qui n’ont pas encore été générés. diff --git a/README.md b/README.md index 2f474e4..519446c 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ Les descriptions FR/EN/RU sont déclarées dans chaque `fabric.mod.json` et dans Version courante du pack distribué : **`26.2.0-alpha.230`**. Cette release distribue Sanctuary **`0.0.0-alpha.136`** et Red-Stoner **`0.0.0-alpha.17`** ; les huit autres modules conservent leur version issue de l'alpha.229. +Le prochain Red-Stoner **`0.0.0-alpha.18`** présente le panneau de trophées comme une plaque verticale de chêne et rend enfin ses quatre lignes lisibles : titre et numéro de page, puis les trois places du podium. Un clic droit avance d’une page et `Maj` + clic droit revient à la précédente ; les données v4 et le protocole réseau 7 restent inchangés. + L’alpha.230 attribue les quêtes communautaires terminées à leur preneur et répartit les lits de sortie rares sur chacun des cinq niveaux de la Backroom. Elle ajoute aussi les classements publics et le panneau mural `redstoner:trophy_panel`, corrige la projection des couleurs et motifs de la cape blanche avec les sprites de bouclier, et permet d’équiper une poule adulte avec l’armure de loup vanilla en écailles de tatou. Les sauvegardes restent compatibles ; Sanctuary passe aux données v15 et Red-Stoner aux données v4 sans changer leurs protocoles réseau 24 et 7. L’alpha.229 ajoute au terminal les tris alphabétique, par quantité croissante et par quantité décroissante. Le tri ne change que sur demande explicite et les rafraîchissements périodiques conservent l’ordre ainsi que les objets sous le curseur. Les sauvegardes, les données Red-Stoner v3 et le protocole réseau 7 restent compatibles. diff --git a/build.gradle b/build.gradle index 16d5873..6c89917 100644 --- a/build.gradle +++ b/build.gradle @@ -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.230" || rootProject.anotherworld_version != "0.0.0-alpha.57" - || rootProject.redstoner_version != "0.0.0-alpha.17" + || rootProject.redstoner_version != "0.0.0-alpha.18" || 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"] @@ -4225,13 +4225,20 @@ project(":redstoner") { "src/main/java/fr/koka99cab/sanctuary26/redstoner/registry/RedStonerRegistries.java").text def panel = file( "src/main/java/fr/koka99cab/sanctuary26/redstoner/block/entity/TrophyPanelBlockEntity.java").text + def block = file( + "src/main/java/fr/koka99cab/sanctuary26/redstoner/block/TrophyPanelBlock.java").text + def renderer = file( + "src/main/java/fr/koka99cab/sanctuary26/redstoner/client/renderer/TrophyPanelBlockEntityRenderer.java").text + def model = new JsonSlurper().parse(file( + "src/main/resources/assets/redstoner/models/block/trophy_panel.json")) def rankingApi = rootProject.file( "sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/ranking/SanctuaryRankingApi.java").text def rankingData = rootProject.file( "sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/ranking/SanctuaryRankingData.java").text def requiredKeys = [ "block.redstoner.trophy_panel", "message.redstoner.trophy_panel.not_owner", - "message.redstoner.trophy_panel.configured"] + "message.redstoner.trophy_panel.configured", "block.redstoner.trophy_panel.page_title", + "block.redstoner.trophy_panel.podium"] def redstonerLocales = ["fr_fr", "en_us", "ru_ru"].collect { new JsonSlurper().parse(file("src/main/resources/assets/redstoner/lang/${it}.json")) } @@ -4239,7 +4246,7 @@ project(":redstoner") { new JsonSlurper().parse(rootProject.file( "sanctuary/src/main/resources/assets/sanctuary/lang/${it}.json")) } - if (rootProject.redstoner_version != "0.0.0-alpha.17" + if (rootProject.redstoner_version != "0.0.0-alpha.18" || rootProject.sanctuary_version != "0.0.0-alpha.137" || redstonerManifest.custom?.sanctuary26?.data_version != 4 || redstonerManifest.custom?.sanctuary26?.network_protocol != 7 @@ -4256,6 +4263,15 @@ project(":redstoner") { || !panel.contains("REFRESH_INTERVAL_TICKS = 20") || !panel.contains("CLIENT_SNAPSHOT_TAG") || !panel.contains("PAGE_CODEC.listOf(0, TrophyPanelRules.MAX_PAGES)") + || !panel.contains("public boolean previousPage()") + || !block.contains("player.isSecondaryUseActive()") + || !renderer.contains("TrophyPanelRenderState.LINE_COUNT") + || !renderer.contains("state.lightCoords, TEXT_COLOR, 0, 0") + || model.textures?.wood != "minecraft:block/oak_planks" + || model.textures?.containsKey("screen") + || model.elements?.size() != 1 + || model.elements[0].from != [0, 0, 14] + || model.elements[0].to != [16, 16, 16] || !rankingApi.contains("public static RankingSnapshot snapshot") || !rankingApi.contains("!player.isCreative() && !player.isSpectator()") || !rankingData.contains("vanillaStatsImported") @@ -4400,7 +4416,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.17" + if (project.version.toString() != "0.0.0-alpha.18" || manifest.custom?.sanctuary26?.data_version != 4 || manifest.custom?.sanctuary26?.network_protocol != 7 || terminalMigration.source?.pack_version != "26.2.0-alpha.217" @@ -6751,7 +6767,7 @@ tasks.register("verifyAlpha218Release") { "file = \"mods/${id}-${version}.jar\"" } if (rootProject.pack_version != "26.2.0-alpha.230" - || rootProject.redstoner_version != "0.0.0-alpha.17" + || rootProject.redstoner_version != "0.0.0-alpha.18" || currentModules.findAll { id, version -> id != "redstoner" && id != "sanctuary" && id != "onlyfun" && id != "iliketomoveit" }.any { @@ -6940,7 +6956,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.230" - || rootProject.redstoner_version != "0.0.0-alpha.17" + || rootProject.redstoner_version != "0.0.0-alpha.18" || 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" @@ -7169,7 +7185,7 @@ tasks.register("verifyAlpha222Release") { it.path == "mods/jei-26.2-fabric-30.29.0.199.jar" } if (rootProject.pack_version != "26.2.0-alpha.230" - || rootProject.redstoner_version != "0.0.0-alpha.17" + || rootProject.redstoner_version != "0.0.0-alpha.18" || rootProject.sanctuary_version != "0.0.0-alpha.137" || migration.source?.pack_version != "26.2.0-alpha.221" || migration.source?.modules != [ @@ -7629,7 +7645,8 @@ tasks.register("verifyAlpha225Release") { def workspaceModules = moduleIds.collectEntries { id -> [(id): project(":${id}").version.toString()] } - def releasedModules = workspaceModules + [sanctuary: "0.0.0-alpha.136"] + def releasedModules = workspaceModules + [ + redstoner: "0.0.0-alpha.17", sanctuary: "0.0.0-alpha.136"] def requiredJars = releasedModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } @@ -7789,7 +7806,8 @@ tasks.register("verifyAlpha226Release") { def workspaceModules = moduleIds.collectEntries { id -> [(id): project(":${id}").version.toString()] } - def releasedModules = workspaceModules + [sanctuary: "0.0.0-alpha.136"] + def releasedModules = workspaceModules + [ + redstoner: "0.0.0-alpha.17", sanctuary: "0.0.0-alpha.136"] def requiredJars = releasedModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } @@ -7880,7 +7898,8 @@ tasks.register("verifyAlpha227Release") { def workspaceModules = moduleIds.collectEntries { id -> [(id): project(":${id}").version.toString()] } - def releasedModules = workspaceModules + [sanctuary: "0.0.0-alpha.136"] + def releasedModules = workspaceModules + [ + redstoner: "0.0.0-alpha.17", sanctuary: "0.0.0-alpha.136"] def requiredJars = releasedModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } @@ -7978,12 +7997,13 @@ tasks.register("verifyAlpha228Release") { def workspaceModules = moduleIds.collectEntries { id -> [(id): project(":${id}").version.toString()] } - def releasedModules = workspaceModules + [sanctuary: "0.0.0-alpha.136"] + def releasedModules = workspaceModules + [ + redstoner: "0.0.0-alpha.17", sanctuary: "0.0.0-alpha.136"] def requiredJars = releasedModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } if (rootProject.pack_version != "26.2.0-alpha.230" - || rootProject.redstoner_version != "0.0.0-alpha.17" + || rootProject.redstoner_version != "0.0.0-alpha.18" || rootProject.sanctuary_version != "0.0.0-alpha.137" || migration.status != "released" || migration.source?.pack_version != "26.2.0-alpha.227" @@ -8083,7 +8103,8 @@ tasks.register("verifyAlpha229Release") { def workspaceModules = moduleIds.collectEntries { id -> [(id): project(":${id}").version.toString()] } - def releasedModules = workspaceModules + [sanctuary: "0.0.0-alpha.136"] + def releasedModules = workspaceModules + [ + redstoner: "0.0.0-alpha.17", sanctuary: "0.0.0-alpha.136"] def requiredJars = releasedModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } @@ -8093,7 +8114,7 @@ tasks.register("verifyAlpha229Release") { "screen.redstoner.storage_terminal.sort.count_ascending", "screen.redstoner.storage_terminal.sort.count_descending"] if (rootProject.pack_version != "26.2.0-alpha.230" - || rootProject.redstoner_version != "0.0.0-alpha.17" + || rootProject.redstoner_version != "0.0.0-alpha.18" || rootProject.sanctuary_version != "0.0.0-alpha.137" || migration.status != "released" || migration.source?.pack_version != "26.2.0-alpha.228" @@ -8171,7 +8192,8 @@ tasks.register("verifyAlpha230Release") { def workspaceModules = moduleIds.collectEntries { id -> [(id): project(":${id}").version.toString()] } - def releasedModules = workspaceModules + [sanctuary: "0.0.0-alpha.136"] + def releasedModules = workspaceModules + [ + redstoner: "0.0.0-alpha.17", sanctuary: "0.0.0-alpha.136"] def requiredJars = releasedModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } @@ -8179,7 +8201,7 @@ tasks.register("verifyAlpha230Release") { .digest(packwizIndexFile.bytes).encodeHex().toString() if (rootProject.pack_version != "26.2.0-alpha.230" || rootProject.sanctuary_version != "0.0.0-alpha.137" - || rootProject.redstoner_version != "0.0.0-alpha.17" + || rootProject.redstoner_version != "0.0.0-alpha.18" || migration.schema_version != 1 || migration.status != "released" || migration.source?.pack_version != "26.2.0-alpha.229" diff --git a/gradle.properties b/gradle.properties index 213cc74..dcb47f0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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.17 +redstoner_version=0.0.0-alpha.18 redstoner_lifecycle=active anotherworld_version=0.0.0-alpha.57 anotherworld_lifecycle=active diff --git a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/block/TrophyPanelBlock.java b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/block/TrophyPanelBlock.java index 40b6515..2d552a3 100644 --- a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/block/TrophyPanelBlock.java +++ b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/block/TrophyPanelBlock.java @@ -3,7 +3,6 @@ package fr.koka99cab.sanctuary26.redstoner.block; import com.mojang.serialization.MapCodec; import fr.koka99cab.sanctuary26.redstoner.block.entity.TrophyPanelBlockEntity; import fr.koka99cab.sanctuary26.redstoner.registry.RedStonerRegistries; -import fr.koka99cab.sanctuary26.sanctuary.api.ranking.RankingUnit; import java.util.Map; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -45,10 +44,10 @@ public final class TrophyPanelBlock extends BaseEntityBlock { public static final MapCodec CODEC = simpleCodec(TrophyPanelBlock::new); public static final EnumProperty FACING = BlockStateProperties.HORIZONTAL_FACING; private static final Map SHAPES = Map.of( - Direction.NORTH, Block.box(0.0D, 0.0D, 13.0D, 16.0D, 16.0D, 16.0D), - Direction.SOUTH, Block.box(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 3.0D), - Direction.WEST, Block.box(13.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D), - Direction.EAST, Block.box(0.0D, 0.0D, 0.0D, 3.0D, 16.0D, 16.0D) + Direction.NORTH, Block.box(0.0D, 0.0D, 14.0D, 16.0D, 16.0D, 16.0D), + Direction.SOUTH, Block.box(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 2.0D), + Direction.WEST, Block.box(14.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D), + Direction.EAST, Block.box(0.0D, 0.0D, 0.0D, 2.0D, 16.0D, 16.0D) ); public TrophyPanelBlock(BlockBehaviour.Properties properties) { @@ -120,18 +119,20 @@ public final class TrophyPanelBlock extends BaseEntityBlock { if (level.isClientSide()) return InteractionResult.SUCCESS; if (!(player instanceof ServerPlayer serverPlayer) || !(level.getBlockEntity(pos) instanceof TrophyPanelBlockEntity panel)) return InteractionResult.CONSUME; - if (player.isSecondaryUseActive()) return cycle(panel, serverPlayer); + if (player.isSecondaryUseActive()) return cycle(panel, serverPlayer, true); boolean operator = serverPlayer.createCommandSourceStack().permissions() .hasPermission(Permissions.COMMANDS_GAMEMASTER); if (!panel.canConfigure(serverPlayer, operator)) { - serverPlayer.sendSystemMessage(Component.translatable("message.redstoner.trophy_panel.not_owner")); - return InteractionResult.CONSUME; + return cycle(panel, serverPlayer, false); } TrophyPanelBlockEntity.ConfigureResult result = panel.configure(serverPlayer, stack); + if (result == TrophyPanelBlockEntity.ConfigureResult.NO_METRIC) { + return cycle(panel, serverPlayer, false); + } String key = switch (result) { case SUCCESS -> "configured"; - case NO_METRIC -> "no_metric"; + case NO_METRIC -> throw new IllegalStateException("Handled above"); case NEWER_DATA -> "newer_data"; }; serverPlayer.sendSystemMessage(Component.translatable("message.redstoner.trophy_panel." + key)); @@ -144,9 +145,7 @@ public final class TrophyPanelBlock extends BaseEntityBlock { if (level.isClientSide()) return InteractionResult.SUCCESS; if (!(player instanceof ServerPlayer serverPlayer) || !(level.getBlockEntity(pos) instanceof TrophyPanelBlockEntity panel)) return InteractionResult.CONSUME; - if (player.isSecondaryUseActive()) return cycle(panel, serverPlayer); - showDetails(panel, serverPlayer); - return InteractionResult.SUCCESS_SERVER; + return cycle(panel, serverPlayer, player.isSecondaryUseActive()); } @Override @@ -164,8 +163,9 @@ public final class TrophyPanelBlock extends BaseEntityBlock { return state.rotate(mirror.getRotation(state.getValue(FACING))); } - private static InteractionResult cycle(TrophyPanelBlockEntity panel, ServerPlayer player) { - if (!panel.cyclePage()) { + private static InteractionResult cycle(TrophyPanelBlockEntity panel, ServerPlayer player, boolean backwards) { + boolean changed = backwards ? panel.previousPage() : panel.nextPage(); + if (!changed) { player.sendSystemMessage(Component.translatable("message.redstoner.trophy_panel.newer_data")); return InteractionResult.CONSUME; } @@ -173,25 +173,4 @@ public final class TrophyPanelBlock extends BaseEntityBlock { panel.pageNumber(), panel.pageCount())); return InteractionResult.SUCCESS_SERVER; } - - private static void showDetails(TrophyPanelBlockEntity panel, ServerPlayer player) { - TrophyPanelBlockEntity.ClientSnapshot snapshot = panel.visibleSnapshot(); - RankingUnit unit = snapshot.unit(); - ItemStack icon = panel.currentPage().icon(); - Component metric = icon.isEmpty() ? Component.translatable(snapshot.translationKey()) - : Component.translatable(snapshot.translationKey(), icon.getHoverName()); - player.sendSystemMessage(Component.translatable("message.redstoner.trophy_panel.header", metric, - panel.pageNumber(), panel.pageCount())); - for (TrophyPanelBlockEntity.ClientEntry entry : snapshot.podium()) { - player.sendSystemMessage(Component.translatable("message.redstoner.trophy_panel.podium", - entry.rank(), entry.name(), unit.format(entry.value()))); - } - if (snapshot.ownerRank() > 0) { - player.sendSystemMessage(Component.translatable("message.redstoner.trophy_panel.owner_rank", - panel.ownerName(), snapshot.ownerRank(), unit.format(snapshot.ownerValue()))); - } else { - player.sendSystemMessage(Component.translatable("message.redstoner.trophy_panel.owner_unranked", - panel.ownerName())); - } - } } diff --git a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/block/entity/TrophyPanelBlockEntity.java b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/block/entity/TrophyPanelBlockEntity.java index b719ac9..2d3c838 100644 --- a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/block/entity/TrophyPanelBlockEntity.java +++ b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/block/entity/TrophyPanelBlockEntity.java @@ -110,9 +110,17 @@ public final class TrophyPanelBlockEntity extends BlockEntity implements ItemOwn return ConfigureResult.SUCCESS; } - public boolean cyclePage() { + public boolean nextPage() { + return movePage(1); + } + + public boolean previousPage() { + return movePage(-1); + } + + private boolean movePage(int offset) { if (!writable() || pages.isEmpty()) return false; - currentPage = TrophyPanelRules.nextPage(currentPage, pages.size()); + currentPage = TrophyPanelRules.pageByOffset(currentPage, pages.size(), offset); syncPersistent(); if (level instanceof ServerLevel serverLevel) refresh(serverLevel); return true; diff --git a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/client/renderer/TrophyPanelBlockEntityRenderer.java b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/client/renderer/TrophyPanelBlockEntityRenderer.java index 4774ab4..6a2e3be 100644 --- a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/client/renderer/TrophyPanelBlockEntityRenderer.java +++ b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/client/renderer/TrophyPanelBlockEntityRenderer.java @@ -11,22 +11,21 @@ import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.feature.ModelFeatureRenderer; -import net.minecraft.client.renderer.item.ItemModelResolver; import net.minecraft.client.renderer.state.level.CameraRenderState; -import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.network.chat.Component; import net.minecraft.util.FormattedCharSequence; -import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.Vec3; public final class TrophyPanelBlockEntityRenderer implements BlockEntityRenderer { - private final ItemModelResolver itemModelResolver; + private static final int MAX_TEXT_WIDTH = 90; + private static final float TEXT_SCALE = 0.010416667F; + private static final float[] LINE_HEIGHTS = {0.70F, 0.59F, 0.48F, 0.37F}; + private static final int TEXT_COLOR = 0xFF3D281A; private final Font font; public TrophyPanelBlockEntityRenderer(BlockEntityRendererProvider.Context context) { - itemModelResolver = context.itemModelResolver(); font = context.font(); } @@ -40,65 +39,51 @@ public final class TrophyPanelBlockEntityRenderer float tickProgress, Vec3 cameraPos, ModelFeatureRenderer.CrumblingOverlay crumblingOverlay) { BlockEntityRenderer.super.extractRenderState(panel, state, tickProgress, cameraPos, crumblingOverlay); state.facing = panel.getBlockState().getValue(TrophyPanelBlock.FACING); - state.icon.clear(); ItemStack icon = panel.currentPage().icon(); - state.hasIcon = !icon.isEmpty(); - if (state.hasIcon) { - itemModelResolver.updateForTopItem(state.icon, icon, ItemDisplayContext.FIXED, - panel.level(), panel, (int) panel.getBlockPos().asLong()); - } - TrophyPanelBlockEntity.ClientSnapshot snapshot = panel.visibleSnapshot(); RankingUnit unit = snapshot.unit(); - state.metric = state.hasIcon ? Component.translatable(snapshot.translationKey(), icon.getHoverName()) + Component metric = !icon.isEmpty() ? Component.translatable(snapshot.translationKey(), icon.getHoverName()) : Component.translatable(snapshot.translationKey()); + state.lines[0] = Component.translatable("block.redstoner.trophy_panel.page_title", + panel.pageNumber(), panel.pageCount(), metric); if (snapshot.podium().isEmpty()) { - state.champion = Component.translatable("block.redstoner.trophy_panel.no_score"); + state.lines[1] = Component.translatable("block.redstoner.trophy_panel.no_score"); + state.lines[2] = Component.empty(); + state.lines[3] = Component.empty(); } else { - TrophyPanelBlockEntity.ClientEntry champion = snapshot.podium().getFirst(); - state.champion = Component.translatable("block.redstoner.trophy_panel.champion", - champion.name(), unit.format(champion.value())); + for (int index = 0; index < 3; index++) { + if (index >= snapshot.podium().size()) { + state.lines[index + 1] = Component.empty(); + continue; + } + TrophyPanelBlockEntity.ClientEntry entry = snapshot.podium().get(index); + state.lines[index + 1] = Component.translatable("block.redstoner.trophy_panel.podium", + entry.rank(), entry.name(), unit.format(entry.value())); + } } - state.owner = snapshot.ownerRank() > 0 - ? Component.translatable("block.redstoner.trophy_panel.owner_rank", panel.ownerName(), - snapshot.ownerRank(), unit.format(snapshot.ownerValue())) - : Component.translatable("block.redstoner.trophy_panel.owner_unranked", panel.ownerName()); - state.page = Component.literal(panel.pageNumber() + "/" + panel.pageCount()); } @Override public void submit(TrophyPanelRenderState state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState cameraRenderState) { float yRotation = -state.facing.toYRot(); - if (state.hasIcon) submitIcon(state, poseStack, submitNodeCollector, yRotation); - submitText(state.metric, 0.72F, 0.0065F, state, poseStack, submitNodeCollector, yRotation, 0xFFE8B4); - submitText(state.champion, 0.52F, 0.0060F, state, poseStack, submitNodeCollector, yRotation, 0xFFFFFF); - submitText(state.owner, 0.36F, 0.0055F, state, poseStack, submitNodeCollector, yRotation, 0xB8D9FF); - submitText(state.page, 0.20F, 0.0050F, state, poseStack, submitNodeCollector, yRotation, 0xA0A0A0); + for (int index = 0; index < TrophyPanelRenderState.LINE_COUNT; index++) { + submitText(state.lines[index], LINE_HEIGHTS[index], state, poseStack, submitNodeCollector, yRotation); + } } - private void submitIcon(TrophyPanelRenderState state, PoseStack poseStack, - SubmitNodeCollector submitNodeCollector, float yRotation) { - poseStack.pushPose(); - poseStack.translate(0.5F, 0.89F, 0.5F); - poseStack.mulPose(Axis.YP.rotationDegrees(yRotation)); - poseStack.translate(0.0F, 0.0F, -0.33F); - poseStack.scale(0.18F, 0.18F, 0.18F); - state.icon.submit(poseStack, submitNodeCollector, state.lightCoords, OverlayTexture.NO_OVERLAY, 0); - poseStack.popPose(); - } - - private void submitText(Component component, float y, float scale, TrophyPanelRenderState state, - PoseStack poseStack, SubmitNodeCollector submitNodeCollector, float yRotation, int color) { - FormattedCharSequence text = component.getVisualOrderText(); + private void submitText(Component component, float y, TrophyPanelRenderState state, + PoseStack poseStack, SubmitNodeCollector submitNodeCollector, float yRotation) { + FormattedCharSequence text = font.split(component, MAX_TEXT_WIDTH).stream().findFirst() + .orElse(FormattedCharSequence.EMPTY); float x = -font.width(text) / 2.0F; poseStack.pushPose(); poseStack.translate(0.5F, y, 0.5F); poseStack.mulPose(Axis.YP.rotationDegrees(yRotation)); poseStack.translate(0.0F, 0.0F, -0.331F); - poseStack.scale(scale, -scale, scale); + poseStack.scale(TEXT_SCALE, -TEXT_SCALE, TEXT_SCALE); submitNodeCollector.submitText(poseStack, x, 0.0F, text, false, Font.DisplayMode.POLYGON_OFFSET, - color, state.lightCoords, 0, 0x30181818); + state.lightCoords, TEXT_COLOR, 0, 0); poseStack.popPose(); } } diff --git a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/client/renderer/state/TrophyPanelRenderState.java b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/client/renderer/state/TrophyPanelRenderState.java index 1a09ee9..bebf7e4 100644 --- a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/client/renderer/state/TrophyPanelRenderState.java +++ b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/client/renderer/state/TrophyPanelRenderState.java @@ -1,16 +1,13 @@ package fr.koka99cab.sanctuary26.redstoner.client.renderer.state; import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState; -import net.minecraft.client.renderer.item.ItemStackRenderState; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; public final class TrophyPanelRenderState extends BlockEntityRenderState { - public final ItemStackRenderState icon = new ItemStackRenderState(); + public static final int LINE_COUNT = 4; + public final Component[] lines = { + Component.empty(), Component.empty(), Component.empty(), Component.empty() + }; public Direction facing = Direction.NORTH; - public boolean hasIcon; - public Component metric = Component.empty(); - public Component champion = Component.empty(); - public Component owner = Component.empty(); - public Component page = Component.empty(); } diff --git a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/trophy/TrophyPanelRules.java b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/trophy/TrophyPanelRules.java index cb9af86..2c2da3d 100644 --- a/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/trophy/TrophyPanelRules.java +++ b/redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/trophy/TrophyPanelRules.java @@ -17,7 +17,15 @@ public final class TrophyPanelRules { } public static int nextPage(int currentPage, int pageCount) { - return pageCount <= 0 ? 0 : Math.floorMod(currentPage + 1, pageCount); + return pageByOffset(currentPage, pageCount, 1); + } + + public static int previousPage(int currentPage, int pageCount) { + return pageByOffset(currentPage, pageCount, -1); + } + + public static int pageByOffset(int currentPage, int pageCount, int offset) { + return pageCount <= 0 ? 0 : Math.floorMod(currentPage + offset, pageCount); } public static List mergeMetricIds(List current, List offered) { diff --git a/redstoner/src/main/resources/assets/redstoner/lang/en_us.json b/redstoner/src/main/resources/assets/redstoner/lang/en_us.json index 24fa3b6..9d795bd 100644 --- a/redstoner/src/main/resources/assets/redstoner/lang/en_us.json +++ b/redstoner/src/main/resources/assets/redstoner/lang/en_us.json @@ -64,6 +64,8 @@ "screen.redstoner.storage_terminal.error.too_large": "Network too large (maximum 128 storage blocks).", "screen.redstoner.storage_terminal.error.locked": "The network contains a locked storage block.", "block.redstoner.trophy_panel": "Trophy Panel", + "block.redstoner.trophy_panel.page_title": "[%s/%s] %s", + "block.redstoner.trophy_panel.podium": "#%s %s · %s", "block.redstoner.trophy_panel.no_score": "No score yet", "block.redstoner.trophy_panel.champion": "#1 %s · %s", "block.redstoner.trophy_panel.owner_rank": "%s · #%s · %s", diff --git a/redstoner/src/main/resources/assets/redstoner/lang/fr_fr.json b/redstoner/src/main/resources/assets/redstoner/lang/fr_fr.json index 73aaca4..d9bbc3a 100644 --- a/redstoner/src/main/resources/assets/redstoner/lang/fr_fr.json +++ b/redstoner/src/main/resources/assets/redstoner/lang/fr_fr.json @@ -64,6 +64,8 @@ "screen.redstoner.storage_terminal.error.too_large": "Réseau trop grand (128 stockages maximum).", "screen.redstoner.storage_terminal.error.locked": "Le réseau contient un stockage verrouillé.", "block.redstoner.trophy_panel": "Panneau de trophées", + "block.redstoner.trophy_panel.page_title": "[%s/%s] %s", + "block.redstoner.trophy_panel.podium": "#%s %s · %s", "block.redstoner.trophy_panel.no_score": "Aucun score", "block.redstoner.trophy_panel.champion": "#1 %s · %s", "block.redstoner.trophy_panel.owner_rank": "%s · #%s · %s", diff --git a/redstoner/src/main/resources/assets/redstoner/lang/ru_ru.json b/redstoner/src/main/resources/assets/redstoner/lang/ru_ru.json index d77b746..d217ec2 100644 --- a/redstoner/src/main/resources/assets/redstoner/lang/ru_ru.json +++ b/redstoner/src/main/resources/assets/redstoner/lang/ru_ru.json @@ -64,6 +64,8 @@ "screen.redstoner.storage_terminal.error.too_large": "Сеть слишком велика (не более 128 хранилищ).", "screen.redstoner.storage_terminal.error.locked": "В сети есть запертое хранилище.", "block.redstoner.trophy_panel": "Панель трофеев", + "block.redstoner.trophy_panel.page_title": "[%s/%s] %s", + "block.redstoner.trophy_panel.podium": "#%s %s · %s", "block.redstoner.trophy_panel.no_score": "Результатов пока нет", "block.redstoner.trophy_panel.champion": "#1 %s · %s", "block.redstoner.trophy_panel.owner_rank": "%s · #%s · %s", diff --git a/redstoner/src/main/resources/assets/redstoner/models/block/trophy_panel.json b/redstoner/src/main/resources/assets/redstoner/models/block/trophy_panel.json index 53b0576..0eec79a 100644 --- a/redstoner/src/main/resources/assets/redstoner/models/block/trophy_panel.json +++ b/redstoner/src/main/resources/assets/redstoner/models/block/trophy_panel.json @@ -1,14 +1,12 @@ { "parent": "minecraft:block/block", "textures": { - "particle": "minecraft:block/dark_oak_planks", - "wood": "minecraft:block/dark_oak_planks", - "frame": "minecraft:block/gold_block", - "screen": "minecraft:block/black_concrete" + "particle": "minecraft:block/oak_planks", + "wood": "minecraft:block/oak_planks" }, "elements": [ { - "from": [0, 0, 13], + "from": [0, 0, 14], "to": [16, 16, 16], "faces": { "north": { "texture": "#wood" }, @@ -18,31 +16,6 @@ "up": { "texture": "#wood" }, "down": { "texture": "#wood" } } - }, - { - "from": [1.5, 1.5, 12.5], - "to": [14.5, 14.5, 13], - "faces": { "north": { "texture": "#screen" } } - }, - { - "from": [0.5, 0.5, 12.25], - "to": [15.5, 1.5, 13], - "faces": { "north": { "texture": "#frame" } } - }, - { - "from": [0.5, 14.5, 12.25], - "to": [15.5, 15.5, 13], - "faces": { "north": { "texture": "#frame" } } - }, - { - "from": [0.5, 1.5, 12.25], - "to": [1.5, 14.5, 13], - "faces": { "north": { "texture": "#frame" } } - }, - { - "from": [14.5, 1.5, 12.25], - "to": [15.5, 14.5, 13], - "faces": { "north": { "texture": "#frame" } } } ] } diff --git a/redstoner/src/test/java/fr/koka99cab/sanctuary26/redstoner/trophy/TrophyPanelRulesSmoke.java b/redstoner/src/test/java/fr/koka99cab/sanctuary26/redstoner/trophy/TrophyPanelRulesSmoke.java index ea0d1db..367ac74 100644 --- a/redstoner/src/test/java/fr/koka99cab/sanctuary26/redstoner/trophy/TrophyPanelRulesSmoke.java +++ b/redstoner/src/test/java/fr/koka99cab/sanctuary26/redstoner/trophy/TrophyPanelRulesSmoke.java @@ -15,6 +15,10 @@ public final class TrophyPanelRulesSmoke { require(TrophyPanelRules.canConfigure(owner, visitor, true), "An operator cannot repair a panel"); require(TrophyPanelRules.nextPage(0, 3) == 1 && TrophyPanelRules.nextPage(2, 3) == 0, "Public page cycling does not wrap"); + require(TrophyPanelRules.previousPage(0, 3) == 2 && TrophyPanelRules.previousPage(2, 3) == 1, + "Reverse public page cycling does not wrap"); + require(TrophyPanelRules.pageByOffset(4, 0, 1) == 0, + "An empty panel produced an invalid page index"); Identifier first = Identifier.parse("sanctuary:first"); Identifier second = Identifier.parse("sanctuary:second");