返回提交历史
Modified
gradle.properties
+1
-1
Added
src/main/java/com/xfestudio/mydimension/client/MindAccessRequestScreen.java
+87
-0
Modified
src/main/java/com/xfestudio/mydimension/client/RiftActionScreen.java
+355
-100
Modified
src/main/java/com/xfestudio/mydimension/client/RiftClient.java
+13
-0
Added
src/main/java/com/xfestudio/mydimension/client/TeamMindScreen.java
+438
-0
Modified
src/main/java/com/xfestudio/mydimension/item/RiftAction.java
+2
-1
Modified
src/main/java/com/xfestudio/mydimension/item/RiftItem.java
+76
-1
Added
src/main/java/com/xfestudio/mydimension/network/MindAccessPromptPacket.java
+27
-0
Modified
src/main/java/com/xfestudio/mydimension/network/ModNetwork.java
+49
-2
Added
src/main/java/com/xfestudio/mydimension/network/TeamMindCommandPacket.java
+160
-0
Added
src/main/java/com/xfestudio/mydimension/network/TeamMindDataPacket.java
+87
-0
Modified
src/main/java/com/xfestudio/mydimension/world/MindInstances.java
+22
-2
Added
src/main/java/com/xfestudio/mydimension/world/MindTeamAccess.java
+236
-0
Added
src/main/java/com/xfestudio/mydimension/world/MindType.java
+29
-0
Modified
src/main/resources/assets/mydimension/lang/en_us.json
+39
-1
Modified
src/main/resources/assets/mydimension/lang/zh_cn.json
+38
-0
XFEstudio/MyDimension
新增团队心境访问功能
f39926c
代码差异
16 个文件
+1659
-108
@@ -11,7 +11,7 @@ loader_version_range=[47,)
11
11
mod_id=mydimension
12
12
mod_name=\u6211\u7684\u7ef4\u5ea6
13
13
mod_license=CC0-1.0
14
mod_version=2.2.3
14
mod_version=2.3.0
15
15
mod_group_id=com.xfestudio.mydimension
16
16
maven_group=com.xfestudio
17
17
archives_base_name=mydimension
@@ -0,0 +1,87 @@
1
package com.xfestudio.mydimension.client;
2
3
import com.xfestudio.mydimension.network.ModNetwork;
4
import com.xfestudio.mydimension.network.TeamMindCommandPacket;
5
import net.minecraft.Util;
6
import net.minecraft.client.gui.GuiGraphics;
7
import net.minecraft.client.gui.components.Button;
8
import net.minecraft.client.gui.screens.Screen;
9
import net.minecraft.network.chat.Component;
10
import net.minecraft.util.Mth;
11
12
import java.util.UUID;
13
14
public class MindAccessRequestScreen extends Screen {
15
private final Screen parent;
16
private final UUID requesterId;
17
private final String requesterName;
18
private final long openedAt = Util.getMillis();
19
private boolean responded;
20
21
public MindAccessRequestScreen(Screen parent, UUID requesterId, String requesterName) {
22
super(Component.translatable("screen.mydimension.team.request_title"));
23
this.parent = parent;
24
this.requesterId = requesterId;
25
this.requesterName = requesterName;
26
}
27
28
@Override
29
protected void init() {
30
int centerX = width / 2;
31
int centerY = height / 2;
32
addRenderableWidget(Button.builder(Component.translatable("screen.mydimension.team.accept"), button -> respond(true))
33
.bounds(centerX - 106, centerY + 24, 98, 22).build());
34
addRenderableWidget(Button.builder(Component.translatable("screen.mydimension.team.deny"), button -> respond(false))
35
.bounds(centerX + 8, centerY + 24, 98, 22).build());
36
}
37
38
@Override
39
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
40
graphics.fillGradient(0, 0, width, height, 0xD0101218, 0xE0181026);
41
float progress = easeOut(Mth.clamp((Util.getMillis() - openedAt) / 220.0F, 0.0F, 1.0F));
42
int centerX = width / 2;
43
int centerY = height / 2;
44
int offset = Math.round((1.0F - progress) * 8.0F);
45
graphics.fill(centerX - 130, centerY - 45 + offset, centerX + 130, centerY + 56 + offset,
46
multiplyAlpha(0xE0060A12, progress));
47
graphics.renderOutline(centerX - 130, centerY - 45 + offset, 260, 101, multiplyAlpha(0xFF85D6F7, progress));
48
graphics.drawCenteredString(font, title, centerX, centerY - 31 + offset, multiplyAlpha(0xFFEAFBFF, progress));
49
Component prompt = Component.translatable("screen.mydimension.team.request_prompt", requesterName);
50
String fittedPrompt = font.plainSubstrByWidth(prompt.getString(), 236);
51
graphics.drawCenteredString(font, fittedPrompt, centerX, centerY - 7 + offset, multiplyAlpha(0xFFC5E7F3, progress));
52
super.render(graphics, mouseX, mouseY, partialTick);
53
}
54
55
@Override
56
public void onClose() {
57
if (!responded) {
58
respond(false);
59
}
60
}
61
62
@Override
63
public boolean isPauseScreen() {
64
return false;
65
}
66
67
private void respond(boolean accepted) {
68
if (responded) {
69
return;
70
}
71
responded = true;
72
ModNetwork.CHANNEL.sendToServer(TeamMindCommandPacket.respond(requesterId, accepted));
73
if (minecraft != null) {
74
minecraft.setScreen(parent);
75
}
76
}
77
78
private static float easeOut(float value) {
79
float inverse = 1.0F - value;
80
return 1.0F - inverse * inverse * inverse;
81
}
82
83
private static int multiplyAlpha(int color, float multiplier) {
84
int alpha = Math.round(((color >>> 24) & 0xFF) * Mth.clamp(multiplier, 0.0F, 1.0F));
85
return (alpha << 24) | (color & 0x00FFFFFF);
86
}
87
}
@@ -1,5 +1,6 @@
1
1
package com.xfestudio.mydimension.client;
2
2
3
import com.mojang.blaze3d.systems.RenderSystem;
3
4
import com.xfestudio.mydimension.MyDimension;
4
5
import com.xfestudio.mydimension.item.RiftAction;
5
6
import com.xfestudio.mydimension.item.RiftItem;
@@ -8,6 +9,7 @@ import com.xfestudio.mydimension.network.SetRiftActionPacket;
8
9
import com.xfestudio.mydimension.registry.ModItems;
9
10
import com.xfestudio.mydimension.world.ModDimensions;
10
11
import com.xfestudio.mydimension.world.PrivateMindFeature;
12
import net.minecraft.Util;
11
13
import net.minecraft.client.Minecraft;
12
14
import net.minecraft.client.gui.Font;
13
15
import net.minecraft.client.gui.GuiGraphics;
@@ -20,18 +22,21 @@ import net.minecraft.world.item.ItemStack;
20
22
21
23
import java.util.ArrayList;
22
24
import java.util.List;
25
import java.util.function.BooleanSupplier;
23
26
24
27
public class RiftActionScreen extends Screen {
25
private static final int BUTTON_HEIGHT = 26;
26
private static final int BUTTON_GAP = 18;
28
private static final int GRID_GAP = 10;
27
29
private static final int TRAVEL_COLOR = 0xFF3E8DB8;
28
30
private static final int MOB_COLOR = 0xFF8B58C8;
29
31
private static final int ANCHOR_COLOR = 0xFFD6A23E;
30
32
private static final int COPY_COLOR = 0xFF4EBA7A;
33
private static final int TEAM_COLOR = 0xFF4FB5A5;
31
34
private static final ResourceLocation RIFT_ICON = new ResourceLocation(MyDimension.MOD_ID, "textures/item/rift.png");
32
35
private static final ResourceLocation PORTAL_ICON = new ResourceLocation("minecraft", "textures/block/nether_portal.png");
33
36
private static final ResourceLocation ANCHOR_ICON = new ResourceLocation(MyDimension.MOD_ID, "textures/gui/rift_anchor_icon.png");
34
37
38
private final long openedAt;
39
private long contentAnimationAt;
35
40
private Page page = Page.TRAVEL_PRIVATE;
36
41
private boolean inMindDimension;
37
42
private boolean creative;
@@ -39,6 +44,8 @@ public class RiftActionScreen extends Screen {
39
44
40
45
public RiftActionScreen() {
41
46
super(Component.translatable("screen.mydimension.rift_actions"));
47
openedAt = Util.getMillis();
48
contentAnimationAt = openedAt;
42
49
}
43
50
44
51
@Override
@@ -46,20 +53,24 @@ public class RiftActionScreen extends Screen {
46
53
inMindDimension = minecraft != null && minecraft.player != null && ModDimensions.isMindDimension(minecraft.player.level().dimension());
47
54
creative = minecraft != null && minecraft.player != null && minecraft.player.isCreative();
48
55
privateMindsEnabled = PrivateMindFeature.isEnabled();
56
normalizePage();
49
57
50
int centerX = width / 2;
51
int centerY = height / 2;
52
addTabs(centerX, centerY - 108);
53
addActionGrid(currentActions(), centerY - 36);
58
Layout layout = createLayout();
59
addModeTabs(layout);
60
if (showsScopeSelector()) {
61
addScopeTabs(layout);
62
}
63
addActionGrid(currentActions(), layout);
54
64
if (inMindDimension) {
55
addCenteredActionButton(RiftAction.SET_ANCHOR, centerY + 88);
65
addAnchorButton(layout);
56
66
}
57
67
}
58
68
59
69
@Override
60
70
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
61
71
graphics.fillGradient(0, 0, width, height, 0xD0101218, 0xE0181026);
62
renderCenterPanel(graphics);
72
renderMotes(graphics);
73
renderCenterPanel(graphics, createLayout());
63
74
super.render(graphics, mouseX, mouseY, partialTick);
64
75
}
65
76
@@ -68,31 +79,161 @@ public class RiftActionScreen extends Screen {
68
79
return false;
69
80
}
70
81
71
private void addTabs(int centerX, int y) {
72
List<Page> pages = visiblePages();
73
int tabWidth = Math.max(68, Math.min(94, (width - 48 - (pages.size() - 1) * 8) / pages.size()));
74
int totalWidth = pages.size() * tabWidth + (pages.size() - 1) * 8;
75
int x = centerX - totalWidth / 2;
76
for (Page tab : pages) {
77
addRenderableWidget(new PageButton(x, y, tabWidth, tab));
78
x += tabWidth + 8;
82
private Layout createLayout() {
83
int desiredHeight = inMindDimension ? 220 : 190;
84
int panelHeight = Math.min(desiredHeight, Math.max(156, height - 12));
85
int panelWidth = Math.min(470, Math.max(280, width - 24));
86
int left = (width - panelWidth) / 2;
87
int top = (height - panelHeight) / 2;
88
return new Layout(left, top, left + panelWidth, top + panelHeight, panelWidth, panelHeight < 205);
89
}
90
91
private void addModeTabs(Layout layout) {
92
List<MenuMode> modes = visibleModes();
93
int height = layout.compact() ? 18 : 22;
94
int gap = 7;
95
int maxWidth = (layout.width() - 28 - gap * (modes.size() - 1)) / modes.size();
96
int tabWidth = Mth.clamp(maxWidth, 74, 112);
97
int totalWidth = modes.size() * tabWidth + (modes.size() - 1) * gap;
98
int x = width / 2 - totalWidth / 2;
99
int y = layout.top() + (layout.compact() ? 28 : 34);
100
101
for (int i = 0; i < modes.size(); i++) {
102
MenuMode mode = modes.get(i);
103
addRenderableWidget(new SegmentButton(x, y, tabWidth, height, mode.title(), button -> switchMode(mode),
104
() -> currentMode() == mode, i));
105
x += tabWidth + gap;
79
106
}
80
107
}
81
108
82
private List<Page> visiblePages() {
83
List<Page> pages = privateMindsEnabled
84
? new ArrayList<>(List.of(Page.TRAVEL_PRIVATE, Page.TRAVEL_SHARED, Page.MOB_PRIVATE, Page.MOB_SHARED))
85
: new ArrayList<>(List.of(Page.TRAVEL_SHARED, Page.MOB_SHARED));
109
private void addScopeTabs(Layout layout) {
110
int tabWidth = Math.min(116, (layout.width() - 42) / 2);
111
int gap = 6;
112
int totalWidth = tabWidth * 2 + gap;
113
int x = width / 2 - totalWidth / 2;
114
int y = layout.top() + (layout.compact() ? 50 : 62);
115
int height = layout.compact() ? 18 : 20;
116
117
addRenderableWidget(new SegmentButton(x, y, tabWidth, height,
118
Component.translatable("screen.mydimension.rift_actions.scope.private"), button -> switchScope(false),
119
() -> !isSharedPage(), 3));
120
addRenderableWidget(new SegmentButton(x + tabWidth + gap, y, tabWidth, height,
121
Component.translatable("screen.mydimension.rift_actions.scope.shared"), button -> switchScope(true),
122
this::isSharedPage, 4));
123
}
124
125
private void addActionGrid(RiftAction[] actions, Layout layout) {
126
int columns = 3;
127
int horizontalPadding = 18;
128
int buttonWidth = (layout.width() - horizontalPadding * 2 - GRID_GAP * (columns - 1)) / columns;
129
int buttonHeight = layout.compact() ? 24 : 30;
130
int rowGap = layout.compact() ? 6 : 10;
131
int left = layout.left() + horizontalPadding;
132
int top = layout.top() + (showsScopeSelector() ? (layout.compact() ? 72 : 90) : (layout.compact() ? 52 : 68));
133
RiftAction selectedAction = getSelectedAction();
86
134
135
for (int i = 0; i < actions.length; i++) {
136
int x = left + (i % columns) * (buttonWidth + GRID_GAP);
137
int y = top + (i / columns) * (buttonHeight + rowGap);
138
addRenderableWidget(new ActionButton(x, y, buttonWidth, buttonHeight, actions[i],
139
selectedAction == actions[i], i, actionLabel(actions[i])));
140
}
141
}
142
143
private void addAnchorButton(Layout layout) {
144
int buttonWidth = Math.min(210, layout.width() - 56);
145
int buttonHeight = layout.compact() ? 24 : 28;
146
int y = layout.bottom() - buttonHeight - (layout.compact() ? 7 : 10);
147
addRenderableWidget(new ActionButton(width / 2 - buttonWidth / 2, y, buttonWidth, buttonHeight,
148
RiftAction.SET_ANCHOR, getSelectedAction() == RiftAction.SET_ANCHOR, 6, RiftAction.SET_ANCHOR.displayName()));
149
}
150
151
private List<MenuMode> visibleModes() {
152
List<MenuMode> modes = new ArrayList<>();
153
modes.add(MenuMode.TRAVEL);
154
if (!inMindDimension) {
155
modes.add(MenuMode.MOB);
156
}
87
157
if (privateMindsEnabled && creative) {
88
pages.add(Page.COPY_SHARED);
158
modes.add(MenuMode.COPY);
159
}
160
if (privateMindsEnabled) {
161
modes.add(MenuMode.TEAM);
162
}
163
return modes;
164
}
165
166
private void normalizePage() {
167
if (!privateMindsEnabled) {
168
page = switch (page) {
169
case MOB_PRIVATE, MOB_SHARED -> inMindDimension ? Page.TRAVEL_SHARED : Page.MOB_SHARED;
170
default -> Page.TRAVEL_SHARED;
171
};
172
return;
89
173
}
90
174
91
if (!pages.contains(page)) {
92
page = pages.get(0);
175
if (!creative && page == Page.COPY_SHARED) {
176
page = Page.TRAVEL_PRIVATE;
177
}
178
if (inMindDimension && (page == Page.MOB_PRIVATE || page == Page.MOB_SHARED)) {
179
page = page == Page.MOB_SHARED ? Page.TRAVEL_SHARED : Page.TRAVEL_PRIVATE;
93
180
}
181
}
94
182
95
return pages;
183
private boolean showsScopeSelector() {
184
return privateMindsEnabled && currentMode() != MenuMode.COPY;
185
}
186
187
private MenuMode currentMode() {
188
return switch (page) {
189
case TRAVEL_PRIVATE, TRAVEL_SHARED -> MenuMode.TRAVEL;
190
case MOB_PRIVATE, MOB_SHARED -> MenuMode.MOB;
191
case COPY_SHARED -> MenuMode.COPY;
192
};
193
}
194
195
private boolean isSharedPage() {
196
return page == Page.TRAVEL_SHARED || page == Page.MOB_SHARED || page == Page.COPY_SHARED;
197
}
198
199
private void switchMode(MenuMode mode) {
200
if (mode == MenuMode.TEAM) {
201
if (minecraft != null) {
202
minecraft.setScreen(new TeamMindScreen(this));
203
}
204
return;
205
}
206
if (mode == currentMode()) {
207
return;
208
}
209
210
boolean shared = !privateMindsEnabled || isSharedPage();
211
page = switch (mode) {
212
case TRAVEL -> shared ? Page.TRAVEL_SHARED : Page.TRAVEL_PRIVATE;
213
case MOB -> shared ? Page.MOB_SHARED : Page.MOB_PRIVATE;
214
case COPY -> Page.COPY_SHARED;
215
case TEAM -> page;
216
};
217
animatePageChange();
218
}
219
220
private void switchScope(boolean shared) {
221
if (shared == isSharedPage() || currentMode() == MenuMode.COPY) {
222
return;
223
}
224
225
page = switch (currentMode()) {
226
case TRAVEL -> shared ? Page.TRAVEL_SHARED : Page.TRAVEL_PRIVATE;
227
case MOB -> shared ? Page.MOB_SHARED : Page.MOB_PRIVATE;
228
case COPY -> Page.COPY_SHARED;
229
case TEAM -> page;
230
};
231
animatePageChange();
232
}
233
234
private void animatePageChange() {
235
contentAnimationAt = Util.getMillis();
236
rebuildWidgets();
96
237
}
97
238
98
239
private RiftAction[] currentActions() {
@@ -105,41 +246,62 @@ public class RiftActionScreen extends Screen {
105
246
};
106
247
}
107
248
108
private void addActionGrid(RiftAction[] actions, int top) {
109
int columns = 3;
110
int buttonWidth = rowButtonWidth(columns);
111
int totalWidth = buttonWidth * columns + BUTTON_GAP * (columns - 1);
112
int left = width / 2 - totalWidth / 2;
113
for (int i = 0; i < actions.length; i++) {
114
int x = left + (i % columns) * (buttonWidth + BUTTON_GAP);
115
int y = top + (i / columns) * 42;
116
addRenderableWidget(new ActionButton(x, y, buttonWidth, actions[i], getSelectedAction() == actions[i]));
249
private Component actionLabel(RiftAction action) {
250
if (privateMindsEnabled) {
251
return action.displayName();
117
252
}
118
}
119
253
120
private void addCenteredActionButton(RiftAction action, int y) {
121
int buttonWidth = Mth.clamp(width / 4, 140, 190);
122
addRenderableWidget(new ActionButton(width / 2 - buttonWidth / 2, y, buttonWidth, action, getSelectedAction() == action));
254
RiftAction simplified = switch (action) {
255
case SHARED_ETHEREAL_MIND -> RiftAction.ETHEREAL_MIND;
256
case SHARED_MIRROR_MIND -> RiftAction.MIRROR_MIND;
257
case SHARED_WATER_MIND -> RiftAction.WATER_MIND;
258
case SHARED_NATURE_MIND -> RiftAction.NATURE_MIND;
259
case SHARED_SOARING_MIND -> RiftAction.SOARING_MIND;
260
case SEND_MOB_SHARED_ETHEREAL -> RiftAction.SEND_MOB_ETHEREAL;
261
case SEND_MOB_SHARED_MIRROR -> RiftAction.SEND_MOB_MIRROR;
262
case SEND_MOB_SHARED_WATER -> RiftAction.SEND_MOB_WATER;
263
case SEND_MOB_SHARED_NATURE -> RiftAction.SEND_MOB_NATURE;
264
case SEND_MOB_SHARED_SOARING -> RiftAction.SEND_MOB_SOARING;
265
default -> action;
266
};
267
return simplified.displayName();
123
268
}
124
269
125
private int rowButtonWidth(int columns) {
126
int available = Math.max(96, width - 64);
127
int maxByWidth = (available - (columns - 1) * BUTTON_GAP) / columns;
128
return Mth.clamp(maxByWidth, 64, 150);
270
private void renderCenterPanel(GuiGraphics graphics, Layout layout) {
271
float progress = openingProgress(0, 260);
272
int titleOffset = Math.round((1.0F - easeOut(progress)) * 7.0F);
273
int panelFill = multiplyAlpha(0xC0060A12, progress);
274
int panelEdge = multiplyAlpha(0xFF85D6F7, progress);
275
276
fillRoundedRect(graphics, layout.left(), layout.top(), layout.right(), layout.bottom(), 8, panelFill);
277
drawRoundedBorder(graphics, layout.left(), layout.top(), layout.right(), layout.bottom(), 8, panelEdge);
278
graphics.fill(layout.left() + 12, layout.top() + 1, layout.left() + 72, layout.top() + 3,
279
multiplyAlpha(currentMode().accentColor(), progress));
280
graphics.drawCenteredString(font, title, width / 2, layout.top() + (layout.compact() ? 9 : 13) + titleOffset,
281
multiplyAlpha(0xFFEAFBFF, progress));
282
283
if (!layout.compact()) {
284
int footerY = inMindDimension ? layout.bottom() - 55 : layout.bottom() - 19;
285
Component selected = Component.translatable("screen.mydimension.rift_actions.selected", actionLabel(getSelectedAction()));
286
graphics.drawCenteredString(font, selected, width / 2, footerY, multiplyAlpha(0xFFA9C9D8, progress));
287
}
129
288
}
130
289
131
private void renderCenterPanel(GuiGraphics graphics) {
132
int centerX = width / 2;
133
int centerY = height / 2;
134
int left = centerX - 180;
135
int top = centerY - 72;
136
int right = centerX + 180;
137
int bottom = centerY + 72;
138
139
fillRoundedRect(graphics, left, top, right, bottom, 7, 0x99060A12);
140
drawRoundedBorder(graphics, left, top, right, bottom, 7, 0xFF85D6F7);
141
graphics.drawCenteredString(font, title, centerX, centerY - 61, 0xFFEAFBFF);
142
graphics.drawCenteredString(font, page.title(), centerX, centerY + 52, page == Page.COPY_SHARED ? 0xFFB8FFD2 : 0xFF9DDBFF);
290
private void renderMotes(GuiGraphics graphics) {
291
long elapsed = Util.getMillis() - openedAt;
292
int verticalSpan = Math.max(1, height + 36);
293
int horizontalSpan = Math.max(1, width - 20);
294
float progress = openingProgress(80, 420);
295
296
for (int i = 0; i < 16; i++) {
297
int x = 10 + Math.floorMod(i * 83 + (i % 3) * 29, horizontalSpan);
298
int drift = (int) (elapsed * (0.006F + (i % 4) * 0.0015F));
299
int y = Math.floorMod(i * 47 - drift, verticalSpan) - 18;
300
int size = i % 5 == 0 ? 2 : 1;
301
int color = i % 3 == 0 ? 0xFF9A6CE0 : 0xFF70D4F4;
302
int alpha = 28 + (i % 4) * 9;
303
graphics.fill(x, y, x + size, y + size, multiplyAlpha(withAlpha(color, alpha), progress));
304
}
143
305
}
144
306
145
307
private RiftAction getSelectedAction() {
@@ -153,7 +315,8 @@ public class RiftActionScreen extends Screen {
153
315
}
154
316
155
317
ItemStack offHand = minecraft.player.getOffhandItem();
156
return offHand.is(ModItems.RIFT.get()) ? RiftItem.getSelectedAction(offHand) : (privateMindsEnabled ? RiftAction.ETHEREAL_MIND : RiftAction.SHARED_ETHEREAL_MIND);
318
return offHand.is(ModItems.RIFT.get()) ? RiftItem.getSelectedAction(offHand)
319
: (privateMindsEnabled ? RiftAction.ETHEREAL_MIND : RiftAction.SHARED_ETHEREAL_MIND);
157
320
}
158
321
159
322
private void select(RiftAction action) {
@@ -163,6 +326,50 @@ public class RiftActionScreen extends Screen {
163
326
}
164
327
}
165
328
329
private float openingProgress(int delayMillis, int durationMillis) {
330
return animationProgress(openedAt, delayMillis, durationMillis);
331
}
332
333
private float contentProgress(int order) {
334
return easeOut(animationProgress(contentAnimationAt, order * 34, 210));
335
}
336
337
private float animationProgress(long startedAt, int delayMillis, int durationMillis) {
338
float elapsed = Util.getMillis() - startedAt - delayMillis;
339
return Mth.clamp(elapsed / durationMillis, 0.0F, 1.0F);
340
}
341
342
private static float easeOut(float value) {
343
float inverse = 1.0F - value;
344
return 1.0F - inverse * inverse * inverse;
345
}
346
347
private static int multiplyAlpha(int color, float multiplier) {
348
int alpha = Math.round(((color >>> 24) & 0xFF) * Mth.clamp(multiplier, 0.0F, 1.0F));
349
return (alpha << 24) | (color & 0x00FFFFFF);
350
}
351
352
private static int withAlpha(int color, int alpha) {
353
return (Mth.clamp(alpha, 0, 255) << 24) | (color & 0x00FFFFFF);
354
}
355
356
private static int mixColor(int from, int to, float amount) {
357
float value = Mth.clamp(amount, 0.0F, 1.0F);
358
int alpha = Math.round(Mth.lerp(value, (from >>> 24) & 0xFF, (to >>> 24) & 0xFF));
359
int red = Math.round(Mth.lerp(value, (from >>> 16) & 0xFF, (to >>> 16) & 0xFF));
360
int green = Math.round(Mth.lerp(value, (from >>> 8) & 0xFF, (to >>> 8) & 0xFF));
361
int blue = Math.round(Mth.lerp(value, from & 0xFF, to & 0xFF));
362
return (alpha << 24) | (red << 16) | (green << 8) | blue;
363
}
364
365
private static int darken(int color) {
366
int alpha = color & 0xFF000000;
367
int red = (int) (((color >> 16) & 0xFF) * 0.58F);
368
int green = (int) (((color >> 8) & 0xFF) * 0.58F);
369
int blue = (int) ((color & 0xFF) * 0.58F);
370
return alpha | (red << 16) | (green << 8) | blue;
371
}
372
166
373
private static void fillRoundedRect(GuiGraphics graphics, int left, int top, int right, int bottom, int radius, int color) {
167
374
graphics.fill(left + radius, top, right - radius, bottom, color);
168
375
graphics.fill(left, top + radius, right, bottom - radius, color);
@@ -183,76 +390,133 @@ public class RiftActionScreen extends Screen {
183
390
}
184
391
185
392
private enum Page {
186
TRAVEL_PRIVATE("screen.mydimension.rift_actions.page.travel_private"),
187
TRAVEL_SHARED("screen.mydimension.rift_actions.page.travel_shared"),
188
MOB_PRIVATE("screen.mydimension.rift_actions.page.mob_private"),
189
MOB_SHARED("screen.mydimension.rift_actions.page.mob_shared"),
190
COPY_SHARED("screen.mydimension.rift_actions.page.copy_shared");
393
TRAVEL_PRIVATE,
394
TRAVEL_SHARED,
395
MOB_PRIVATE,
396
MOB_SHARED,
397
COPY_SHARED
398
}
399
400
private enum MenuMode {
401
TRAVEL("screen.mydimension.rift_actions.travel", TRAVEL_COLOR),
402
MOB("screen.mydimension.rift_actions.mob", MOB_COLOR),
403
COPY("screen.mydimension.rift_actions.copy", COPY_COLOR),
404
TEAM("screen.mydimension.rift_actions.team", TEAM_COLOR);
191
405
192
406
private final String translationKey;
407
private final int accentColor;
193
408
194
Page(String translationKey) {
409
MenuMode(String translationKey, int accentColor) {
195
410
this.translationKey = translationKey;
411
this.accentColor = accentColor;
196
412
}
197
413
198
414
private Component title() {
199
415
return Component.translatable(translationKey);
200
416
}
417
418
private int accentColor() {
419
return accentColor;
420
}
201
421
}
202
422
203
private class PageButton extends Button {
204
private final Page targetPage;
423
private record Layout(int left, int top, int right, int bottom, int width, boolean compact) {
424
}
425
426
private class SegmentButton extends Button {
427
private final BooleanSupplier selected;
428
private final int animationOrder;
429
private float hoverProgress;
205
430
206
private PageButton(int x, int y, int width, Page targetPage) {
207
super(x, y, width, 20, targetPage.title(), button -> {
208
page = targetPage;
209
rebuildWidgets();
210
}, DEFAULT_NARRATION);
211
this.targetPage = targetPage;
431
private SegmentButton(int x, int y, int width, int height, Component message, OnPress onPress,
432
BooleanSupplier selected, int animationOrder) {
433
super(x, y, width, height, message, onPress, DEFAULT_NARRATION);
434
this.selected = selected;
435
this.animationOrder = animationOrder;
212
436
}
213
437
214
438
@Override
215
439
protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
216
int fill = targetPage == page ? 0xD6D6A23E : (isHoveredOrFocused() ? 0xC83E8DB8 : 0x963E8DB8);
217
fillRoundedRect(graphics, getX(), getY(), getX() + getWidth(), getY() + getHeight(), 5, fill);
218
drawRoundedBorder(graphics, getX(), getY(), getX() + getWidth(), getY() + getHeight(), 5, targetPage == page ? 0xFFFFF4A8 : 0xFFB8F0FF);
219
drawCenteredFittingText(graphics, Minecraft.getInstance().font, getMessage(), getX(), getY(), getWidth(), getHeight(), 0xFFEAFBFF);
440
hoverProgress = Mth.clamp(hoverProgress + (isHoveredOrFocused() ? 0.16F : -0.16F), 0.0F, 1.0F);
441
float progress = easeOut(openingProgress(animationOrder * 24, 220));
442
int offset = Math.round((1.0F - progress) * 5.0F);
443
int left = getX();
444
int top = getY() + offset;
445
int right = left + getWidth();
446
int bottom = top + getHeight();
447
boolean active = selected.getAsBoolean();
448
int activeColor = currentMode().accentColor();
449
int fill = active ? withAlpha(activeColor, 218) : mixColor(0xA62A4354, 0xD0487894, hoverProgress);
450
int edge = active ? 0xFFFFEEA3 : mixColor(0xFF7096AA, 0xFFC9F5FF, hoverProgress);
451
452
fillRoundedRect(graphics, left, top, right, bottom, 5, multiplyAlpha(fill, progress));
453
drawRoundedBorder(graphics, left, top, right, bottom, 5, multiplyAlpha(edge, progress));
454
if (active) {
455
int lineWidth = Math.max(12, getWidth() / 3);
456
graphics.fill(left + (getWidth() - lineWidth) / 2, bottom - 2,
457
right - (getWidth() - lineWidth) / 2, bottom - 1, multiplyAlpha(0xFFFFF3B0, progress));
458
}
459
drawCenteredFittingText(graphics, Minecraft.getInstance().font, getMessage(), left, top, getWidth(), getHeight(),
460
multiplyAlpha(active || hoverProgress > 0.15F ? 0xFFFFFFFF : 0xFFD8E9F0, progress));
220
461
}
221
462
}
222
463
223
464
private class ActionButton extends Button {
224
465
private final RiftAction action;
225
466
private final boolean selected;
467
private final int animationOrder;
468
private float hoverProgress;
226
469
227
private ActionButton(int x, int y, int width, RiftAction action, boolean selected) {
228
super(x, y, width, BUTTON_HEIGHT, action.displayName(), button -> select(action), DEFAULT_NARRATION);
470
private ActionButton(int x, int y, int width, int height, RiftAction action, boolean selected,
471
int animationOrder, Component message) {
472
super(x, y, width, height, message, button -> select(action), DEFAULT_NARRATION);
229
473
this.action = action;
230
474
this.selected = selected;
475
this.animationOrder = animationOrder;
231
476
}
232
477
233
478
@Override
234
479
protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
480
hoverProgress = Mth.clamp(hoverProgress + (isHoveredOrFocused() ? 0.14F : -0.14F), 0.0F, 1.0F);
481
float progress = contentProgress(animationOrder);
482
if (progress <= 0.01F) {
483
return;
484
}
485
235
486
int left = getX();
236
int top = getY();
487
int top = getY() + Math.round((1.0F - progress) * 9.0F);
237
488
int right = left + getWidth();
238
489
int bottom = top + getHeight();
239
int base = action == RiftAction.SET_ANCHOR ? ANCHOR_COLOR : (action.copiesSharedDimension() ? COPY_COLOR : (action.sendsMob() ? MOB_COLOR : TRAVEL_COLOR));
240
int fill = withAlpha(base, isHoveredOrFocused() ? 226 : 174);
241
int edge = selected ? 0xFFFFF4A8 : (action == RiftAction.SET_ANCHOR ? 0xFFFFE0A3 : (action.copiesSharedDimension() ? 0xFFB8FFD2 : (action.sendsMob() ? 0xFFD8C1FF : 0xFFB8F0FF)));
490
int base = action == RiftAction.SET_ANCHOR ? ANCHOR_COLOR
491
: (action.copiesSharedDimension() ? COPY_COLOR : (action.sendsMob() ? MOB_COLOR : TRAVEL_COLOR));
492
int fill = withAlpha(base, Math.round(Mth.lerp(hoverProgress, 172.0F, 232.0F)));
493
int edge = selected ? 0xFFFFF4A8
494
: (action == RiftAction.SET_ANCHOR ? 0xFFFFE0A3
495
: (action.copiesSharedDimension() ? 0xFFB8FFD2 : (action.sendsMob() ? 0xFFD8C1FF : 0xFFB8F0FF)));
496
497
fillRoundedRect(graphics, left, top, right, bottom, 7, multiplyAlpha(darken(fill), progress));
498
fillRoundedRect(graphics, left + 1, top + 1, right - 1, bottom - 1, 6, multiplyAlpha(fill, progress));
499
drawRoundedBorder(graphics, left, top, right, bottom, 7, multiplyAlpha(edge, progress));
242
500
243
fillRoundedRect(graphics, left, top, right, bottom, 7, darken(fill));
244
fillRoundedRect(graphics, left + 1, top + 1, right - 1, bottom - 1, 6, fill);
245
drawRoundedBorder(graphics, left, top, right, bottom, 7, edge);
246
501
if (selected) {
247
fillRoundedRect(graphics, left + 4, top + 5, left + 8, bottom - 5, 2, 0xFFFFF4A8);
502
float pulse = 0.72F + (Mth.sin(Util.getMillis() / 210.0F) + 1.0F) * 0.12F;
503
fillRoundedRect(graphics, left + 4, top + 5, left + 7, bottom - 5, 2,
504
multiplyAlpha(0xFFFFF4A8, progress * pulse));
505
}
506
if (hoverProgress > 0.01F) {
507
int glintWidth = Math.round((getWidth() - 18) * hoverProgress);
508
graphics.fill(left + 9, bottom - 3, left + 9 + glintWidth, bottom - 2,
509
multiplyAlpha(edge, progress * hoverProgress * 0.85F));
248
510
}
249
511
250
renderIcon(graphics, left + 10, top + 5);
251
int textColor = isHoveredOrFocused() ? 0xFFFFFFFF : 0xFFEAFBFF;
252
drawFittingText(graphics, Minecraft.getInstance().font, getMessage(), left + 32, top, getWidth() - 38, getHeight(), textColor);
512
renderIcon(graphics, left + 9 + Math.round(hoverProgress * 2.0F), top + (getHeight() - 16) / 2, progress);
513
int textColor = mixColor(0xFFEAFBFF, 0xFFFFFFFF, hoverProgress);
514
drawFittingText(graphics, Minecraft.getInstance().font, getMessage(), left + 32, top,
515
getWidth() - 38, getHeight(), multiplyAlpha(textColor, progress));
253
516
}
254
517
255
private void renderIcon(GuiGraphics graphics, int x, int y) {
518
private void renderIcon(GuiGraphics graphics, int x, int y, float opacity) {
519
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, opacity);
256
520
if (action == RiftAction.SET_ANCHOR) {
257
521
graphics.blit(ANCHOR_ICON, x, y, 0, 0, 16, 16, 16, 16);
258
522
} else if (action.sendsMob()) {
@@ -260,27 +524,18 @@ public class RiftActionScreen extends Screen {
260
524
} else {
261
525
graphics.blit(RIFT_ICON, x, y, 0, 0, 16, 16, 16, 16);
262
526
}
263
}
264
265
private int withAlpha(int color, int alpha) {
266
return (Mth.clamp(alpha, 0, 255) << 24) | (color & 0x00FFFFFF);
267
}
268
269
private int darken(int color) {
270
int alpha = color & 0xFF000000;
271
int red = (int) (((color >> 16) & 0xFF) * 0.58F);
272
int green = (int) (((color >> 8) & 0xFF) * 0.58F);
273
int blue = (int) ((color & 0xFF) * 0.58F);
274
return alpha | (red << 16) | (green << 8) | blue;
527
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
275
528
}
276
529
}
277
530
278
private static void drawCenteredFittingText(GuiGraphics graphics, Font font, Component text, int left, int top, int width, int height, int color) {
531
private static void drawCenteredFittingText(GuiGraphics graphics, Font font, Component text,
532
int left, int top, int width, int height, int color) {
279
533
String label = font.plainSubstrByWidth(text.getString(), width - 8);
280
534
graphics.drawCenteredString(font, label, left + width / 2, top + (height - 8) / 2, color);
281
535
}
282
536
283
private static void drawFittingText(GuiGraphics graphics, Font font, Component text, int left, int top, int width, int height, int color) {
537
private static void drawFittingText(GuiGraphics graphics, Font font, Component text,
538
int left, int top, int width, int height, int color) {
284
539
String label = font.plainSubstrByWidth(text.getString(), width);
285
540
graphics.drawString(font, label, left, top + (height - 8) / 2, color);
286
541
}
@@ -1,9 +1,22 @@
1
1
package com.xfestudio.mydimension.client;
2
2
3
import com.xfestudio.mydimension.network.MindAccessPromptPacket;
4
import com.xfestudio.mydimension.network.TeamMindDataPacket;
3
5
import net.minecraft.client.Minecraft;
4
6
5
7
public class RiftClient {
6
8
public static void openActionScreen() {
7
9
Minecraft.getInstance().setScreen(new RiftActionScreen());
8
10
}
11
12
public static void handleTeamMindData(TeamMindDataPacket packet) {
13
if (Minecraft.getInstance().screen instanceof TeamMindScreen screen) {
14
screen.updateData(packet);
15
}
16
}
17
18
public static void openMindAccessPrompt(MindAccessPromptPacket packet) {
19
Minecraft minecraft = Minecraft.getInstance();
20
minecraft.setScreen(new MindAccessRequestScreen(minecraft.screen, packet.requesterId(), packet.requesterName()));
21
}
9
22
}
@@ -0,0 +1,438 @@
1
package com.xfestudio.mydimension.client;
2
3
import com.xfestudio.mydimension.MyDimension;
4
import com.xfestudio.mydimension.network.ModNetwork;
5
import com.xfestudio.mydimension.network.TeamMindCommandPacket;
6
import com.xfestudio.mydimension.network.TeamMindDataPacket;
7
import com.xfestudio.mydimension.world.MindType;
8
import net.minecraft.Util;
9
import net.minecraft.client.Minecraft;
10
import net.minecraft.client.gui.Font;
11
import net.minecraft.client.gui.GuiGraphics;
12
import net.minecraft.client.gui.components.Button;
13
import net.minecraft.client.gui.screens.Screen;
14
import net.minecraft.network.chat.Component;
15
import net.minecraft.resources.ResourceLocation;
16
import net.minecraft.util.Mth;
17
18
import java.util.HashSet;
19
import java.util.List;
20
import java.util.Set;
21
import java.util.UUID;
22
import java.util.function.BooleanSupplier;
23
24
public class TeamMindScreen extends Screen {
25
private static final int ENTRANCE_COLOR = 0xFF3E8DB8;
26
private static final int ADD_COLOR = 0xFF4EBA7A;
27
private static final int MANAGE_COLOR = 0xFF8B58C8;
28
private static final ResourceLocation RIFT_ICON = new ResourceLocation(MyDimension.MOD_ID, "textures/item/rift.png");
29
30
private final Screen parent;
31
private final long openedAt = Util.getMillis();
32
private final Set<UUID> requestedPlayers = new HashSet<>();
33
private TeamTab tab = TeamTab.ENTRANCES;
34
private List<TeamMindDataPacket.PlayerInfo> entrances = List.of();
35
private List<TeamMindDataPacket.PlayerInfo> candidates = List.of();
36
private List<TeamMindDataPacket.PlayerInfo> guests = List.of();
37
private UUID selectedOwner;
38
private int listPage;
39
private boolean requestedData;
40
41
public TeamMindScreen(Screen parent) {
42
super(Component.translatable("screen.mydimension.team.title"));
43
this.parent = parent;
44
}
45
46
@Override
47
protected void init() {
48
Layout layout = createLayout();
49
addTabButtons(layout);
50
switch (tab) {
51
case ENTRANCES -> addEntranceWidgets(layout);
52
case ADD -> addPlayerRows(layout, candidates, RowAction.REQUEST);
53
case MANAGE -> addPlayerRows(layout, guests, RowAction.REVOKE);
54
}
55
addFooterButtons(layout);
56
57
if (!requestedData) {
58
requestedData = true;
59
ModNetwork.CHANNEL.sendToServer(TeamMindCommandPacket.refresh());
60
}
61
}
62
63
public void updateData(TeamMindDataPacket packet) {
64
entrances = packet.entrances();
65
candidates = packet.candidates();
66
guests = packet.guests();
67
requestedPlayers.clear();
68
if (selectedOwner == null || entrances.stream().noneMatch(player -> player.id().equals(selectedOwner))) {
69
selectedOwner = entrances.isEmpty() ? null : entrances.get(0).id();
70
}
71
clampPage();
72
rebuildWidgets();
73
}
74
75
@Override
76
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
77
graphics.fillGradient(0, 0, width, height, 0xD0101218, 0xE0181026);
78
Layout layout = createLayout();
79
float progress = easeOut(Mth.clamp((Util.getMillis() - openedAt) / 260.0F, 0.0F, 1.0F));
80
fillRoundedRect(graphics, layout.left(), layout.top(), layout.right(), layout.bottom(), 8,
81
multiplyAlpha(0xD0060A12, progress));
82
drawRoundedBorder(graphics, layout.left(), layout.top(), layout.right(), layout.bottom(), 8,
83
multiplyAlpha(0xFF85D6F7, progress));
84
graphics.fill(layout.left() + 12, layout.top() + 1, layout.left() + 78, layout.top() + 3,
85
multiplyAlpha(tab.color(), progress));
86
graphics.drawCenteredString(font, title, width / 2, layout.top() + 13, multiplyAlpha(0xFFEAFBFF, progress));
87
88
renderContentLabels(graphics, layout, progress);
89
super.render(graphics, mouseX, mouseY, partialTick);
90
}
91
92
@Override
93
public void onClose() {
94
if (minecraft != null) {
95
minecraft.setScreen(parent);
96
}
97
}
98
99
@Override
100
public boolean isPauseScreen() {
101
return false;
102
}
103
104
private Layout createLayout() {
105
int panelWidth = Math.min(500, Math.max(300, width - 24));
106
int panelHeight = Math.min(252, Math.max(190, height - 12));
107
int left = (width - panelWidth) / 2;
108
int top = (height - panelHeight) / 2;
109
return new Layout(left, top, left + panelWidth, top + panelHeight, panelWidth, panelHeight);
110
}
111
112
private void addTabButtons(Layout layout) {
113
TeamTab[] tabs = TeamTab.values();
114
int gap = 7;
115
int tabWidth = Math.min(118, (layout.width() - 36 - gap * (tabs.length - 1)) / tabs.length);
116
int totalWidth = tabWidth * tabs.length + gap * (tabs.length - 1);
117
int x = width / 2 - totalWidth / 2;
118
int y = layout.top() + 34;
119
120
for (int i = 0; i < tabs.length; i++) {
121
TeamTab target = tabs[i];
122
addRenderableWidget(new TeamButton(x, y, tabWidth, 22, target.title(), target.color(),
123
() -> tab == target, i, button -> {
124
tab = target;
125
listPage = 0;
126
rebuildWidgets();
127
}));
128
x += tabWidth + gap;
129
}
130
}
131
132
private void addEntranceWidgets(Layout layout) {
133
int contentTop = layout.top() + 66;
134
int leftWidth = Math.min(156, Math.max(112, layout.width() / 3));
135
int left = layout.left() + 16;
136
int from = listPage * rowsPerPage();
137
int to = Math.min(entrances.size(), from + rowsPerPage());
138
139
for (int index = from; index < to; index++) {
140
TeamMindDataPacket.PlayerInfo owner = entrances.get(index);
141
int y = contentTop + (index - from) * 25;
142
addRenderableWidget(new TeamButton(left, y, leftWidth, 23, Component.literal(owner.name()), ENTRANCE_COLOR,
143
() -> owner.id().equals(selectedOwner), index - from + 3, button -> {
144
selectedOwner = owner.id();
145
rebuildWidgets();
146
}));
147
}
148
149
if (selectedOwner == null) {
150
return;
151
}
152
153
int right = left + leftWidth + 16;
154
int availableWidth = layout.right() - 16 - right;
155
int gap = 8;
156
int buttonWidth = (availableWidth - gap) / 2;
157
MindType[] mindTypes = MindType.values();
158
for (int i = 0; i < mindTypes.length; i++) {
159
MindType mindType = mindTypes[i];
160
int x = right + (i % 2) * (buttonWidth + gap);
161
int y = contentTop + (i / 2) * 31;
162
addRenderableWidget(new MindButton(x, y, buttonWidth, 25, mindType, i + 5));
163
}
164
addPaginationButtons(layout, entrances);
165
}
166
167
private void addPlayerRows(Layout layout, List<TeamMindDataPacket.PlayerInfo> players, RowAction action) {
168
int rowsPerPage = rowsPerPage();
169
int from = listPage * rowsPerPage;
170
int to = Math.min(players.size(), from + rowsPerPage);
171
int left = layout.left() + 24;
172
int right = layout.right() - 24;
173
int top = layout.top() + 66;
174
int actionWidth = 78;
175
176
for (int index = from; index < to; index++) {
177
TeamMindDataPacket.PlayerInfo player = players.get(index);
178
int row = index - from;
179
int y = top + row * 25;
180
addRenderableWidget(new TeamButton(left, y, right - left - actionWidth - 8, 23,
181
Component.literal(player.name()), tab.color(), () -> false, row + 3, button -> {
182
}));
183
184
boolean pending = action == RowAction.REQUEST && requestedPlayers.contains(player.id());
185
Component label = pending
186
? Component.translatable("screen.mydimension.team.requested")
187
: Component.translatable(action.translationKey());
188
TeamButton actionButton = new TeamButton(right - actionWidth, y, actionWidth, 23, label,
189
action == RowAction.REQUEST ? ADD_COLOR : 0xFFC95D66, () -> false, row + 4, button -> {
190
if (action == RowAction.REQUEST) {
191
requestedPlayers.add(player.id());
192
ModNetwork.CHANNEL.sendToServer(TeamMindCommandPacket.requestAccess(player.id()));
193
rebuildWidgets();
194
} else {
195
ModNetwork.CHANNEL.sendToServer(TeamMindCommandPacket.revoke(player.id()));
196
}
197
});
198
actionButton.active = !pending;
199
addRenderableWidget(actionButton);
200
}
201
202
addPaginationButtons(layout, players);
203
}
204
205
private void addFooterButtons(Layout layout) {
206
int y = layout.bottom() - 29;
207
addRenderableWidget(new TeamButton(layout.left() + 12, y, 62, 20,
208
Component.translatable("gui.back"), 0xFF47677A, () -> false, 10, button -> onClose()));
209
addRenderableWidget(new TeamButton(layout.right() - 74, y, 62, 20,
210
Component.translatable("screen.mydimension.team.refresh"), 0xFF47677A, () -> false, 10, button -> {
211
ModNetwork.CHANNEL.sendToServer(TeamMindCommandPacket.refresh());
212
}));
213
}
214
215
private void renderContentLabels(GuiGraphics graphics, Layout layout, float progress) {
216
int color = multiplyAlpha(0xFFA9C9D8, progress);
217
if (tab == TeamTab.ENTRANCES) {
218
if (entrances.isEmpty()) {
219
graphics.drawCenteredString(font, Component.translatable("screen.mydimension.team.no_entrances"),
220
width / 2, layout.top() + 119, color);
221
return;
222
}
223
TeamMindDataPacket.PlayerInfo owner = selectedOwnerInfo();
224
if (owner != null) {
225
int leftWidth = Math.min(156, Math.max(112, layout.width() / 3));
226
int center = layout.left() + 16 + leftWidth + 16 + (layout.right() - 16 - (layout.left() + 16 + leftWidth + 16)) / 2;
227
graphics.drawCenteredString(font, Component.translatable("screen.mydimension.team.owner_minds", owner.name()),
228
center, layout.top() + 62, color);
229
}
230
renderPageNumber(graphics, layout, entrances, color);
231
} else {
232
List<TeamMindDataPacket.PlayerInfo> players = currentList();
233
if (players.isEmpty()) {
234
Component empty = Component.translatable(tab == TeamTab.ADD
235
? "screen.mydimension.team.no_candidates"
236
: "screen.mydimension.team.no_guests");
237
graphics.drawCenteredString(font, empty, width / 2, layout.top() + 119, color);
238
}
239
renderPageNumber(graphics, layout, players, color);
240
}
241
}
242
243
private TeamMindDataPacket.PlayerInfo selectedOwnerInfo() {
244
return entrances.stream().filter(player -> player.id().equals(selectedOwner)).findFirst().orElse(null);
245
}
246
247
private List<TeamMindDataPacket.PlayerInfo> currentList() {
248
return switch (tab) {
249
case ENTRANCES -> entrances;
250
case ADD -> candidates;
251
case MANAGE -> guests;
252
};
253
}
254
255
private void addPaginationButtons(Layout layout, List<?> values) {
256
int pages = pageCount(values);
257
if (pages <= 1) {
258
return;
259
}
260
261
int y = layout.bottom() - 39;
262
TeamButton previous = new TeamButton(width / 2 - 54, y, 24, 20, Component.literal("<"), tab.color(),
263
() -> false, 9, button -> changePage(-1));
264
previous.active = listPage > 0;
265
addRenderableWidget(previous);
266
TeamButton next = new TeamButton(width / 2 + 30, y, 24, 20, Component.literal(">"), tab.color(),
267
() -> false, 9, button -> changePage(1));
268
next.active = listPage + 1 < pages;
269
addRenderableWidget(next);
270
}
271
272
private void renderPageNumber(GuiGraphics graphics, Layout layout, List<?> values, int color) {
273
int pages = pageCount(values);
274
if (pages > 1) {
275
graphics.drawCenteredString(font, Component.literal((listPage + 1) + " / " + pages),
276
width / 2, layout.bottom() - 34, color);
277
}
278
}
279
280
private void changePage(int amount) {
281
listPage = Mth.clamp(listPage + amount, 0, Math.max(0, pageCount(currentList()) - 1));
282
if (tab == TeamTab.ENTRANCES && !entrances.isEmpty()) {
283
selectedOwner = entrances.get(Math.min(entrances.size() - 1, listPage * rowsPerPage())).id();
284
}
285
rebuildWidgets();
286
}
287
288
private void clampPage() {
289
listPage = Mth.clamp(listPage, 0, Math.max(0, pageCount(currentList()) - 1));
290
}
291
292
private static int pageCount(List<?> values) {
293
int rowsPerPage = rowsPerPage();
294
return Math.max(1, (values.size() + rowsPerPage - 1) / rowsPerPage);
295
}
296
297
private static int rowsPerPage() {
298
Minecraft minecraft = Minecraft.getInstance();
299
return minecraft.getWindow().getGuiScaledHeight() < 232 ? 3 : 5;
300
}
301
302
private static float easeOut(float value) {
303
float inverse = 1.0F - value;
304
return 1.0F - inverse * inverse * inverse;
305
}
306
307
private static int multiplyAlpha(int color, float multiplier) {
308
int alpha = Math.round(((color >>> 24) & 0xFF) * Mth.clamp(multiplier, 0.0F, 1.0F));
309
return (alpha << 24) | (color & 0x00FFFFFF);
310
}
311
312
private static int withAlpha(int color, int alpha) {
313
return (Mth.clamp(alpha, 0, 255) << 24) | (color & 0x00FFFFFF);
314
}
315
316
private static void fillRoundedRect(GuiGraphics graphics, int left, int top, int right, int bottom, int radius, int color) {
317
graphics.fill(left + radius, top, right - radius, bottom, color);
318
graphics.fill(left, top + radius, right, bottom - radius, color);
319
graphics.fill(left + 1, top + 1, right - 1, top + radius, color);
320
graphics.fill(left + 1, bottom - radius, right - 1, bottom - 1, color);
321
}
322
323
private static void drawRoundedBorder(GuiGraphics graphics, int left, int top, int right, int bottom, int radius, int color) {
324
graphics.fill(left + radius, top, right - radius, top + 1, color);
325
graphics.fill(left + radius, bottom - 1, right - radius, bottom, color);
326
graphics.fill(left, top + radius, left + 1, bottom - radius, color);
327
graphics.fill(right - 1, top + radius, right, bottom - radius, color);
328
graphics.fill(left + 1, top + 1, left + radius, top + 2, color);
329
graphics.fill(right - radius, top + 1, right - 1, top + 2, color);
330
graphics.fill(left + 1, bottom - 2, left + radius, bottom - 1, color);
331
graphics.fill(right - radius, bottom - 2, right - 1, bottom - 1, color);
332
}
333
334
private enum TeamTab {
335
ENTRANCES("screen.mydimension.team.tab.entrances", ENTRANCE_COLOR),
336
ADD("screen.mydimension.team.tab.add", ADD_COLOR),
337
MANAGE("screen.mydimension.team.tab.manage", MANAGE_COLOR);
338
339
private final String translationKey;
340
private final int color;
341
342
TeamTab(String translationKey, int color) {
343
this.translationKey = translationKey;
344
this.color = color;
345
}
346
347
private Component title() {
348
return Component.translatable(translationKey);
349
}
350
351
private int color() {
352
return color;
353
}
354
}
355
356
private enum RowAction {
357
REQUEST("screen.mydimension.team.request"),
358
REVOKE("screen.mydimension.team.revoke");
359
360
private final String translationKey;
361
362
RowAction(String translationKey) {
363
this.translationKey = translationKey;
364
}
365
366
private String translationKey() {
367
return translationKey;
368
}
369
}
370
371
private record Layout(int left, int top, int right, int bottom, int width, int height) {
372
}
373
374
private class MindButton extends TeamButton {
375
private final MindType mindType;
376
377
private MindButton(int x, int y, int width, int height, MindType mindType, int animationOrder) {
378
super(x, y, width, height, mindType.displayName(), ENTRANCE_COLOR, () -> false, animationOrder,
379
button -> TeamMindScreen.this.selectMind(mindType));
380
this.mindType = mindType;
381
}
382
383
@Override
384
protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
385
super.renderWidget(graphics, mouseX, mouseY, partialTick);
386
int y = getY() + (getHeight() - 16) / 2;
387
graphics.blit(RIFT_ICON, getX() + 8, y, 0, 0, 16, 16, 16, 16);
388
}
389
390
}
391
392
private void selectMind(MindType mindType) {
393
if (selectedOwner == null || minecraft == null) {
394
return;
395
}
396
ModNetwork.CHANNEL.sendToServer(TeamMindCommandPacket.select(selectedOwner, mindType));
397
minecraft.setScreen(null);
398
}
399
400
private class TeamButton extends Button {
401
private final int color;
402
private final BooleanSupplier selected;
403
private final int animationOrder;
404
private float hoverProgress;
405
406
private TeamButton(int x, int y, int width, int height, Component message, int color,
407
BooleanSupplier selected, int animationOrder, OnPress onPress) {
408
super(x, y, width, height, message, onPress, DEFAULT_NARRATION);
409
this.color = color;
410
this.selected = selected;
411
this.animationOrder = animationOrder;
412
}
413
414
@Override
415
protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
416
hoverProgress = Mth.clamp(hoverProgress + (isHoveredOrFocused() ? 0.15F : -0.15F), 0.0F, 1.0F);
417
float progress = easeOut(Mth.clamp((Util.getMillis() - openedAt - animationOrder * 28L) / 220.0F, 0.0F, 1.0F));
418
int top = getY() + Math.round((1.0F - progress) * 7.0F);
419
int fillAlpha = active ? Math.round(Mth.lerp(hoverProgress, 150.0F, 220.0F)) : 75;
420
int edge = selected.getAsBoolean() ? 0xFFFFF4A8 : (active ? 0xFFB8F0FF : 0xFF6A747B);
421
422
fillRoundedRect(graphics, getX(), top, getX() + getWidth(), top + getHeight(), 6,
423
multiplyAlpha(withAlpha(color, fillAlpha), progress));
424
drawRoundedBorder(graphics, getX(), top, getX() + getWidth(), top + getHeight(), 6,
425
multiplyAlpha(edge, progress));
426
int textLeft = this instanceof MindButton ? getX() + 29 : getX();
427
int textWidth = this instanceof MindButton ? getWidth() - 34 : getWidth();
428
drawCenteredFittingText(graphics, Minecraft.getInstance().font, getMessage(), textLeft, top,
429
textWidth, getHeight(), multiplyAlpha(active ? 0xFFEAFBFF : 0xFF8A969C, progress));
430
}
431
}
432
433
private static void drawCenteredFittingText(GuiGraphics graphics, Font font, Component text,
434
int left, int top, int width, int height, int color) {
435
String label = font.plainSubstrByWidth(text.getString(), Math.max(4, width - 8));
436
graphics.drawCenteredString(font, label, left + width / 2, top + (height - 8) / 2, color);
437
}
438
}
@@ -33,7 +33,8 @@ public enum RiftAction {
33
33
COPY_SHARED_WATER("copy_shared_water", "action.mydimension.copy_shared_water", ModDimensions.WATER_MIND, false, false, true),
34
34
COPY_SHARED_NATURE("copy_shared_nature", "action.mydimension.copy_shared_nature", ModDimensions.NATURE_MIND, false, false, true),
35
35
COPY_SHARED_SOARING("copy_shared_soaring", "action.mydimension.copy_shared_soaring", ModDimensions.SOARING_MIND, false, false, true),
36
SET_ANCHOR("set_anchor", "action.mydimension.set_anchor", null, false, false, false);
36
SET_ANCHOR("set_anchor", "action.mydimension.set_anchor", null, false, false, false),
37
VISIT_TEAM_MIND("visit_team_mind", "action.mydimension.visit_team_mind", null, false, false, false);
37
38
38
39
private final String id;
39
40
private final String translationKey;