XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

MyDimension

【Java】我的维度模组

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/MyDimension

优化UI显示等多个修改

e3fe034
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

15 个文件 +429 -93
Modified build.gradle +1 -1
@@ -122,7 +122,7 @@ tasks.register('generatePlayerMindDimensions') {
122 122 ]
123 123 ]
124 124
125 (0..<32).each { slot ->
125 (0..<128).each { slot ->
126 126 dimensions.each { name, json ->
127 127 def file = new File(dimensionDir, "slot_${slot}/${name}.json")
128 128 file.parentFile.mkdirs()
Modified gradle.properties +1 -1
@@ -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=1.3.9
14 mod_version=2.0.0
15 15 mod_group_id=com.xfestudio.mydimension
16 16 maven_group=com.xfestudio
17 17 archives_base_name=mydimension
Modified src/main/java/com/xfestudio/mydimension/MyDimensionEvents.java +1 -1
@@ -235,7 +235,7 @@ public class MyDimensionEvents {
235 235 event.setCanceled(true);
236 236
237 237 if (!player.level().isClientSide()) {
238 RiftItem.sendToMind(player, target, stack, action.targetDimension());
238 RiftItem.sendToMind(player, target, stack, action);
239 239 }
240 240 }
241 241
Modified src/main/java/com/xfestudio/mydimension/client/RiftActionScreen.java +109 -54
@@ -17,18 +17,23 @@ import net.minecraft.resources.ResourceLocation;
17 17 import net.minecraft.util.Mth;
18 18 import net.minecraft.world.item.ItemStack;
19 19
20 import java.util.ArrayList;
21 import java.util.List;
22
20 23 public class RiftActionScreen extends Screen {
21 24 private static final int BUTTON_HEIGHT = 26;
22 private static final int BUTTON_GAP = 22;
23 private static final int ROW_GAP = 82;
25 private static final int BUTTON_GAP = 18;
24 26 private static final int TRAVEL_COLOR = 0xFF3E8DB8;
25 27 private static final int MOB_COLOR = 0xFF8B58C8;
26 28 private static final int ANCHOR_COLOR = 0xFFD6A23E;
29 private static final int COPY_COLOR = 0xFF4EBA7A;
27 30 private static final ResourceLocation RIFT_ICON = new ResourceLocation(MyDimension.MOD_ID, "textures/item/rift.png");
28 31 private static final ResourceLocation PORTAL_ICON = new ResourceLocation("minecraft", "textures/block/nether_portal.png");
29 32 private static final ResourceLocation ANCHOR_ICON = new ResourceLocation(MyDimension.MOD_ID, "textures/gui/rift_anchor_icon.png");
30 33
34 private Page page = Page.TRAVEL_PRIVATE;
31 35 private boolean inMindDimension;
36 private boolean creative;
32 37
33 38 public RiftActionScreen() {
34 39 super(Component.translatable("screen.mydimension.rift_actions"));
@@ -37,24 +42,14 @@ public class RiftActionScreen extends Screen {
37 42 @Override
38 43 protected void init() {
39 44 inMindDimension = minecraft != null && minecraft.player != null && ModDimensions.isMindDimension(minecraft.player.level().dimension());
45 creative = minecraft != null && minecraft.player != null && minecraft.player.isCreative();
40 46
41 RiftAction[] travelActions = new RiftAction[] {
42 RiftAction.ETHEREAL_MIND,
43 RiftAction.MIRROR_MIND,
44 RiftAction.WATER_MIND,
45 RiftAction.NATURE_MIND
46 };
47 addActionRow(travelActions, height / 2 - ROW_GAP);
48
47 int centerX = width / 2;
48 int centerY = height / 2;
49 addTabs(centerX, centerY - 108);
50 addActionGrid(currentActions(), centerY - 32);
49 51 if (inMindDimension) {
50 addCenteredActionButton(RiftAction.SET_ANCHOR, height / 2 + ROW_GAP - BUTTON_HEIGHT / 2);
51 } else {
52 addActionRow(new RiftAction[] {
53 RiftAction.SEND_MOB_ETHEREAL,
54 RiftAction.SEND_MOB_MIRROR,
55 RiftAction.SEND_MOB_WATER,
56 RiftAction.SEND_MOB_NATURE
57 }, height / 2 + ROW_GAP);
52 addCenteredActionButton(RiftAction.SET_ANCHOR, centerY + 78);
58 53 }
59 54 }
60 55
@@ -62,7 +57,6 @@ public class RiftActionScreen extends Screen {
62 57 public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
63 58 graphics.fillGradient(0, 0, width, height, 0xD0101218, 0xE0181026);
64 59 renderCenterPanel(graphics);
65 renderGuideLines(graphics);
66 60 super.render(graphics, mouseX, mouseY, partialTick);
67 61 }
68 62
@@ -71,53 +65,71 @@ public class RiftActionScreen extends Screen {
71 65 return false;
72 66 }
73 67
74 private void addActionRow(RiftAction[] actions, int centerY) {
75 int columns = actions.length;
76 int buttonWidth = rowButtonWidth(columns);
77 int totalWidth = columns * buttonWidth + (columns - 1) * BUTTON_GAP;
78 int x = width / 2 - totalWidth / 2;
79 int y = centerY - BUTTON_HEIGHT / 2;
68 private void addTabs(int centerX, int y) {
69 List<Page> pages = visiblePages();
70 int tabWidth = Math.max(68, Math.min(94, (width - 48 - (pages.size() - 1) * 8) / pages.size()));
71 int totalWidth = pages.size() * tabWidth + (pages.size() - 1) * 8;
72 int x = centerX - totalWidth / 2;
73 for (Page tab : pages) {
74 addRenderableWidget(new PageButton(x, y, tabWidth, tab));
75 x += tabWidth + 8;
76 }
77 }
80 78
81 for (RiftAction action : actions) {
82 addRenderableWidget(new ActionButton(x, y, buttonWidth, action, getSelectedAction() == action));
83 x += buttonWidth + BUTTON_GAP;
79 private List<Page> visiblePages() {
80 List<Page> pages = new ArrayList<>(List.of(Page.TRAVEL_PRIVATE, Page.TRAVEL_SHARED, Page.MOB_PRIVATE, Page.MOB_SHARED));
81 if (creative) {
82 pages.add(Page.COPY_SHARED);
83 } else if (page == Page.COPY_SHARED) {
84 page = Page.TRAVEL_PRIVATE;
85 }
86 return pages;
87 }
88
89 private RiftAction[] currentActions() {
90 return switch (page) {
91 case TRAVEL_PRIVATE -> new RiftAction[] {RiftAction.ETHEREAL_MIND, RiftAction.MIRROR_MIND, RiftAction.WATER_MIND, RiftAction.NATURE_MIND};
92 case TRAVEL_SHARED -> new RiftAction[] {RiftAction.SHARED_ETHEREAL_MIND, RiftAction.SHARED_MIRROR_MIND, RiftAction.SHARED_WATER_MIND, RiftAction.SHARED_NATURE_MIND};
93 case MOB_PRIVATE -> new RiftAction[] {RiftAction.SEND_MOB_ETHEREAL, RiftAction.SEND_MOB_MIRROR, RiftAction.SEND_MOB_WATER, RiftAction.SEND_MOB_NATURE};
94 case MOB_SHARED -> new RiftAction[] {RiftAction.SEND_MOB_SHARED_ETHEREAL, RiftAction.SEND_MOB_SHARED_MIRROR, RiftAction.SEND_MOB_SHARED_WATER, RiftAction.SEND_MOB_SHARED_NATURE};
95 case COPY_SHARED -> new RiftAction[] {RiftAction.COPY_SHARED_ETHEREAL, RiftAction.COPY_SHARED_MIRROR, RiftAction.COPY_SHARED_WATER, RiftAction.COPY_SHARED_NATURE};
96 };
97 }
98
99 private void addActionGrid(RiftAction[] actions, int top) {
100 int buttonWidth = rowButtonWidth(2);
101 int totalWidth = buttonWidth * 2 + BUTTON_GAP;
102 int left = width / 2 - totalWidth / 2;
103 for (int i = 0; i < actions.length; i++) {
104 int x = left + (i % 2) * (buttonWidth + BUTTON_GAP);
105 int y = top + (i / 2) * 42;
106 addRenderableWidget(new ActionButton(x, y, buttonWidth, actions[i], getSelectedAction() == actions[i]));
84 107 }
85 108 }
86 109
87 110 private void addCenteredActionButton(RiftAction action, int y) {
88 int buttonWidth = Mth.clamp(width / 4, 132, 176);
111 int buttonWidth = Mth.clamp(width / 4, 140, 190);
89 112 addRenderableWidget(new ActionButton(width / 2 - buttonWidth / 2, y, buttonWidth, action, getSelectedAction() == action));
90 113 }
91 114
92 115 private int rowButtonWidth(int columns) {
93 116 int available = Math.max(96, width - 64);
94 117 int maxByWidth = (available - (columns - 1) * BUTTON_GAP) / columns;
95 return Mth.clamp(maxByWidth, 92, 150);
118 return Mth.clamp(maxByWidth, 116, 178);
96 119 }
97 120
98 121 private void renderCenterPanel(GuiGraphics graphics) {
99 122 int centerX = width / 2;
100 123 int centerY = height / 2;
101 int left = centerX - 90;
102 int top = centerY - 37;
103 int right = centerX + 90;
104 int bottom = centerY + 37;
124 int left = centerX - 120;
125 int top = centerY - 72;
126 int right = centerX + 120;
127 int bottom = centerY + 64;
105 128
106 fillRoundedRect(graphics, left, top, right, bottom, 7, 0xB0060A12);
129 fillRoundedRect(graphics, left, top, right, bottom, 7, 0x99060A12);
107 130 drawRoundedBorder(graphics, left, top, right, bottom, 7, 0xFF85D6F7);
108 graphics.drawCenteredString(font, title, centerX, centerY - 25, 0xFFEAFBFF);
109
110 Component mode = Component.translatable(inMindDimension ? "screen.mydimension.rift_actions.mode_mind" : "screen.mydimension.rift_actions.mode_outside");
111 Component selected = Component.translatable("screen.mydimension.rift_actions.selected", getSelectedAction().displayName());
112 graphics.drawCenteredString(font, mode, centerX, centerY - 4, inMindDimension ? 0xFFFFE0A3 : 0xFFD0B6FF);
113 graphics.drawCenteredString(font, selected, centerX, centerY + 14, 0xFF9DDBFF);
114 }
115
116 private void renderGuideLines(GuiGraphics graphics) {
117 int centerX = width / 2;
118 int centerY = height / 2;
119 graphics.fill(centerX - 1, centerY - ROW_GAP + BUTTON_HEIGHT / 2 + 8, centerX + 1, centerY - 43, 0x4485D6F7);
120 graphics.fill(centerX - 1, centerY + 43, centerX + 1, centerY + ROW_GAP - BUTTON_HEIGHT / 2 - 8, inMindDimension ? 0x55FFE0A3 : 0x447F53B9);
131 graphics.drawCenteredString(font, title, centerX, centerY - 61, 0xFFEAFBFF);
132 graphics.drawCenteredString(font, page.title(), centerX, centerY + 43, page == Page.COPY_SHARED ? 0xFFB8FFD2 : 0xFF9DDBFF);
121 133 }
122 134
123 135 private RiftAction getSelectedAction() {
@@ -160,6 +172,44 @@ public class RiftActionScreen extends Screen {
160 172 graphics.fill(right - radius, bottom - 2, right - 1, bottom - 1, color);
161 173 }
162 174
175 private enum Page {
176 TRAVEL_PRIVATE("screen.mydimension.rift_actions.page.travel_private"),
177 TRAVEL_SHARED("screen.mydimension.rift_actions.page.travel_shared"),
178 MOB_PRIVATE("screen.mydimension.rift_actions.page.mob_private"),
179 MOB_SHARED("screen.mydimension.rift_actions.page.mob_shared"),
180 COPY_SHARED("screen.mydimension.rift_actions.page.copy_shared");
181
182 private final String translationKey;
183
184 Page(String translationKey) {
185 this.translationKey = translationKey;
186 }
187
188 private Component title() {
189 return Component.translatable(translationKey);
190 }
191 }
192
193 private class PageButton extends Button {
194 private final Page targetPage;
195
196 private PageButton(int x, int y, int width, Page targetPage) {
197 super(x, y, width, 20, targetPage.title(), button -> {
198 page = targetPage;
199 rebuildWidgets();
200 }, DEFAULT_NARRATION);
201 this.targetPage = targetPage;
202 }
203
204 @Override
205 protected void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
206 int fill = targetPage == page ? 0xD6D6A23E : (isHoveredOrFocused() ? 0xC83E8DB8 : 0x963E8DB8);
207 fillRoundedRect(graphics, getX(), getY(), getX() + getWidth(), getY() + getHeight(), 5, fill);
208 drawRoundedBorder(graphics, getX(), getY(), getX() + getWidth(), getY() + getHeight(), 5, targetPage == page ? 0xFFFFF4A8 : 0xFFB8F0FF);
209 drawCenteredFittingText(graphics, Minecraft.getInstance().font, getMessage(), getX(), getY(), getWidth(), getHeight(), 0xFFEAFBFF);
210 }
211 }
212
163 213 private class ActionButton extends Button {
164 214 private final RiftAction action;
165 215 private final boolean selected;
@@ -176,9 +226,9 @@ public class RiftActionScreen extends Screen {
176 226 int top = getY();
177 227 int right = left + getWidth();
178 228 int bottom = top + getHeight();
179 int base = action == RiftAction.SET_ANCHOR ? ANCHOR_COLOR : (action.sendsMob() ? MOB_COLOR : TRAVEL_COLOR);
229 int base = action == RiftAction.SET_ANCHOR ? ANCHOR_COLOR : (action.copiesSharedDimension() ? COPY_COLOR : (action.sendsMob() ? MOB_COLOR : TRAVEL_COLOR));
180 230 int fill = withAlpha(base, isHoveredOrFocused() ? 226 : 174);
181 int edge = selected ? 0xFFFFF4A8 : (action == RiftAction.SET_ANCHOR ? 0xFFFFE0A3 : (action.sendsMob() ? 0xFFD8C1FF : 0xFFB8F0FF));
231 int edge = selected ? 0xFFFFF4A8 : (action == RiftAction.SET_ANCHOR ? 0xFFFFE0A3 : (action.copiesSharedDimension() ? 0xFFB8FFD2 : (action.sendsMob() ? 0xFFD8C1FF : 0xFFB8F0FF)));
182 232
183 233 fillRoundedRect(graphics, left, top, right, bottom, 7, darken(fill));
184 234 fillRoundedRect(graphics, left + 1, top + 1, right - 1, bottom - 1, 6, fill);
@@ -213,10 +263,15 @@ public class RiftActionScreen extends Screen {
213 263 int blue = (int) ((color & 0xFF) * 0.58F);
214 264 return alpha | (red << 16) | (green << 8) | blue;
215 265 }
266 }
216 267
217 private void drawFittingText(GuiGraphics graphics, Font font, Component text, int left, int top, int width, int height, int color) {
218 String label = font.plainSubstrByWidth(text.getString(), width);
219 graphics.drawString(font, label, left, top + (height - 8) / 2, color);
220 }
268 private static void drawCenteredFittingText(GuiGraphics graphics, Font font, Component text, int left, int top, int width, int height, int color) {
269 String label = font.plainSubstrByWidth(text.getString(), width - 8);
270 graphics.drawCenteredString(font, label, left + width / 2, top + (height - 8) / 2, color);
271 }
272
273 private static void drawFittingText(GuiGraphics graphics, Font font, Component text, int left, int top, int width, int height, int color) {
274 String label = font.plainSubstrByWidth(text.getString(), width);
275 graphics.drawString(font, label, left, top + (height - 8) / 2, color);
221 276 }
222 277 }
Modified src/main/java/com/xfestudio/mydimension/item/RiftAction.java +35 -11
@@ -8,26 +8,42 @@ import net.minecraft.world.level.Level;
8 8 import java.util.Locale;
9 9
10 10 public enum RiftAction {
11 ETHEREAL_MIND("ethereal_mind", "action.mydimension.ethereal_mind", ModDimensions.ETHEREAL_MIND, false),
12 MIRROR_MIND("mirror_mind", "action.mydimension.mirror_mind", ModDimensions.MIRROR_MIND, false),
13 WATER_MIND("water_mind", "action.mydimension.water_mind", ModDimensions.WATER_MIND, false),
14 NATURE_MIND("nature_mind", "action.mydimension.nature_mind", ModDimensions.NATURE_MIND, false),
15 SEND_MOB_ETHEREAL("send_mob_ethereal", "action.mydimension.send_mob_ethereal", ModDimensions.ETHEREAL_MIND, true),
16 SEND_MOB_MIRROR("send_mob_mirror", "action.mydimension.send_mob_mirror", ModDimensions.MIRROR_MIND, true),
17 SEND_MOB_WATER("send_mob_water", "action.mydimension.send_mob_water", ModDimensions.WATER_MIND, true),
18 SEND_MOB_NATURE("send_mob_nature", "action.mydimension.send_mob_nature", ModDimensions.NATURE_MIND, true),
19 SET_ANCHOR("set_anchor", "action.mydimension.set_anchor", null, false);
11 ETHEREAL_MIND("ethereal_mind", "action.mydimension.ethereal_mind", ModDimensions.ETHEREAL_MIND, false, false, false),
12 MIRROR_MIND("mirror_mind", "action.mydimension.mirror_mind", ModDimensions.MIRROR_MIND, false, false, false),
13 WATER_MIND("water_mind", "action.mydimension.water_mind", ModDimensions.WATER_MIND, false, false, false),
14 NATURE_MIND("nature_mind", "action.mydimension.nature_mind", ModDimensions.NATURE_MIND, false, false, false),
15 SHARED_ETHEREAL_MIND("shared_ethereal_mind", "action.mydimension.shared_ethereal_mind", ModDimensions.ETHEREAL_MIND, false, true, false),
16 SHARED_MIRROR_MIND("shared_mirror_mind", "action.mydimension.shared_mirror_mind", ModDimensions.MIRROR_MIND, false, true, false),
17 SHARED_WATER_MIND("shared_water_mind", "action.mydimension.shared_water_mind", ModDimensions.WATER_MIND, false, true, false),
18 SHARED_NATURE_MIND("shared_nature_mind", "action.mydimension.shared_nature_mind", ModDimensions.NATURE_MIND, false, true, false),
19 SEND_MOB_ETHEREAL("send_mob_ethereal", "action.mydimension.send_mob_ethereal", ModDimensions.ETHEREAL_MIND, true, false, false),
20 SEND_MOB_MIRROR("send_mob_mirror", "action.mydimension.send_mob_mirror", ModDimensions.MIRROR_MIND, true, false, false),
21 SEND_MOB_WATER("send_mob_water", "action.mydimension.send_mob_water", ModDimensions.WATER_MIND, true, false, false),
22 SEND_MOB_NATURE("send_mob_nature", "action.mydimension.send_mob_nature", ModDimensions.NATURE_MIND, true, false, false),
23 SEND_MOB_SHARED_ETHEREAL("send_mob_shared_ethereal", "action.mydimension.send_mob_shared_ethereal", ModDimensions.ETHEREAL_MIND, true, true, false),
24 SEND_MOB_SHARED_MIRROR("send_mob_shared_mirror", "action.mydimension.send_mob_shared_mirror", ModDimensions.MIRROR_MIND, true, true, false),
25 SEND_MOB_SHARED_WATER("send_mob_shared_water", "action.mydimension.send_mob_shared_water", ModDimensions.WATER_MIND, true, true, false),
26 SEND_MOB_SHARED_NATURE("send_mob_shared_nature", "action.mydimension.send_mob_shared_nature", ModDimensions.NATURE_MIND, true, true, false),
27 COPY_SHARED_ETHEREAL("copy_shared_ethereal", "action.mydimension.copy_shared_ethereal", ModDimensions.ETHEREAL_MIND, false, false, true),
28 COPY_SHARED_MIRROR("copy_shared_mirror", "action.mydimension.copy_shared_mirror", ModDimensions.MIRROR_MIND, false, false, true),
29 COPY_SHARED_WATER("copy_shared_water", "action.mydimension.copy_shared_water", ModDimensions.WATER_MIND, false, false, true),
30 COPY_SHARED_NATURE("copy_shared_nature", "action.mydimension.copy_shared_nature", ModDimensions.NATURE_MIND, false, false, true),
31 SET_ANCHOR("set_anchor", "action.mydimension.set_anchor", null, false, false, false);
20 32
21 33 private final String id;
22 34 private final String translationKey;
23 35 private final ResourceKey<Level> targetDimension;
24 36 private final boolean sendsMob;
37 private final boolean sharedDimension;
38 private final boolean copiesSharedDimension;
25 39
26 RiftAction(String id, String translationKey, ResourceKey<Level> targetDimension, boolean sendsMob) {
40 RiftAction(String id, String translationKey, ResourceKey<Level> targetDimension, boolean sendsMob, boolean sharedDimension, boolean copiesSharedDimension) {
27 41 this.id = id;
28 42 this.translationKey = translationKey;
29 43 this.targetDimension = targetDimension;
30 44 this.sendsMob = sendsMob;
45 this.sharedDimension = sharedDimension;
46 this.copiesSharedDimension = copiesSharedDimension;
31 47 }
32 48
33 49 public String id() {
@@ -43,13 +59,21 @@ public enum RiftAction {
43 59 }
44 60
45 61 public boolean teleportsPlayer() {
46 return targetDimension != null && !sendsMob;
62 return targetDimension != null && !sendsMob && !copiesSharedDimension;
47 63 }
48 64
49 65 public boolean sendsMob() {
50 66 return sendsMob;
51 67 }
52 68
69 public boolean usesSharedDimension() {
70 return sharedDimension;
71 }
72
73 public boolean copiesSharedDimension() {
74 return copiesSharedDimension;
75 }
76
53 77 public static RiftAction byId(String id) {
54 78 if ("send_mob".equals(id)) {
55 79 return SEND_MOB_ETHEREAL;
Modified src/main/java/com/xfestudio/mydimension/item/RiftItem.java +108 -11
@@ -9,6 +9,7 @@ import net.minecraft.nbt.CompoundTag;
9 9 import net.minecraft.network.chat.Component;
10 10 import net.minecraft.resources.ResourceKey;
11 11 import net.minecraft.resources.ResourceLocation;
12 import net.minecraft.server.MinecraftServer;
12 13 import net.minecraft.server.level.ServerLevel;
13 14 import net.minecraft.server.level.ServerPlayer;
14 15 import net.minecraft.sounds.SoundEvents;
@@ -23,8 +24,10 @@ import net.minecraft.world.entity.projectile.ProjectileUtil;
23 24 import net.minecraft.world.item.Item;
24 25 import net.minecraft.world.item.ItemStack;
25 26 import net.minecraft.world.level.Level;
27 import net.minecraft.world.level.dimension.DimensionType;
26 28 import net.minecraft.world.level.levelgen.Heightmap;
27 29 import net.minecraft.world.level.portal.PortalInfo;
30 import net.minecraft.world.level.storage.LevelResource;
28 31 import net.minecraft.world.phys.AABB;
29 32 import net.minecraft.world.phys.EntityHitResult;
30 33 import net.minecraft.world.phys.Vec3;
@@ -32,6 +35,12 @@ import net.minecraftforge.api.distmarker.Dist;
32 35 import net.minecraftforge.common.util.ITeleporter;
33 36 import net.minecraftforge.fml.DistExecutor;
34 37
38 import java.io.IOException;
39 import java.nio.file.FileVisitResult;
40 import java.nio.file.Files;
41 import java.nio.file.Path;
42 import java.nio.file.SimpleFileVisitor;
43 import java.nio.file.attribute.BasicFileAttributes;
35 44 import java.util.function.Function;
36 45
37 46 public class RiftItem extends Item {
@@ -100,7 +109,7 @@ public class RiftItem extends Item {
100 109 }
101 110
102 111 if (player instanceof ServerPlayer serverPlayer) {
103 sendToMind(serverPlayer, target, stack, action.targetDimension());
112 sendToMind(serverPlayer, target, stack, action);
104 113 }
105 114
106 115 return InteractionResult.CONSUME;
@@ -126,26 +135,32 @@ public class RiftItem extends Item {
126 135 return;
127 136 }
128 137
138 if (action.copiesSharedDimension()) {
139 copySharedDimension(player, action);
140 return;
141 }
142
129 143 if (action.sendsMob()) {
130 144 LivingEntity target = findLookedAtLivingEntity(player);
131 if (target == null || !sendToMind(player, target, stack, action.targetDimension())) {
145 if (target == null || !sendToMind(player, target, stack, action)) {
132 146 player.displayClientMessage(Component.translatable("message.mydimension.no_mob_target"), true);
133 147 }
134 148 return;
135 149 }
136 150
137 teleport(player, stack, action.targetDimension());
151 teleport(player, stack, action);
138 152 }
139 153
140 private static void teleport(ServerPlayer player, ItemStack stack, ResourceKey<Level> selectedDimension) {
154 private static void teleport(ServerPlayer player, ItemStack stack, RiftAction action) {
155 ResourceKey<Level> selectedDimension = action.targetDimension();
141 156 ServerLevel currentLevel = player.serverLevel();
142 157 ResourceKey<Level> currentDimension = currentLevel.dimension();
143 158 ResourceKey<Level> currentMindBase = ModDimensions.baseMindDimension(currentDimension);
144 boolean returningFromSelectedMind = selectedDimension.equals(currentMindBase);
159 ResourceKey<Level> actualTargetDimension = action.usesSharedDimension() ? selectedDimension : MindInstances.dimensionFor(player, selectedDimension);
160 boolean returningFromSelectedMind = currentDimension.equals(actualTargetDimension) && selectedDimension.equals(currentMindBase);
145 161 ReturnPoint returnPoint = returningFromSelectedMind ? readPoint(stack, RETURN_POINT_TAG) : null;
146 ResourceKey<Level> targetDimension = returningFromSelectedMind ? null : MindInstances.dimensionFor(player, selectedDimension);
147 ReturnPoint mindPoint = returningFromSelectedMind ? null : readMindPoint(stack, targetDimension);
148 ServerLevel targetLevel = returningFromSelectedMind ? getReturnLevel(player, returnPoint) : player.getServer().getLevel(targetDimension);
162 ReturnPoint mindPoint = returningFromSelectedMind ? null : readMindPoint(stack, actualTargetDimension);
163 ServerLevel targetLevel = returningFromSelectedMind ? getReturnLevel(player, returnPoint) : player.getServer().getLevel(actualTargetDimension);
149 164
150 165 if (targetLevel == null) {
151 166 player.displayClientMessage(Component.translatable("message.mydimension.missing_dimension"), true);
@@ -154,7 +169,7 @@ public class RiftItem extends Item {
154 169
155 170 double x = player.getX();
156 171 double z = player.getZ();
157 double y = returningFromSelectedMind ? overworldSpawnY(targetLevel) : safeEntryY(targetLevel, targetDimension, x, z);
172 double y = returningFromSelectedMind ? overworldSpawnY(targetLevel) : safeEntryY(targetLevel, actualTargetDimension, x, z);
158 173 float yRot = player.getYRot();
159 174 float xRot = player.getXRot();
160 175
@@ -210,8 +225,9 @@ public class RiftItem extends Item {
210 225 return ModDimensions.entryHeight(dimension);
211 226 }
212 227
213 public static boolean sendToMind(ServerPlayer player, LivingEntity target, ItemStack stack, ResourceKey<Level> targetDimension) {
214 ResourceKey<Level> actualTargetDimension = MindInstances.dimensionFor(player, targetDimension);
228 public static boolean sendToMind(ServerPlayer player, LivingEntity target, ItemStack stack, RiftAction action) {
229 ResourceKey<Level> targetDimension = action.targetDimension();
230 ResourceKey<Level> actualTargetDimension = action.usesSharedDimension() ? targetDimension : MindInstances.dimensionFor(player, targetDimension);
215 231 ServerLevel targetLevel = player.getServer().getLevel(actualTargetDimension);
216 232 if (targetLevel == null) {
217 233 player.displayClientMessage(Component.translatable("message.mydimension.missing_dimension"), true);
@@ -243,6 +259,87 @@ public class RiftItem extends Item {
243 259 return false;
244 260 }
245 261
262 private static void copySharedDimension(ServerPlayer player, RiftAction action) {
263 if (!player.isCreative()) {
264 player.displayClientMessage(Component.translatable("message.mydimension.copy_creative_only"), true);
265 return;
266 }
267
268 ResourceKey<Level> sourceDimension = action.targetDimension();
269 ResourceKey<Level> targetDimension = MindInstances.dimensionFor(player, sourceDimension);
270 if (sourceDimension.equals(targetDimension)) {
271 player.displayClientMessage(Component.translatable("message.mydimension.copy_private_unavailable"), true);
272 return;
273 }
274
275 MinecraftServer server = player.getServer();
276 if (server == null || server.getLevel(sourceDimension) == null || server.getLevel(targetDimension) == null) {
277 player.displayClientMessage(Component.translatable("message.mydimension.missing_dimension"), true);
278 return;
279 }
280
281 try {
282 server.saveEverything(false, true, false);
283 Path worldRoot = server.getWorldPath(LevelResource.ROOT).normalize();
284 Path source = DimensionType.getStorageFolder(sourceDimension, worldRoot).normalize();
285 Path target = DimensionType.getStorageFolder(targetDimension, worldRoot).normalize();
286 if (!source.startsWith(worldRoot) || !target.startsWith(worldRoot) || source.equals(target)) {
287 player.displayClientMessage(Component.translatable("message.mydimension.copy_failed"), true);
288 return;
289 }
290
291 if (!Files.exists(source)) {
292 player.displayClientMessage(Component.translatable("message.mydimension.copy_missing_shared"), true);
293 return;
294 }
295
296 deleteDirectory(target);
297 copyDirectory(source, target);
298 player.displayClientMessage(Component.translatable("message.mydimension.copy_done"), true);
299 } catch (IOException exception) {
300 player.displayClientMessage(Component.translatable("message.mydimension.copy_failed"), true);
301 }
302 }
303
304 private static void deleteDirectory(Path path) throws IOException {
305 if (!Files.exists(path)) {
306 return;
307 }
308
309 Files.walkFileTree(path, new SimpleFileVisitor<>() {
310 @Override
311 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
312 Files.delete(file);
313 return FileVisitResult.CONTINUE;
314 }
315
316 @Override
317 public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
318 if (exc != null) {
319 throw exc;
320 }
321 Files.delete(dir);
322 return FileVisitResult.CONTINUE;
323 }
324 });
325 }
326
327 private static void copyDirectory(Path source, Path target) throws IOException {
328 Files.walkFileTree(source, new SimpleFileVisitor<>() {
329 @Override
330 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
331 Files.createDirectories(target.resolve(source.relativize(dir)));
332 return FileVisitResult.CONTINUE;
333 }
334
335 @Override
336 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
337 Files.copy(file, target.resolve(source.relativize(file)));
338 return FileVisitResult.CONTINUE;
339 }
340 });
341 }
342
246 343 private static LivingEntity findLookedAtLivingEntity(ServerPlayer player) {
247 344 double reach = 6.0D;
248 345 Vec3 eye = player.getEyePosition();
Modified src/main/java/com/xfestudio/mydimension/world/MindInstances.java +7 -2
@@ -12,13 +12,14 @@ import java.util.Map;
12 12 import java.util.UUID;
13 13
14 14 public class MindInstances {
15 public static final int MAX_PLAYER_SLOTS = 32;
15 public static final int MAX_PLAYER_SLOTS = 128;
16 16 private static final String DATA_NAME = "mydimension_mind_instances";
17 17 private static final String NEXT_SLOT_TAG = "NextSlot";
18 18 private static final String SLOTS_TAG = "Slots";
19 19
20 20 public static ResourceKey<Level> dimensionFor(ServerPlayer player, ResourceKey<Level> baseDimension) {
21 return ModDimensions.playerDimension(baseDimension, slotFor(player));
21 int slot = slotFor(player);
22 return slot < 0 ? baseDimension : ModDimensions.playerDimension(baseDimension, slot);
22 23 }
23 24
24 25 public static int slotFor(ServerPlayer player) {
@@ -63,6 +64,10 @@ public class MindInstances {
63 64 return existing;
64 65 }
65 66
67 if (nextSlot >= MAX_PLAYER_SLOTS) {
68 return -1;
69 }
70
66 71 int slot = nextSlot++;
67 72 slots.put(owner, slot);
68 73 setDirty();
Modified src/main/resources/assets/mydimension/lang/en_us.json +29 -4
@@ -5,22 +5,47 @@
5 5 "dimension.mydimension.water_mind": "Water Mind",
6 6 "dimension.mydimension.nature_mind": "Nature Mind",
7 7 "screen.mydimension.rift_actions": "Rift",
8 "screen.mydimension.rift_actions.travel": "Inner: Travel",
9 "screen.mydimension.rift_actions.mob": "Outer: Send Mob",
10 "screen.mydimension.rift_actions.anchor": "Center: Set Anchor",
8 "screen.mydimension.rift_actions.travel": "Travel",
9 "screen.mydimension.rift_actions.mob": "Send Mob",
10 "screen.mydimension.rift_actions.anchor": "Set Anchor",
11 "screen.mydimension.rift_actions.mode_mind": "Mind: Travel or Set Anchor",
12 "screen.mydimension.rift_actions.mode_outside": "Outside: Travel or Send Mob",
13 "screen.mydimension.rift_actions.selected": "Selected: %s",
14 "screen.mydimension.rift_actions.page.travel_private": "Travel",
15 "screen.mydimension.rift_actions.page.travel_shared": "Shared",
16 "screen.mydimension.rift_actions.page.mob_private": "Send",
17 "screen.mydimension.rift_actions.page.mob_shared": "Send Shared",
18 "screen.mydimension.rift_actions.page.copy_shared": "Copy Shared",
11 19 "action.mydimension.ethereal_mind": "Go to Ethereal Mind",
12 20 "action.mydimension.mirror_mind": "Go to Mirror Mind",
13 21 "action.mydimension.water_mind": "Go to Water Mind",
14 22 "action.mydimension.nature_mind": "Go to Nature Mind",
23 "action.mydimension.shared_ethereal_mind": "Go to Shared Ethereal",
24 "action.mydimension.shared_mirror_mind": "Go to Shared Mirror",
25 "action.mydimension.shared_water_mind": "Go to Shared Water",
26 "action.mydimension.shared_nature_mind": "Go to Shared Nature",
15 27 "action.mydimension.send_mob_ethereal": "Send Mob to Ethereal",
16 28 "action.mydimension.send_mob_mirror": "Send Mob to Mirror",
17 29 "action.mydimension.send_mob_water": "Send Mob to Water",
18 30 "action.mydimension.send_mob_nature": "Send Mob to Nature",
31 "action.mydimension.send_mob_shared_ethereal": "Send Mob to Shared Ethereal",
32 "action.mydimension.send_mob_shared_mirror": "Send Mob to Shared Mirror",
33 "action.mydimension.send_mob_shared_water": "Send Mob to Shared Water",
34 "action.mydimension.send_mob_shared_nature": "Send Mob to Shared Nature",
35 "action.mydimension.copy_shared_ethereal": "Copy Shared Ethereal",
36 "action.mydimension.copy_shared_mirror": "Copy Shared Mirror",
37 "action.mydimension.copy_shared_water": "Copy Shared Water",
38 "action.mydimension.copy_shared_nature": "Copy Shared Nature",
19 39 "action.mydimension.set_anchor": "Set Teleport Anchor",
20 40 "message.mydimension.already_in_target_mind": "That mob is already in the target mind dimension",
21 41 "message.mydimension.anchor_only_mind": "Teleport anchors can only be set in mind dimensions",
22 42 "message.mydimension.anchor_set": "Teleport anchor set for this mind dimension",
23 43 "message.mydimension.no_mob_target": "No mob target selected",
24 44 "message.mydimension.missing_dimension": "The target mind dimension is not loaded",
25 "message.mydimension.protected_tp": "%s is in a mind dimension and cannot be teleported by another player"
45 "message.mydimension.protected_tp": "%s is in a mind dimension and cannot be teleported by another player",
46 "message.mydimension.copy_creative_only": "Only creative players can copy shared mind saves",
47 "message.mydimension.copy_private_unavailable": "No private mind slot is available, so the shared save cannot be copied",
48 "message.mydimension.copy_missing_shared": "The shared mind has no saved world data to copy yet",
49 "message.mydimension.copy_done": "Copied the shared mind save to your private mind",
50 "message.mydimension.copy_failed": "Failed to copy shared mind save"
26 51 }
Modified src/main/resources/assets/mydimension/lang/zh_cn.json +22 -0
@@ -11,14 +11,31 @@
11 11 "screen.mydimension.rift_actions.mode_mind": "心境内:前往或设置锚点",
12 12 "screen.mydimension.rift_actions.mode_outside": "外界:前往或传送生物",
13 13 "screen.mydimension.rift_actions.selected": "当前:%s",
14 "screen.mydimension.rift_actions.page.travel_private": "前往",
15 "screen.mydimension.rift_actions.page.travel_shared": "前往共享",
16 "screen.mydimension.rift_actions.page.mob_private": "传送",
17 "screen.mydimension.rift_actions.page.mob_shared": "传送共享",
18 "screen.mydimension.rift_actions.page.copy_shared": "复制公共",
14 19 "action.mydimension.ethereal_mind": "前往空灵心境",
15 20 "action.mydimension.mirror_mind": "前往镜之心境",
16 21 "action.mydimension.water_mind": "前往水之心境",
17 22 "action.mydimension.nature_mind": "前往自然心境",
23 "action.mydimension.shared_ethereal_mind": "前往共享空灵",
24 "action.mydimension.shared_mirror_mind": "前往共享镜",
25 "action.mydimension.shared_water_mind": "前往共享水",
26 "action.mydimension.shared_nature_mind": "前往共享自然",
18 27 "action.mydimension.send_mob_ethereal": "传送生物到空灵",
19 28 "action.mydimension.send_mob_mirror": "传送生物到镜",
20 29 "action.mydimension.send_mob_water": "传送生物到水",
21 30 "action.mydimension.send_mob_nature": "传送生物到自然",
31 "action.mydimension.send_mob_shared_ethereal": "传送生物到共享空灵",
32 "action.mydimension.send_mob_shared_mirror": "传送生物到共享镜",
33 "action.mydimension.send_mob_shared_water": "传送生物到共享水",
34 "action.mydimension.send_mob_shared_nature": "传送生物到共享自然",
35 "action.mydimension.copy_shared_ethereal": "复制公共空灵",
36 "action.mydimension.copy_shared_mirror": "复制公共镜",
37 "action.mydimension.copy_shared_water": "复制公共水",
38 "action.mydimension.copy_shared_nature": "复制公共自然",
22 39 "action.mydimension.set_anchor": "设置传送锚点",
23 40 "message.mydimension.already_in_target_mind": "该生物已经在目标心境中",
24 41 "message.mydimension.anchor_only_mind": "只能在心境维度中设置传送锚点",
@@ -26,5 +43,10 @@
26 43 "message.mydimension.no_mob_target": "没有瞄准可传送的生物",
27 44 "message.mydimension.missing_dimension": "目标心境维度未加载",
28 45 "message.mydimension.protected_tp": "%s 正处于心境维度,无法被其他玩家传送",
46 "message.mydimension.copy_creative_only": "只有创造模式玩家可以复制公共心境存档",
47 "message.mydimension.copy_private_unavailable": "私有心境槽位不足,无法复制公共存档",
48 "message.mydimension.copy_missing_shared": "公共心境尚未生成存档,无法复制",
49 "message.mydimension.copy_done": "已复制公共心境存档到你的私有心境",
50 "message.mydimension.copy_failed": "复制公共心境存档失败",
29 51 "itemGroup.mydimension": "我的维度"
30 52 }
Modified src/main/resources/data/mydimension/advancements/recipes/misc/rift.json +16 -3
@@ -1,13 +1,25 @@
1 1 {
2 2 "parent": "minecraft:recipes/root",
3 3 "criteria": {
4 "has_black_glazed_terracotta": {
4 "has_clock": {
5 5 "trigger": "minecraft:inventory_changed",
6 6 "conditions": {
7 7 "items": [
8 8 {
9 9 "items": [
10 "minecraft:black_glazed_terracotta"
10 "minecraft:clock"
11 ]
12 }
13 ]
14 }
15 },
16 "has_ender_pearl": {
17 "trigger": "minecraft:inventory_changed",
18 "conditions": {
19 "items": [
20 {
21 "items": [
22 "minecraft:ender_pearl"
11 23 ]
12 24 }
13 25 ]
@@ -22,7 +34,8 @@
22 34 },
23 35 "requirements": [
24 36 [
25 "has_black_glazed_terracotta",
37 "has_clock",
38 "has_ender_pearl",
26 39 "has_the_recipe"
27 40 ]
28 41 ],
Added src/main/resources/data/mydimension/dimension/ethereal_mind.json +26 -0
@@ -0,0 +1,26 @@
1 {
2 "type": "mydimension:ethereal_mind",
3 "generator": {
4 "type": "minecraft:flat",
5 "settings": {
6 "biome": "mydimension:ethereal_mind",
7 "features": false,
8 "lakes": false,
9 "layers": [
10 {
11 "block": "minecraft:stone",
12 "height": 60
13 },
14 {
15 "block": "minecraft:dirt",
16 "height": 3
17 },
18 {
19 "block": "minecraft:quartz_block",
20 "height": 3
21 }
22 ],
23 "structure_overrides": []
24 }
25 }
26 }
Added src/main/resources/data/mydimension/dimension/mirror_mind.json +11 -0
@@ -0,0 +1,11 @@
1 {
2 "type": "mydimension:mirror_mind",
3 "generator": {
4 "type": "mydimension:no_structure_noise",
5 "biome_source": {
6 "type": "minecraft:multi_noise",
7 "preset": "minecraft:overworld"
8 },
9 "settings": "minecraft:overworld"
10 }
11 }
Added src/main/resources/data/mydimension/dimension/nature_mind.json +26 -0
Added src/main/resources/data/mydimension/dimension/water_mind.json +26 -0
Modified src/main/resources/data/mydimension/recipes/rift.json +11 -5