Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a85eea769 |
No files matched your search
@@ -162,8 +162,8 @@ public final class CharacterBookController implements Consumer<ControlInput>, Au
|
||||
var passiveNames = passiveDefinitions.stream().collect(java.util.stream.Collectors.toMap(
|
||||
games.dmg.fantasystick.passive.PassiveDefinition::id,
|
||||
games.dmg.fantasystick.passive.PassiveDefinition::name));
|
||||
var passiveDetails = passiveDefinitions.stream()
|
||||
.map(definition -> passiveDetailPages(record, definition, passiveNames, passiveView)).toList();
|
||||
var placeholderPassiveDetails = passiveDefinitions.stream()
|
||||
.map(definition -> passiveDetailPages(record, definition, passiveNames, passiveView, 1)).toList();
|
||||
var placeholderTargets = definitions.stream().collect(java.util.stream.Collectors.toMap(
|
||||
games.dmg.fantasystick.ability.AbilityDefinition::id, ignored -> 1));
|
||||
var passivePlaceholderTargets = passiveDefinitions.stream().collect(java.util.stream.Collectors.toMap(
|
||||
@@ -174,10 +174,15 @@ public final class CharacterBookController implements Consumer<ControlInput>, Au
|
||||
int passiveCount = passiveSlotPages(record, passiveDefinitions, passivePlaceholderTargets).size();
|
||||
var placeholderIndex = indexPages(definitions, placeholderTargets);
|
||||
int indexCount = placeholderIndex.pages().size();
|
||||
int passiveIndexCount = passiveIndexPages(passiveDefinitions, passivePlaceholderTargets).size();
|
||||
var placeholderPassiveIndex = passiveIndexPages(passiveDefinitions, passivePlaceholderTargets);
|
||||
int passiveIndexCount = placeholderPassiveIndex.pages().size();
|
||||
int indexStart = pages.size() + activeCount + passiveCount;
|
||||
var indexTargets = new java.util.HashMap<String, Integer>();
|
||||
placeholderIndex.relativePageByAbility().forEach((id, page) -> indexTargets.put(id, indexStart + page + 1));
|
||||
int passiveIndexStart = indexStart + indexCount;
|
||||
var passiveIndexTargets = new java.util.HashMap<String, Integer>();
|
||||
placeholderPassiveIndex.relativePageByPassive().forEach((id, page) ->
|
||||
passiveIndexTargets.put(id, passiveIndexStart + page + 1));
|
||||
var targets = new java.util.HashMap<String, Integer>();
|
||||
int target = pages.size() + activeCount + passiveCount + indexCount + passiveIndexCount + 1;
|
||||
for (int index = 0; index < definitions.size(); index++) {
|
||||
@@ -187,15 +192,18 @@ public final class CharacterBookController implements Consumer<ControlInput>, Au
|
||||
var passiveTargets = new java.util.HashMap<String, Integer>();
|
||||
for (int index = 0; index < passiveDefinitions.size(); index++) {
|
||||
passiveTargets.put(passiveDefinitions.get(index).id(), target);
|
||||
target += passiveDetails.get(index).size();
|
||||
target += placeholderPassiveDetails.get(index).size();
|
||||
}
|
||||
var index = indexPages(definitions, targets);
|
||||
var details = definitions.stream()
|
||||
.map(definition -> abilityPages(record, definition, abilityView, indexTargets.get(definition.id()))).toList();
|
||||
var passiveIndex = passiveIndexPages(passiveDefinitions, passiveTargets);
|
||||
var passiveDetails = passiveDefinitions.stream().map(definition -> passiveDetailPages(record, definition,
|
||||
passiveNames, passiveView, passiveIndexTargets.get(definition.id()))).toList();
|
||||
pages.addAll(activePages(record, definitions, targets));
|
||||
pages.addAll(passiveSlotPages(record, passiveDefinitions, passiveTargets));
|
||||
pages.addAll(index.pages());
|
||||
pages.addAll(passiveIndexPages(passiveDefinitions, passiveTargets));
|
||||
pages.addAll(passiveIndex.pages());
|
||||
details.forEach(pages::addAll);
|
||||
passiveDetails.forEach(pages::addAll);
|
||||
}
|
||||
@@ -293,12 +301,17 @@ public final class CharacterBookController implements Consumer<ControlInput>, Au
|
||||
var relativePages = new java.util.HashMap<String, Integer>();
|
||||
for (var category : games.dmg.fantasystick.ability.AbilityDefinition.Category.values()) {
|
||||
var grouped = definitions.stream().filter(definition -> definition.category() == category).toList();
|
||||
for (int start = 0; start < grouped.size(); start += 11) {
|
||||
int cursor = 0;
|
||||
while (cursor < grouped.size()) {
|
||||
var builder = new PageBuilder(); builder.text("Ability index"); builder.text(category.name());
|
||||
int relativePage = pages.size();
|
||||
for (var definition : grouped.subList(start, Math.min(start + 11, grouped.size()))) {
|
||||
int usedLines = 0;
|
||||
while (cursor < grouped.size()) {
|
||||
var definition = grouped.get(cursor);
|
||||
int linkLines = BookPagination.lines(definition.name()).size();
|
||||
if (usedLines > 0 && usedLines + linkLines > 11) break;
|
||||
relativePages.put(definition.id(), pages.size());
|
||||
builder.link("", definition.name(), targets.get(definition.id()));
|
||||
relativePages.put(definition.id(), relativePage);
|
||||
usedLines += linkLines; cursor++;
|
||||
}
|
||||
pages.addAll(builder.pages());
|
||||
}
|
||||
@@ -306,21 +319,33 @@ public final class CharacterBookController implements Consumer<ControlInput>, Au
|
||||
return new AbilityIndex(pages, relativePages);
|
||||
}
|
||||
|
||||
private static java.util.List<Component> passiveIndexPages(
|
||||
private record PassiveIndex(java.util.List<Component> pages, Map<String, Integer> relativePageByPassive) {
|
||||
private PassiveIndex { pages = java.util.List.copyOf(pages); relativePageByPassive = Map.copyOf(relativePageByPassive); }
|
||||
}
|
||||
|
||||
private static PassiveIndex passiveIndexPages(
|
||||
java.util.List<games.dmg.fantasystick.passive.PassiveDefinition> definitions, Map<String, Integer> targets) {
|
||||
var pages = new java.util.ArrayList<Component>();
|
||||
for (int start = 0; start < definitions.size(); start += 11) {
|
||||
var pages = new java.util.ArrayList<Component>(); var relativePages = new java.util.HashMap<String, Integer>();
|
||||
int cursor = 0;
|
||||
while (cursor < definitions.size()) {
|
||||
var builder = new PageBuilder(); builder.text("Passive index"); builder.blank();
|
||||
for (var definition : definitions.subList(start, Math.min(start + 11, definitions.size()))) {
|
||||
int usedLines = 0;
|
||||
while (cursor < definitions.size()) {
|
||||
var definition = definitions.get(cursor);
|
||||
int linkLines = BookPagination.lines(definition.name()).size();
|
||||
if (usedLines > 0 && usedLines + linkLines > 11) break;
|
||||
relativePages.put(definition.id(), pages.size());
|
||||
builder.link("", definition.name(), targets.get(definition.id()));
|
||||
usedLines += linkLines; cursor++;
|
||||
}
|
||||
pages.addAll(builder.pages());
|
||||
}
|
||||
return java.util.List.copyOf(pages);
|
||||
return new PassiveIndex(pages, relativePages);
|
||||
}
|
||||
|
||||
private static java.util.List<Component> passiveDetailPages(CharacterRecord record,
|
||||
games.dmg.fantasystick.passive.PassiveDefinition definition, Map<String, String> names, PassiveView view) {
|
||||
games.dmg.fantasystick.passive.PassiveDefinition definition, Map<String, String> names, PassiveView view,
|
||||
int indexPage) {
|
||||
String requirements = definition.requirements().entrySet().stream().sorted(Map.Entry.comparingByKey())
|
||||
.map(entry -> entry.getKey() + " " + entry.getValue()).collect(java.util.stream.Collectors.joining(", "));
|
||||
if (!definition.prerequisites().isEmpty()) {
|
||||
@@ -341,6 +366,8 @@ public final class CharacterBookController implements Consumer<ControlInput>, Au
|
||||
else if (prerequisites && stats && points && slot) builder.component(passiveButton("Learn", PASSIVE_UNLOCK, view, definition.id()));
|
||||
else builder.text(state);
|
||||
builder.blank(); definition.description().forEach(builder::text); builder.blank(); builder.text(state);
|
||||
builder.component(Component.text("[Back to index]", net.kyori.adventure.text.format.NamedTextColor.DARK_BLUE)
|
||||
.clickEvent(net.kyori.adventure.text.event.ClickEvent.changePage(indexPage)));
|
||||
return builder.pages();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,28 @@ class QuickerRegenerationNativeTest {
|
||||
assertTrue(active > 0 && active < passive && passive < activeIndex && activeIndex < passiveIndex && passiveIndex < party);
|
||||
assertTrue(pages.get(passive).getString().contains("1: No Passive"));
|
||||
assertTrue(pages.get(passiveIndex).getString().replace("\n", "").contains("Quicker Regeneration I"));
|
||||
var indexPageByPassive = new java.util.HashMap<String, Integer>();
|
||||
var detailStartByPassive = new java.util.HashMap<String, Integer>();
|
||||
var passiveRegistry = (games.dmg.fantasystick.passive.PassiveRegistry)
|
||||
FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "passiveRegistry");
|
||||
for (var definition : passiveRegistry.definitions()) {
|
||||
for (int page = passiveIndex; page < pages.size() && pages.get(page).getString().startsWith("Passive index"); page++) {
|
||||
var target = changePageTo(pages.get(page), pages, definition.name());
|
||||
if (target != null) { indexPageByPassive.put(definition.name(), page);
|
||||
detailStartByPassive.put(definition.name(), target.page() - 1); break; }
|
||||
}
|
||||
}
|
||||
assertEquals(passiveRegistry.definitions().size(), detailStartByPassive.size());
|
||||
for (var entry : detailStartByPassive.entrySet()) {
|
||||
int end = party;
|
||||
for (int other : detailStartByPassive.values()) if (other > entry.getValue()) end = Math.min(end, other);
|
||||
var backPages = new java.util.ArrayList<Integer>();
|
||||
for (int candidate = entry.getValue(); candidate < end; candidate++)
|
||||
if (changePageNamed(pages.get(candidate), "[Back to index]") != null) backPages.add(candidate);
|
||||
assertEquals(java.util.List.of(end - 1), backPages, entry.getKey());
|
||||
assertEquals(indexPageByPassive.get(entry.getKey()) + 1,
|
||||
changePageNamed(pages.get(end - 1), "[Back to index]").page(), entry.getKey());
|
||||
}
|
||||
var jump = changePageTo(pages.get(passiveIndex), pages, "Quicker Regeneration I"); assertNotNull(jump);
|
||||
String detail = pages.get(jump.page() - 1).getString();
|
||||
assertTrue(detail.replaceAll("\\s+", "").startsWith("QuickerRegenerationICON12,WIS12[Learn]"), detail);
|
||||
@@ -74,6 +96,50 @@ class QuickerRegenerationNativeTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test void multiPagePassiveIndexAndWrappedDetailsReturnToTheirExactContainingPage() throws Exception {
|
||||
try (var f = new FantasyStickLifecycleNativeTest.Fixture(data)) {
|
||||
f.plugin.setEnabled(true);
|
||||
var registry = (games.dmg.fantasystick.passive.PassiveRegistry)
|
||||
FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "passiveRegistry");
|
||||
for (int index = 0; index < 12; index++) {
|
||||
String suffix = String.format(java.util.Locale.ROOT, "%02d", index);
|
||||
registry.register(new games.dmg.fantasystick.passive.PassiveDefinition("synthetic_" + suffix,
|
||||
"Synthetic Passive " + suffix, java.util.Map.of(), java.util.Set.of(), BigInteger.ONE,
|
||||
List.of(index == 0 ? "Wrapped detail ".repeat(80) : "Synthetic passive detail.")));
|
||||
}
|
||||
var a = new FantasyStickLifecycleNativeTest.Actor(data); f.players.put(a.core.id, a.player); f.activate(a);
|
||||
var before = storage(f).find(a.core.record.id()).get().orElseThrow(); PartyBookNativeTest.open(f, a);
|
||||
var pages = nativePages(a); assertTrue(pages.size() <= 100);
|
||||
int passiveIndex = first(pages, "Passive index"), party = first(pages, "Party");
|
||||
var indexPageByPassive = new java.util.HashMap<String, Integer>();
|
||||
var detailStartByPassive = new java.util.HashMap<String, Integer>();
|
||||
int indexPages = 0;
|
||||
for (int page = passiveIndex; page < pages.size() && pages.get(page).getString().startsWith("Passive index"); page++) indexPages++;
|
||||
for (var definition : registry.definitions()) {
|
||||
for (int page = passiveIndex; page < passiveIndex + indexPages; page++) {
|
||||
var target = changePageTo(pages.get(page), pages, definition.name());
|
||||
if (target != null) { indexPageByPassive.put(definition.name(), page);
|
||||
detailStartByPassive.put(definition.name(), target.page() - 1); break; }
|
||||
}
|
||||
}
|
||||
assertTrue(indexPages >= 2); assertEquals(registry.definitions().size(), detailStartByPassive.size());
|
||||
boolean wrapped = false;
|
||||
for (var entry : detailStartByPassive.entrySet()) {
|
||||
int end = party;
|
||||
for (int other : detailStartByPassive.values()) if (other > entry.getValue()) end = Math.min(end, other);
|
||||
wrapped |= end - entry.getValue() > 1;
|
||||
var backPages = new java.util.ArrayList<Integer>();
|
||||
for (int candidate = entry.getValue(); candidate < end; candidate++)
|
||||
if (changePageNamed(pages.get(candidate), "[Back to index]") != null) backPages.add(candidate);
|
||||
assertEquals(java.util.List.of(end - 1), backPages, entry.getKey());
|
||||
assertEquals(indexPageByPassive.get(entry.getKey()) + 1,
|
||||
changePageNamed(pages.get(end - 1), "[Back to index]").page(), entry.getKey());
|
||||
}
|
||||
assertTrue(wrapped, "At least one passive detail must span native pages");
|
||||
assertEquals(before, storage(f).find(before.id()).get().orElseThrow());
|
||||
}
|
||||
}
|
||||
|
||||
@Test void unknownFullPassiveSlotsRemainVisibleAndRefuseBeforeSpending() throws Exception {
|
||||
try (var f = new FantasyStickLifecycleNativeTest.Fixture(data)) {
|
||||
f.plugin.setEnabled(true);
|
||||
@@ -144,6 +210,15 @@ class QuickerRegenerationNativeTest {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static net.minecraft.network.chat.ClickEvent.ChangePage changePageNamed(
|
||||
net.minecraft.network.chat.Component component, String label) {
|
||||
if (component.getString().equals(label)
|
||||
&& component.getStyle().getClickEvent() instanceof net.minecraft.network.chat.ClickEvent.ChangePage page) return page;
|
||||
for (var child : component.getSiblings()) {
|
||||
var found = changePageNamed(child, label); if (found != null) return found;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static net.minecraft.network.chat.ClickEvent.Custom custom(List<net.minecraft.network.chat.Component> pages, String id) {
|
||||
for (var page : pages) { var found = custom(page, id); if (found != null) return found; }
|
||||
throw new AssertionError("Missing custom action " + id);
|
||||
|
||||
Reference in new issue
Block a user