Skip to content

Commit 6f83303

Browse files
committed
refactor(research): refactor ResearchTreeScreen layout and functionality
1 parent f44e50d commit 6f83303

16 files changed

Lines changed: 381 additions & 421 deletions

.github/copilot-instructions.md

Lines changed: 132 additions & 185 deletions
Large diffs are not rendered by default.

src/main/java/com/researchcube/client/screen/ResearchTableScreen.java

Lines changed: 152 additions & 180 deletions
Large diffs are not rendered by default.

src/main/java/com/researchcube/client/screen/ResearchTreeScreen.java

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@
3434

3535
/**
3636
* Alternative research UI that visualizes the research dependency graph.
37+
*
38+
* Compact layout (340x250) matching ResearchTableScreen:
39+
* Left column (~100px): Drive, Cube, cost grid, buckets, idea chip, fluid gauge
40+
* Right area: Graph viewport with zoom/pan
41+
* Bottom: Player inventory + hotbar (centered)
3742
*/
3843
public class ResearchTreeScreen extends AbstractContainerScreen<ResearchTableMenu> {
3944

@@ -52,10 +57,11 @@ public class ResearchTreeScreen extends AbstractContainerScreen<ResearchTableMen
5257
private static final int LAYER_X_GAP = 178;
5358
private static final int LAYER_Y_GAP = 64;
5459

55-
private static final int GRAPH_X = 186;
56-
private static final int GRAPH_Y = 34;
57-
private static final int GRAPH_W = 314;
58-
private static final int GRAPH_H = 112;
60+
// Graph viewport (right of the left column)
61+
private static final int GRAPH_X = 108;
62+
private static final int GRAPH_Y = 32;
63+
private static final int GRAPH_W = 228;
64+
private static final int GRAPH_H = 114;
5965

6066
private enum EdgeStyle {
6167
SINGLE,
@@ -106,34 +112,34 @@ private record Dependency(ResourceLocation sourceId, EdgeStyle style) {}
106112

107113
public ResearchTreeScreen(ResearchTableMenu menu, Inventory playerInv, Component title) {
108114
super(menu, playerInv, title);
109-
this.imageWidth = 520;
110-
this.imageHeight = 286;
111-
this.inventoryLabelX = 179;
112-
this.inventoryLabelY = 158;
115+
this.imageWidth = 340;
116+
this.imageHeight = 250;
117+
this.inventoryLabelX = 89;
118+
this.inventoryLabelY = 153;
113119
}
114120

115121
@Override
116122
protected void init() {
117123
super.init();
118124

119-
this.startButton = addRenderableWidget(Button.builder(Component.literal("Start Research"), b -> onStartResearch())
120-
.bounds(leftPos + 22, topPos + 104, 140, 18)
125+
this.startButton = addRenderableWidget(Button.builder(Component.literal("Start"), b -> onStartResearch())
126+
.bounds(leftPos + 10, topPos + 112, 40, 14)
121127
.build());
122128

123-
this.listButton = addRenderableWidget(Button.builder(Component.literal("List View"), b -> openListView())
124-
.bounds(leftPos + 22, topPos + 126, 62, 18)
129+
this.listButton = addRenderableWidget(Button.builder(Component.literal("List"), b -> openListView())
130+
.bounds(leftPos + 54, topPos + 112, 40, 14)
125131
.build());
126132

127133
this.fitButton = addRenderableWidget(Button.builder(Component.literal("Fit"), b -> fitGraphToViewport())
128-
.bounds(leftPos + 88, topPos + 126, 36, 18)
134+
.bounds(leftPos + 10, topPos + 130, 30, 14)
129135
.build());
130136

131137
this.zoomOutButton = addRenderableWidget(Button.builder(Component.literal("-"), b -> adjustZoom(-0.12f))
132-
.bounds(leftPos + 128, topPos + 126, 18, 18)
138+
.bounds(leftPos + 44, topPos + 130, 18, 14)
133139
.build());
134140

135141
this.zoomInButton = addRenderableWidget(Button.builder(Component.literal("+"), b -> adjustZoom(0.12f))
136-
.bounds(leftPos + 150, topPos + 126, 18, 18)
142+
.bounds(leftPos + 66, topPos + 130, 18, 14)
137143
.build());
138144

139145
buildGraph();
@@ -398,17 +404,22 @@ protected void renderBg(GuiGraphics g, float partialTick, int mouseX, int mouseY
398404
int x = leftPos;
399405
int y = topPos;
400406

407+
// Outer background
401408
g.fill(x, y, x + imageWidth, y + imageHeight, BG_OUTER);
402409
g.fill(x, y, x + imageWidth, y + 1, 0xFFFFFFFF);
403410
g.fill(x, y, x + 1, y + imageHeight, 0xFFFFFFFF);
404411
g.fill(x + imageWidth - 1, y, x + imageWidth, y + imageHeight, PANEL_DARK);
405412
g.fill(x, y + imageHeight - 1, x + imageWidth, y + imageHeight, PANEL_DARK);
406413

407-
drawPanel(g, x + 10, y + 20, imageWidth - 20, 132);
408-
drawPanel(g, x + 10, y + 156, imageWidth - 20, 122);
414+
// Main top panel
415+
drawPanel(g, x + 4, y + 14, 332, 140);
416+
// Bottom inventory panel
417+
drawPanel(g, x + 4, y + 156, 332, 90);
409418

410-
// Left utility/slot dock tied to the existing ResearchTableMenu slots.
411-
drawPanel(g, x + 20, y + 34, 160, 118);
419+
// Left machine column sub-panel
420+
drawPanel(g, x + 6, y + 16, 100, 136);
421+
422+
// Slot backgrounds in left column
412423
drawSlotBg(g, x + ResearchTableMenu.DRIVE_X, y + ResearchTableMenu.DRIVE_Y);
413424
drawSlotBg(g, x + ResearchTableMenu.CUBE_X, y + ResearchTableMenu.CUBE_Y);
414425
for (int row = 0; row < 2; row++) {
@@ -418,7 +429,8 @@ protected void renderBg(GuiGraphics g, float partialTick, int mouseX, int mouseY
418429
}
419430
drawSlotBg(g, x + ResearchTableMenu.BUCKET_IN_X, y + ResearchTableMenu.BUCKET_IN_Y);
420431
drawSlotBg(g, x + ResearchTableMenu.BUCKET_OUT_X, y + ResearchTableMenu.BUCKET_OUT_Y);
421-
drawFluidGauge(g, x + 154, y + 36, 16, 58);
432+
drawSlotBg(g, x + ResearchTableMenu.IDEA_CHIP_X, y + ResearchTableMenu.IDEA_CHIP_Y);
433+
drawFluidGauge(g, x + 92, y + 26, 12, 54);
422434

423435
// Player inventory slot backgrounds
424436
for (int row = 0; row < 3; row++) {
@@ -431,8 +443,9 @@ protected void renderBg(GuiGraphics g, float partialTick, int mouseX, int mouseY
431443
}
432444

433445
// Header strip
434-
g.fill(x + 20, y + 22, x + imageWidth - 20, y + 32, 0xFF1C2030);
446+
g.fill(x + 6, y + 16, x + 106, y + 26, 0xFF1C2030);
435447

448+
// Graph viewport
436449
int gx = x + GRAPH_X;
437450
int gy = y + GRAPH_Y;
438451
g.fill(gx, gy, gx + GRAPH_W, gy + GRAPH_H, GRAPH_BG);
@@ -719,17 +732,18 @@ private void renderNodeTooltip(GuiGraphics graphics, NodeBox node, int mouseX, i
719732
protected void renderLabels(GuiGraphics graphics, int mouseX, int mouseY) {
720733
graphics.drawString(this.font, this.title, this.titleLabelX, this.titleLabelY, 0xFF202020, false);
721734
graphics.drawString(this.font, this.playerInventoryTitle, this.inventoryLabelX, this.inventoryLabelY, 0xFFE6EAF5, false);
722-
graphics.drawString(this.font, "Tree View | scroll = zoom, right-drag = pan", 22, 24, 0xFFE5E7EB, false);
723-
graphics.drawString(this.font, "AND", 440, 24, EDGE_AND, false);
724-
graphics.drawString(this.font, "OR", 468, 24, EDGE_OR, false);
725-
graphics.drawString(this.font, "S", 486, 24, EDGE_SINGLE, false);
726-
graphics.drawString(this.font, "Drive", 24, 36, 0xFFD3D7E5, false);
727-
graphics.drawString(this.font, "Cube", 24, 72, 0xFFD3D7E5, false);
728-
graphics.drawString(this.font, "Costs", 70, 36, 0xFFD3D7E5, false);
729-
graphics.drawString(this.font, "Fluid", 154, 36, 0xFFD3D7E5, false);
735+
graphics.drawString(this.font, "Tree View | scroll=zoom, R-drag=pan", 6, 18, 0xFFE5E7EB, false);
736+
graphics.drawString(this.font, "AND", 108, 20, EDGE_AND, false);
737+
graphics.drawString(this.font, "OR", 132, 20, EDGE_OR, false);
738+
graphics.drawString(this.font, "S", 148, 20, EDGE_SINGLE, false);
739+
graphics.drawString(this.font, "Drive", 8, 16, 0xFFD3D7E5, false);
740+
graphics.drawString(this.font, "Cube", 8, 56, 0xFFD3D7E5, false);
741+
graphics.drawString(this.font, "Costs", 36, 16, 0xFFD3D7E5, false);
742+
graphics.drawString(this.font, "Idea", 70, 58, 0xFFD3D7E5, false);
743+
graphics.drawString(this.font, "Fl.", 92, 16, 0xFFD3D7E5, false);
730744
if (menu.isResearching()) {
731-
graphics.drawString(this.font, "\u25CF Researching", 22, 148, 0xFF77DD77, false);
745+
graphics.drawString(this.font, "\u25CF Researching", 10, 148, 0xFF77DD77, false);
732746
}
733-
graphics.drawString(this.font, "Zoom " + Math.round(zoom * 100f) + "%", 390, 24, 0xFFD9DDE7, false);
747+
graphics.drawString(this.font, Math.round(zoom * 100f) + "%", 88, 132, 0xFFD9DDE7, false);
734748
}
735-
}
749+
}

src/main/java/com/researchcube/menu/ResearchTableMenu.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,22 @@ public class ResearchTableMenu extends AbstractContainerMenu {
5353
public static final int DATA_COUNT = 4;
5454

5555
// Layout coordinates shared by screens
56-
public static final int DRIVE_X = 26;
57-
public static final int DRIVE_Y = 42;
58-
public static final int CUBE_X = 26;
59-
public static final int CUBE_Y = 78;
60-
public static final int COST_X = 70;
61-
public static final int COST_Y = 42;
62-
public static final int BUCKET_IN_X = 70;
63-
public static final int BUCKET_IN_Y = 86;
64-
public static final int BUCKET_OUT_X = 92;
65-
public static final int BUCKET_OUT_Y = 86;
66-
public static final int IDEA_CHIP_X = 134;
67-
public static final int IDEA_CHIP_Y = 60;
68-
public static final int PLAYER_INV_X = 179;
69-
public static final int PLAYER_INV_Y = 164;
70-
public static final int HOTBAR_X = 179;
71-
public static final int HOTBAR_Y = 222;
56+
public static final int DRIVE_X = 66;
57+
public static final int DRIVE_Y = 79;
58+
public static final int CUBE_X = 66;
59+
public static final int CUBE_Y = 113;
60+
public static final int COST_X = 113;
61+
public static final int COST_Y = 79;
62+
public static final int BUCKET_IN_X = 185;
63+
public static final int BUCKET_IN_Y = 79;
64+
public static final int BUCKET_OUT_X = 185;
65+
public static final int BUCKET_OUT_Y = 97;
66+
public static final int IDEA_CHIP_X = 167;
67+
public static final int IDEA_CHIP_Y = 113;
68+
public static final int PLAYER_INV_X = 245;
69+
public static final int PLAYER_INV_Y = 191;
70+
public static final int HOTBAR_X = 245;
71+
public static final int HOTBAR_Y = 266;
7272

7373
// ── Constructor from server (block entity available) ──
7474
public ResearchTableMenu(int containerId, Inventory playerInv, ResearchTableBlockEntity be) {

src/main/java/com/researchcube/research/ResearchDefinition.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public class ResearchDefinition {
4040
@Nullable
4141
private final String description; // short description (optional)
4242
@Nullable
43+
private final String flavorText; // optional story/lore text for the detail pane
44+
@Nullable
4345
private final String category; // optional grouping category (e.g., "circuits", "energy")
4446
@Nullable
4547
private final FluidCost fluidCost; // optional fluid cost for this research
@@ -49,7 +51,8 @@ public ResearchDefinition(ResourceLocation id, ResearchTier tier, int duration,
4951
Prerequisite prerequisites, List<ItemCost> itemCosts,
5052
List<WeightedRecipe> weightedRecipePool,
5153
@Nullable String name, @Nullable String description,
52-
@Nullable String category, @Nullable FluidCost fluidCost,
54+
@Nullable String flavorText, @Nullable String category,
55+
@Nullable FluidCost fluidCost,
5356
Optional<ItemStack> ideaChip) {
5457
this.id = id;
5558
this.tier = tier;
@@ -60,6 +63,7 @@ public ResearchDefinition(ResourceLocation id, ResearchTier tier, int duration,
6063
this.recipePool = this.weightedRecipePool.stream().map(WeightedRecipe::id).toList();
6164
this.name = name;
6265
this.description = description;
66+
this.flavorText = flavorText;
6367
this.category = category;
6468
this.fluidCost = fluidCost;
6569
this.ideaChip = ideaChip != null ? ideaChip : Optional.empty();
@@ -72,9 +76,10 @@ public ResearchDefinition(ResourceLocation id, ResearchTier tier, int duration,
7276
Prerequisite prerequisites, List<ItemCost> itemCosts,
7377
List<WeightedRecipe> weightedRecipePool,
7478
@Nullable String name, @Nullable String description,
75-
@Nullable String category, @Nullable FluidCost fluidCost) {
79+
@Nullable String flavorText, @Nullable String category,
80+
@Nullable FluidCost fluidCost) {
7681
this(id, tier, duration, prerequisites, itemCosts, weightedRecipePool,
77-
name, description, category, fluidCost, Optional.empty());
82+
name, description, flavorText, category, fluidCost, Optional.empty());
7883
}
7984

8085
/**
@@ -84,9 +89,9 @@ public ResearchDefinition(ResourceLocation id, ResearchTier tier, int duration,
8489
Prerequisite prerequisites, List<ItemCost> itemCosts,
8590
List<WeightedRecipe> weightedRecipePool,
8691
@Nullable String name, @Nullable String description,
87-
@Nullable String category) {
92+
@Nullable String flavorText, @Nullable String category) {
8893
this(id, tier, duration, prerequisites, itemCosts, weightedRecipePool,
89-
name, description, category, null);
94+
name, description, flavorText, category, null);
9095
}
9196

9297
/**
@@ -97,7 +102,7 @@ public ResearchDefinition(ResourceLocation id, ResearchTier tier, int duration,
97102
List<ResourceLocation> recipePool) {
98103
this(id, tier, duration, prerequisites, itemCosts,
99104
recipePool.stream().map(rl -> new WeightedRecipe(rl, 1)).toList(),
100-
null, null, null, null);
105+
null, null, null, null, null);
101106
}
102107

103108
public ResourceLocation getId() {
@@ -186,6 +191,14 @@ public String getDescription() {
186191
return description;
187192
}
188193

194+
/**
195+
* Optional story/lore flavor text for the detail pane.
196+
*/
197+
@Nullable
198+
public String getFlavorText() {
199+
return flavorText;
200+
}
201+
189202
/**
190203
* Optional category for grouping in the UI (e.g., "circuits", "energy").
191204
*/

src/main/java/com/researchcube/research/ResearchManager.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ private ResearchDefinition parseDefinition(ResourceLocation id, JsonObject json)
115115
}
116116

117117
return new ResearchDefinition(id, tier, duration, prerequisites, itemCosts, weightedRecipePool,
118-
parseName(json), parseDescription(json), parseCategory(json), parseFluidCost(json),
119-
parseIdeaChip(json));
118+
parseName(json), parseDescription(json), parseFlavorText(json), parseCategory(json),
119+
parseFluidCost(json), parseIdeaChip(json));
120120
}
121121

122122
@Nullable
@@ -129,6 +129,11 @@ private String parseDescription(JsonObject json) {
129129
return json.has("description") ? json.get("description").getAsString() : null;
130130
}
131131

132+
@Nullable
133+
private String parseFlavorText(JsonObject json) {
134+
return json.has("flavor_text") ? json.get("flavor_text").getAsString() : null;
135+
}
136+
132137
@Nullable
133138
private String parseCategory(JsonObject json) {
134139
return json.has("category") ? json.get("category").getAsString() : null;
-615 Bytes
Loading

src/main/resources/data/researchcube/research/cosmic_assembly.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "Cosmic Assembly",
33
"description": "The ultimate capstone research — assemble cosmic-tier items. Demonstrates a 3-recipe weighted pool at the highest tier. Requires both star_forging and void_synthesis.",
4+
"flavor_text": "When star and void converge, creation itself bends to your will.",
45
"category": "endgame",
56
"tier": "SELF_AWARE",
67
"duration": 48000,

src/main/resources/data/researchcube/research/crystal_growing.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "Crystal Growing",
33
"description": "Grow crystals in a controlled environment using the Processing Station. A processing-only recipe at PRECISE tier.",
4+
"flavor_text": "Patience is the seed from which all great crystals grow.",
45
"category": "processing",
56
"tier": "PRECISE",
67
"duration": 3200,

src/main/resources/data/researchcube/research/ender_weaving.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"name": "Ender Weaving",
33
"description": "Weave ender energy into items. Requires an Irrecoverable Drive as an idea chip and AND prerequisites (lapis_infusion AND potion_brewing).",
4+
"flavor_text": "Between the cracks of reality, the Ender threads wait to be spun.",
45
"category": "magic",
56
"tier": "FLAWLESS",
67
"duration": 8000,

0 commit comments

Comments
 (0)