puter
This commit is contained in:
1 parent
3300fa8f2a
commit
c1d60d735d
39 files changed
+1080
-121
No files matched your search
@@ -144,6 +144,7 @@ public final class AntarchyConfigCatalog {
|
||||
|| name.equals("swingThroughGrassEnabled")
|
||||
|| name.equals("fabricKeybindingConflictFixEnabled")
|
||||
|| name.equals("experimentalSettingsPopupDisabled")
|
||||
|| name.equals("unlockAllArchives")
|
||||
|| name.equals("entitySpecificFireOverlayEnabled")
|
||||
|| name.equals("dreamSandEnabled")
|
||||
|| name.startsWith("dreamSand")
|
||||
|
||||
@@ -24,6 +24,7 @@ public final class AntarchySettings {
|
||||
private static boolean swingThroughGrassEnabled = true;
|
||||
private static boolean fabricKeybindingConflictFixEnabled = true;
|
||||
private static boolean experimentalSettingsPopupDisabled = true;
|
||||
private static boolean unlockAllArchives = true;
|
||||
private static boolean sizeChangingRaysEnabled = true;
|
||||
private static double sizeRayMinScale = 0.1D;
|
||||
private static double sizeRayMaxScale = 10.0D;
|
||||
@@ -696,6 +697,10 @@ public final class AntarchySettings {
|
||||
return experimentalSettingsPopupDisabled;
|
||||
}
|
||||
|
||||
public static boolean unlockAllArchives() {
|
||||
return unlockAllArchives;
|
||||
}
|
||||
|
||||
public static boolean sizeChangingRaysEnabled() {
|
||||
return sizeChangingRaysEnabled;
|
||||
}
|
||||
@@ -1315,6 +1320,10 @@ public final class AntarchySettings {
|
||||
experimentalSettingsPopupDisabled = value;
|
||||
}
|
||||
|
||||
public static void setUnlockAllArchives(boolean value) {
|
||||
unlockAllArchives = value;
|
||||
}
|
||||
|
||||
public static void setSizeChangingRaysEnabled(boolean value) {
|
||||
sizeChangingRaysEnabled = value;
|
||||
}
|
||||
|
||||
+8
@@ -4,6 +4,7 @@ import com.craisinlord.antarchy.content.AntarchyObjects;
|
||||
import com.craisinlord.antarchy.content.block.ComputerBlock;
|
||||
import com.craisinlord.antarchy.content.computer.ComputerFileSystem;
|
||||
import com.craisinlord.antarchy.content.computer.ComputerDesktopState;
|
||||
import com.craisinlord.antarchy.content.guide.ComputerGuideData;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@@ -92,6 +93,13 @@ public final class ComputerBlockEntity extends BlockEntity implements GeoBlockEn
|
||||
return true;
|
||||
}
|
||||
this.physicalDiskIds.add(diskId);
|
||||
ComputerGuideData.Disk disk = ComputerGuideData.disk(diskId);
|
||||
if (disk != null && !disk.wallpaper().isBlank()) {
|
||||
try {
|
||||
desktopState.unlockWallpaper(ResourceLocation.parse(disk.wallpaper()));
|
||||
} catch (RuntimeException ignored) {
|
||||
}
|
||||
}
|
||||
stack.shrink(1);
|
||||
activate();
|
||||
setChanged();
|
||||
|
||||
+16
-7
@@ -28,15 +28,24 @@ public final class ComputerFileSystemClientState {
|
||||
State state = STATES.computeIfAbsent(payload.pos(), ignored -> new State());
|
||||
state.success = payload.result() == ComputerAccessResultPayload.SUCCESS;
|
||||
state.error = envelope[1];
|
||||
if (action == ComputerAccessPayload.FILE_LIST && state.success) {
|
||||
if (state.success) state.error = "";
|
||||
if (action == ComputerAccessPayload.FILE_LIST) {
|
||||
state.files = new ArrayList<>();
|
||||
if (!envelope[2].isEmpty()) state.files.addAll(List.of(envelope[2].split("\\n")));
|
||||
} else if (action == ComputerAccessPayload.FILE_OPEN && state.success) {
|
||||
String[] file = envelope[2].split("\u0000", 2);
|
||||
if (file.length == 2) {
|
||||
state.openedPath = file[0];
|
||||
state.openedContents = file[1];
|
||||
if (state.success && !envelope[2].isEmpty()) state.files.addAll(List.of(envelope[2].split("\\n")));
|
||||
} else if (action == ComputerAccessPayload.FILE_OPEN) {
|
||||
if (state.success) {
|
||||
String[] file = envelope[2].split("\u0000", 2);
|
||||
if (file.length == 2) {
|
||||
state.openedPath = file[0];
|
||||
state.openedContents = file[1];
|
||||
}
|
||||
} else {
|
||||
state.openedPath = "";
|
||||
state.openedContents = "";
|
||||
}
|
||||
} else if ((action == ComputerAccessPayload.FILE_DELETE || action == ComputerAccessPayload.FILE_MOVE) && state.success) {
|
||||
state.openedPath = "";
|
||||
state.openedContents = "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -309,9 +309,9 @@ public class RoyalBossRenderer extends GeoEntityRenderer<RoyalBossEntity> {
|
||||
private static void drawModelPlane(VertexConsumer vertices, org.joml.Matrix4f pose,
|
||||
int x, int y, int z, int width, int height, int u, int v) {
|
||||
emitQuadUv(vertices, pose,
|
||||
new Vec3(x, y, z), new Vec3(x + width, y, z),
|
||||
new Vec3(x + width, y + height, z), new Vec3(x, y + height, z),
|
||||
u / 128.0F, v / 128.0F, (u + width) / 128.0F, (v + height) / 128.0F);
|
||||
new Vec3(x + width, y, z), new Vec3(x, y, z),
|
||||
new Vec3(x, y + height, z), new Vec3(x + width, y + height, z),
|
||||
(u + width) / 128.0F, v / 128.0F, u / 128.0F, (v + height) / 128.0F);
|
||||
}
|
||||
|
||||
private static void emitQuadUv(VertexConsumer vertices, org.joml.Matrix4f pose,
|
||||
|
||||
+491
-99
@@ -31,6 +31,10 @@ import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.client.gui.screens.inventory.InventoryScreen;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -108,6 +112,19 @@ public final class ComputerScreen extends Screen {
|
||||
}
|
||||
}
|
||||
}
|
||||
AntmailResultPayload mailResult = AntmailClientState.get(position);
|
||||
if (session.antmailRegistrationPending && mailResult != null) {
|
||||
String expectedAddress = session.antmailUsername + "@antmail.com";
|
||||
if (mailResult.address().equalsIgnoreCase(expectedAddress)) {
|
||||
session.antmailStatus = "ADDRESS REGISTERED";
|
||||
session.antmailRegistrationPending = false;
|
||||
AntmailNetworking.requestState(position);
|
||||
} else if (mailResult.detail().startsWith("registration_failed:")) {
|
||||
String reason = mailResult.detail().substring("registration_failed:".length()).trim();
|
||||
session.antmailStatus = "ADDRESS REGISTRATION FAILED // " + (reason.isBlank() ? "SERVER REJECTED" : reason.toUpperCase());
|
||||
session.antmailRegistrationPending = false;
|
||||
}
|
||||
}
|
||||
if (!loggedIn && accessResult != null && accessResult.authenticated()) {
|
||||
loggedIn = true;
|
||||
session.authenticated = true;
|
||||
@@ -134,6 +151,24 @@ public final class ComputerScreen extends Screen {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentResult != null && currentResult.data().startsWith("15\u0000") && !currentResult.data().equals(session.terminalResponse)) {
|
||||
session.terminalResponse = currentResult.data();
|
||||
try {
|
||||
var terminal = AntmailWire.decodeTag(currentResult.data().substring(3));
|
||||
session.terminalDirectory = terminal.getString("Directory");
|
||||
if (terminal.getBoolean("Clear")) session.terminalOutput.clear();
|
||||
var lines = terminal.getList("Lines", 8);
|
||||
for (int index = 0; index < lines.size(); index++) session.terminalOutput.add(lines.getString(index));
|
||||
String openPath = terminal.getString("Open");
|
||||
if (!openPath.isBlank()) {
|
||||
ComputerNetworking.openFile(position, openPath);
|
||||
open(openPath.endsWith(".antpaint") ? "PAINT" : "TEXT");
|
||||
}
|
||||
while (session.terminalOutput.size() > 40) session.terminalOutput.remove(0);
|
||||
} catch (RuntimeException ignored) {
|
||||
session.terminalOutput.add("ERROR: CORRUPTED SERVER RESPONSE");
|
||||
}
|
||||
}
|
||||
antFarm.setGameInstalled(physicalDisks().stream().anyMatch(id -> id.getPath().equals("ant_farm")));
|
||||
if (activeWindow != null && activeWindow.type.equals("GAMES") && activeWindow.gameOpen) antFarm.tick();
|
||||
}
|
||||
@@ -192,9 +227,11 @@ public final class ComputerScreen extends Screen {
|
||||
|
||||
private void renderDesktop(GuiGraphics g, int l, int t, int mouseX, int mouseY) {
|
||||
session.lastUse = System.currentTimeMillis();
|
||||
if (session.wallpaperId.endsWith("grid_ant")) {
|
||||
for (int py = t + 36; py < t + HEIGHT - 8; py += 18) for (int px = l + 8; px < l + WIDTH - 8; px += 36) g.fill(px, py, px + 2, py + 2, 0xFF173817);
|
||||
}
|
||||
session.mouseX = mouseX;
|
||||
session.mouseY = mouseY;
|
||||
session.archiveMouseX = mouseX;
|
||||
session.archiveMouseY = mouseY;
|
||||
renderWallpaper(g, l, t);
|
||||
g.fill(l + 9, t + 9, l + WIDTH - 9, t + 30, BLACK);
|
||||
g.drawString(font, Component.literal("ANTINTOSH OS // v" + Antarchy.MOD_VERSION), l + 18, t + 15, GREEN, false);
|
||||
long dayTime = Minecraft.getInstance().level == null ? 0L : Minecraft.getInstance().level.getDayTime();
|
||||
@@ -222,19 +259,133 @@ public final class ComputerScreen extends Screen {
|
||||
for (Window window : session.windows) if (!window.minimized) renderWindow(g, window, l, t, mouseX, mouseY);
|
||||
}
|
||||
|
||||
private void renderWallpaper(GuiGraphics g, int l, int t) {
|
||||
int left = l + 9;
|
||||
int top = t + 34;
|
||||
int right = l + WIDTH - 9;
|
||||
int bottom = t + HEIGHT - 8;
|
||||
String wallpaperId = ComputerDesktopState.DEFAULT_WALLPAPER.toString();
|
||||
int hash = wallpaperId.hashCode();
|
||||
int green = 24 + Math.floorMod(hash, 40);
|
||||
int blue = 12 + Math.floorMod(hash >>> 8, 24);
|
||||
int base = 0xFF000000 | (green / 2 << 16) | (green << 8) | blue;
|
||||
g.fill(left, top, right, bottom, base);
|
||||
if (wallpaperId.endsWith("grid_ant")) {
|
||||
for (int py = top + 2; py < bottom; py += 18) {
|
||||
for (int px = left + 2; px < right; px += 36) {
|
||||
g.fill(px, py, px + 2, py + 2, 0xFF173817);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
int accent = 0xFF000000 | (Math.min(120, green + 34) << 8) | Math.min(80, blue + 34);
|
||||
int spacing = 18 + Math.floorMod(hash, 13);
|
||||
int offset = Math.floorMod(hash >>> 16, spacing);
|
||||
for (int y = top - spacing; y < bottom + spacing; y += spacing) {
|
||||
int x = left - spacing + offset;
|
||||
while (x < right) {
|
||||
int size = 3 + Math.floorMod(x + y + hash, 7);
|
||||
g.fill(x, y, Math.min(right, x + size), Math.min(bottom, y + 2), accent);
|
||||
x += spacing * 2;
|
||||
}
|
||||
offset = spacing - offset;
|
||||
}
|
||||
}
|
||||
|
||||
private String wallpaperName() {
|
||||
int separator = session.wallpaperId.indexOf(':');
|
||||
String name = separator >= 0 ? session.wallpaperId.substring(separator + 1) : session.wallpaperId;
|
||||
return name.toUpperCase();
|
||||
}
|
||||
|
||||
private void icon(GuiGraphics g, String type, int x, int y) {
|
||||
if (type.equals("ARCHIVE") || type.equals("DISK")) {
|
||||
g.fill(x - 11, y - 2, x + 11, y + 19, BLACK);
|
||||
g.fill(x - 8, y + 1, x + 8, y + 16, GREEN);
|
||||
g.fill(x - 5, y + 3, x + 5, y + 8, BLACK);
|
||||
g.fill(x - 4, y + 12, x + 4, y + 16, BLACK);
|
||||
return;
|
||||
}
|
||||
if (type.equals("FILES")) {
|
||||
g.fill(x - 12, y + 2, x + 11, y + 19, BLACK);
|
||||
g.fill(x - 9, y, x + 1, y + 4, BLACK);
|
||||
g.fill(x - 8, y + 3, x + 9, y + 16, GREEN);
|
||||
g.fill(x - 9, y + 8, x + 9, y + 16, GREEN);
|
||||
g.fill(x - 6, y + 2, x - 1, y + 4, GREEN);
|
||||
return;
|
||||
}
|
||||
if (type.equals("SETTINGS")) {
|
||||
g.fill(x - 5, y - 3, x + 5, y + 20, BLACK);
|
||||
g.fill(x - 12, y + 5, x + 12, y + 13, BLACK);
|
||||
g.fill(x - 9, y, x + 9, y + 18, BLACK);
|
||||
g.fill(x - 2, y, x + 2, y + 17, GREEN);
|
||||
g.fill(x - 9, y + 7, x + 9, y + 11, GREEN);
|
||||
g.fill(x - 3, y + 5, x + 3, y + 13, BLACK);
|
||||
return;
|
||||
}
|
||||
if (type.equals("TERMINAL")) {
|
||||
g.fill(x - 12, y - 1, x + 12, y + 18, BLACK);
|
||||
g.fill(x - 9, y + 2, x + 9, y + 15, GREEN);
|
||||
g.fill(x - 6, y + 6, x - 2, y + 9, BLACK);
|
||||
g.fill(x - 2, y + 9, x + 4, y + 12, BLACK);
|
||||
return;
|
||||
}
|
||||
if (type.equals("TEXT")) {
|
||||
g.fill(x - 9, y - 2, x + 10, y + 20, BLACK);
|
||||
g.fill(x - 6, y + 1, x + 7, y + 17, GREEN);
|
||||
g.fill(x + 5, y + 1, x + 7, y + 4, BLACK);
|
||||
g.fill(x - 3, y + 5, x + 5, y + 7, BLACK);
|
||||
g.fill(x - 3, y + 9, x + 5, y + 11, BLACK);
|
||||
g.fill(x - 3, y + 13, x + 3, y + 15, BLACK);
|
||||
return;
|
||||
}
|
||||
if (type.equals("PAINT")) {
|
||||
// Palette with a separate brush, using a stepped silhouette to keep the icon readable at desktop scale.
|
||||
g.fill(x - 10, y + 2, x + 8, y + 19, BLACK);
|
||||
g.fill(x - 7, y + 4, x + 6, y + 16, GREEN);
|
||||
g.fill(x - 4, y + 6, x - 1, y + 9, BLACK);
|
||||
g.fill(x + 1, y + 5, x + 4, y + 8, BLACK);
|
||||
g.fill(x + 2, y + 11, x + 5, y + 14, BLACK);
|
||||
g.fill(x + 8, y - 3, x + 11, y + 10, BLACK);
|
||||
g.fill(x + 5, y + 6, x + 9, y + 9, BLACK);
|
||||
g.fill(x + 8, y - 1, x + 10, y + 7, PALE_GREEN);
|
||||
g.fill(x + 5, y + 7, x + 8, y + 10, PALE_GREEN);
|
||||
return;
|
||||
}
|
||||
if (type.equals("ANTMAIL")) {
|
||||
g.fill(x - 12, y + 2, x + 12, y + 17, BLACK);
|
||||
g.fill(x - 9, y + 5, x + 9, y + 14, GREEN);
|
||||
// Sealed envelope: the stepped black V is the closed flap.
|
||||
g.fill(x - 8, y + 5, x - 5, y + 7, BLACK);
|
||||
g.fill(x - 6, y + 7, x - 3, y + 9, BLACK);
|
||||
g.fill(x - 4, y + 9, x - 1, y + 11, BLACK);
|
||||
g.fill(x - 1, y + 11, x + 2, y + 13, BLACK);
|
||||
g.fill(x + 1, y + 9, x + 4, y + 11, BLACK);
|
||||
g.fill(x + 3, y + 7, x + 6, y + 9, BLACK);
|
||||
g.fill(x + 5, y + 5, x + 8, y + 7, BLACK);
|
||||
return;
|
||||
}
|
||||
if (type.equals("GAMES")) {
|
||||
g.fill(x - 12, y + 6, x + 12, y + 15, BLACK);
|
||||
g.fill(x - 9, y + 3, x + 9, y + 18, BLACK);
|
||||
g.fill(x - 8, y + 6, x + 8, y + 15, GREEN);
|
||||
g.fill(x - 5, y + 8, x + 1, y + 10, BLACK);
|
||||
g.fill(x - 3, y + 6, x - 1, y + 12, BLACK);
|
||||
g.fill(x + 4, y + 7, x + 6, y + 9, BLACK);
|
||||
g.fill(x + 7, y + 10, x + 9, y + 12, BLACK);
|
||||
return;
|
||||
}
|
||||
if (type.equals("TRASH")) {
|
||||
g.fill(x - 9, y + 2, x + 9, y + 5, BLACK);
|
||||
g.fill(x - 8, y + 5, x + 8, y + 19, BLACK);
|
||||
g.fill(x - 5, y + 7, x + 5, y + 16, GREEN);
|
||||
g.fill(x - 6, y + 3, x + 6, y + 4, GREEN);
|
||||
g.fill(x - 5, y - 1, x + 5, y + 2, BLACK);
|
||||
g.fill(x - 3, y, x + 3, y + 1, GREEN);
|
||||
return;
|
||||
}
|
||||
g.fill(x - 10, y, x + 10, y + 18, BLACK);
|
||||
g.fill(x - 8, y + 2, x + 8, y + 16, GREEN);
|
||||
if (type.equals("SETTINGS")) {
|
||||
g.fill(x - 12, y + 7, x + 12, y + 11, BLACK);
|
||||
g.fill(x - 2, y - 2, x + 2, y + 20, BLACK);
|
||||
} else if (type.equals("TRASH")) {
|
||||
g.fill(x - 12, y - 3, x + 12, y, GREEN);
|
||||
g.fill(x - 7, y + 4, x + 7, y + 18, BLACK);
|
||||
} else if (type.equals("TERMINAL")) {
|
||||
g.fill(x - 5, y + 7, x - 1, y + 11, BLACK);
|
||||
g.fill(x - 1, y + 11, x + 6, y + 14, BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderWindow(GuiGraphics g, Window window, int l, int t, int mouseX, int mouseY) {
|
||||
@@ -254,12 +405,12 @@ public final class ComputerScreen extends Screen {
|
||||
int cx = x + 8;
|
||||
int cy = y + 28;
|
||||
if (window.type.equals("ARCHIVE")) renderArchive(g, cx, cy, w - 16, h - 34);
|
||||
else if (window.type.equals("FILES")) renderFileExplorer(g, cx, cy, w, h);
|
||||
else if (window.type.equals("FILES")) renderFileExplorer(g, cx, cy, w - 16, h - 34);
|
||||
else if (window.type.equals("SETTINGS")) renderSettings(g, cx, cy, h - 34);
|
||||
else if (window.type.equals("TERMINAL")) renderTerminal(g, cx, cy, h);
|
||||
else if (window.type.equals("TEXT")) renderTextEditor(g, cx, cy, w, h);
|
||||
else if (window.type.equals("PAINT")) renderPaint(g, cx, cy, w, h);
|
||||
else if (window.type.equals("ANTMAIL")) renderAntmail(g, cx, cy, h);
|
||||
else if (window.type.equals("TERMINAL")) renderTerminal(g, cx, cy, h - 34);
|
||||
else if (window.type.equals("TEXT")) renderTextEditor(g, cx, cy, w - 16, h - 34);
|
||||
else if (window.type.equals("PAINT")) renderPaint(g, cx, cy, w - 16, h - 34);
|
||||
else if (window.type.equals("ANTMAIL")) renderAntmail(g, cx, cy, h - 34);
|
||||
else if (window.type.equals("GAMES")) renderGames(g, cx, cy);
|
||||
else renderTrash(g, cx, cy);
|
||||
}
|
||||
@@ -305,17 +456,51 @@ public final class ComputerScreen extends Screen {
|
||||
return;
|
||||
}
|
||||
int row = y + 18;
|
||||
int visible = Math.max(1, (h - 34) / 25);
|
||||
for (int i = 0; i < entries.size() && i < visible; i++) {
|
||||
int visible = Math.max(1, (h - 34) / 62);
|
||||
int start = Math.max(0, Math.min(session.archiveScroll, Math.max(0, entries.size() - visible)));
|
||||
for (int i = start; i < entries.size() && i < start + visible; i++) {
|
||||
ComputerGuideData.Entry entry = entries.get(i);
|
||||
int rowTop = row + i * 25;
|
||||
g.drawString(font, Component.literal(String.format("FILE_%02d", i + 1)), x + 5, rowTop, PALE_GREEN, false);
|
||||
String title = trimToWidth(Component.translatable(entry.titleKey()).getString(), w - 64);
|
||||
g.drawString(font, Component.literal(title), x + 57, rowTop, GREEN, false);
|
||||
g.drawString(font, Component.literal(entry.type().toUpperCase() + " // " + entry.category().toUpperCase()), x + 57, rowTop + 11, PALE_GREEN, false);
|
||||
int rowTop = row + (i - start) * 62;
|
||||
boolean hover = inside(x, rowTop, w - 8, 56, session.archiveMouseX, session.archiveMouseY);
|
||||
if (hover) g.fill(x, rowTop, x + w - 8, rowTop + 56, 0xFF173817);
|
||||
g.fill(x + 3, rowTop + 3, x + 51, rowTop + 51, BLACK);
|
||||
renderThumbnail(g, entry, x + 27, rowTop + 27, hover);
|
||||
String title = trimToWidth(Component.translatable(entry.titleKey()).getString(), w - 78);
|
||||
g.drawString(font, Component.literal(title), x + 58, rowTop + 9, GREEN, false);
|
||||
if (!entry.subtitleKey().isBlank()) g.drawString(font, Component.literal(trimToWidth(Component.translatable(entry.subtitleKey()).getString(), w - 78)), x + 58, rowTop + 23, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(entry.type().toUpperCase() + " // " + entry.category().toUpperCase()), x + 58, rowTop + 39, PALE_GREEN, false);
|
||||
}
|
||||
if (entries.size() > visible) g.drawString(font, Component.literal("SCROLLING NOT AVAILABLE // FIRST FILES SHOWN"), x, y + h - 12, PALE_GREEN, false);
|
||||
else g.drawString(font, Component.literal("[ CLICK FILE TO OPEN ]"), x, y + h - 12, PALE_GREEN, false);
|
||||
if (entries.size() > visible) g.drawString(font, Component.literal("SCROLL " + (start + 1) + "-" + Math.min(entries.size(), start + visible) + " / " + entries.size()), x, y + h - 12, PALE_GREEN, false);
|
||||
else g.drawString(font, Component.literal("[ CLICK ENTRY TO OPEN ]"), x, y + h - 12, PALE_GREEN, false);
|
||||
}
|
||||
|
||||
private void renderThumbnail(GuiGraphics g, ComputerGuideData.Entry entry, int centerX, int centerY, boolean hover) {
|
||||
int background = hover ? 0xFF173817 : 0xFF102010;
|
||||
g.fill(centerX - 18, centerY - 18, centerX + 18, centerY + 18, background);
|
||||
if (!entry.itemId().isBlank()) {
|
||||
try {
|
||||
ResourceLocation itemId = ResourceLocation.parse(entry.itemId());
|
||||
var item = BuiltInRegistries.ITEM.getOptional(itemId).orElse(null);
|
||||
if (item != null && !item.equals(net.minecraft.world.item.Items.AIR)) {
|
||||
g.renderItem(new ItemStack(item), centerX - 8, centerY - 8);
|
||||
return;
|
||||
}
|
||||
} catch (RuntimeException ignored) {
|
||||
}
|
||||
}
|
||||
if (!entry.entityId().isBlank() && Minecraft.getInstance().level != null) {
|
||||
try {
|
||||
ResourceLocation entityId = ResourceLocation.parse(entry.entityId());
|
||||
var entityType = BuiltInRegistries.ENTITY_TYPE.getOptional(entityId).orElse(null);
|
||||
var entity = entityType == null ? null : entityType.create(Minecraft.getInstance().level);
|
||||
if (entity instanceof LivingEntity living && !living.isRemoved()) {
|
||||
InventoryScreen.renderEntityInInventoryFollowsMouse(g, centerX - 18, centerY - 18, centerX + 18, centerY + 18, 18, 0.15F, centerX, centerY, living);
|
||||
return;
|
||||
}
|
||||
} catch (RuntimeException ignored) {
|
||||
}
|
||||
}
|
||||
g.drawString(font, Component.literal("ANT"), centerX - 12, centerY - 4, hover ? GREEN : PALE_GREEN, false);
|
||||
}
|
||||
|
||||
private void renderFileExplorer(GuiGraphics g, int x, int y, int w, int h) {
|
||||
@@ -327,12 +512,19 @@ public final class ComputerScreen extends Screen {
|
||||
for (String file : files) {
|
||||
String[] fields = file.split("\\t", 3);
|
||||
if (fields.length < 3 || !isDirectChild(fields[1], session.fileExplorerDirectory) || line > y + h - 20) continue;
|
||||
g.drawString(font, Component.literal(trimToWidth(fields[0], 36)), x, line, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth(fields[1], 125)), x + 42, line, GREEN, false);
|
||||
g.drawString(font, Component.literal(fields[2]), x + w - 28, line, PALE_GREEN, false);
|
||||
boolean selected = fields[1].equals(session.fileExplorerSelected);
|
||||
if (selected) g.fill(x - 3, line - 2, x + w - 3, line + 11, 0xFF173817);
|
||||
g.drawString(font, Component.literal(fileIcon(fields[0]) + " " + trimToWidth(fields[0], 30)), x, line, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth(fields[1], 112)), x + 42, line, GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth(fields[2], 28)), x + w - 28, line, PALE_GREEN, false);
|
||||
line += 14;
|
||||
}
|
||||
if (line == y + 34) g.drawString(font, Component.literal("NO FILES // OPEN TERMINAL TO CREATE ONE"), x, y + 38, PALE_GREEN, false);
|
||||
else g.drawString(font, Component.literal(session.fileExplorerRenaming ? "RENAME: " + session.fileExplorerRename + "_" : "[ DELETE ] [ F2 RENAME ]"), x, y + h - 16, PALE_GREEN, false);
|
||||
}
|
||||
|
||||
private String fileIcon(String type) {
|
||||
return type.equals("DIRECTORY") ? "[D]" : type.equals("TEXT") ? "[T]" : "[I]";
|
||||
}
|
||||
|
||||
private boolean isDirectChild(String path, String directory) {
|
||||
@@ -360,9 +552,8 @@ public final class ComputerScreen extends Screen {
|
||||
g.drawString(font, Component.literal("SYSTEM STATUS"), x, y, GREEN, false);
|
||||
g.drawString(font, Component.literal("CPU " + (System.currentTimeMillis() / 100 % 87 + 12) + "%"), x, y + 18, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("MEM " + (System.currentTimeMillis() / 250 % 42 + 31) + "%"), x, y + 32, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("WALLPAPER " + session.wallpaperId.substring(session.wallpaperId.indexOf(':') + 1).toUpperCase()), x, y + 46, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("[ CLICK TO CYCLE ]"), x, y + 60, GREEN, false);
|
||||
g.drawString(font, Component.literal("PASSWORD CHANGE IN FULL BUILD"), x, y + 70, GREEN, false);
|
||||
g.drawString(font, Component.literal("WALLPAPER DEFAULT // LOCKED"), x, y + 46, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("PASSWORD CHANGE IN FULL BUILD"), x, y + 60, GREEN, false);
|
||||
g.drawString(font, Component.literal("PHYSICAL DISKS"), x, y + 91, GREEN, false);
|
||||
List<ResourceLocation> disks = physicalDisks();
|
||||
if (disks.isEmpty()) {
|
||||
@@ -379,6 +570,21 @@ public final class ComputerScreen extends Screen {
|
||||
g.drawString(font, Component.literal("LOG OUT"), x, y + h - 17, GREEN, false);
|
||||
}
|
||||
|
||||
private void drawWallpaperPreview(GuiGraphics g, int x, int y, int w, int h, String id) {
|
||||
int hash = id.hashCode();
|
||||
int green = 24 + Math.floorMod(hash, 40);
|
||||
int blue = 12 + Math.floorMod(hash >>> 8, 24);
|
||||
int base = 0xFF000000 | (green / 2 << 16) | (green << 8) | blue;
|
||||
g.fill(x - 1, y - 1, x + w + 1, y + h + 1, GREEN);
|
||||
g.fill(x, y, x + w, y + h, base);
|
||||
int accent = 0xFF000000 | (Math.min(120, green + 34) << 8) | Math.min(80, blue + 34);
|
||||
for (int py = y + 4; py < y + h; py += 9) {
|
||||
for (int px = x + 4; px < x + w; px += 12) {
|
||||
if (Math.floorMod(px + py + hash, 3) == 0) g.fill(px, py, Math.min(x + w, px + 3), Math.min(y + h, py + 2), accent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void renderTerminal(GuiGraphics g, int x, int y, int h) {
|
||||
var fileState = ComputerFileSystemClientState.get(position);
|
||||
g.drawString(font, Component.literal("ANTINTOSH TERMINAL [READY]"), x, y, GREEN, false);
|
||||
@@ -387,8 +593,8 @@ public final class ComputerScreen extends Screen {
|
||||
line = wrap(g, output, x, line, 208, PALE_GREEN) + 1;
|
||||
if (line > y + h - 32) break;
|
||||
}
|
||||
if (!fileState.error().isEmpty()) g.drawString(font, Component.literal("RESPONSE: " + fileState.error()), x, y + 16, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(session.terminalDirectory + "> " + session.terminalInput + "_"), x, y + h - 48, GREEN, false);
|
||||
if (!fileState.error().isEmpty()) g.drawString(font, Component.literal("RESPONSE: " + fileState.error()), x, y + h - 40, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(session.terminalDirectory + "> " + session.terminalInput + "_"), x, y + h - 26, GREEN, false);
|
||||
}
|
||||
|
||||
private void renderPaint(GuiGraphics g, int x, int y, int w, int h) {
|
||||
@@ -402,14 +608,27 @@ public final class ComputerScreen extends Screen {
|
||||
}
|
||||
}
|
||||
g.drawString(font, Component.literal("ANTPAINT // " + session.paintName + (session.paintDirty ? " *" : "")), x, y, GREEN, false);
|
||||
g.drawString(font, Component.literal("NEW PENCIL ERASER FILL CLEAR UNDO REDO SAVE"), x, y + 14, PALE_GREEN, false);
|
||||
int size = Math.min((w - 16) / AntPaintCanvas.WIDTH, (h - 54) / AntPaintCanvas.HEIGHT);
|
||||
String controls = "NEW PENCIL ERASER FILL CLEAR UNDO REDO SAVE";
|
||||
g.drawString(font, Component.literal(trimToWidth(controls, w)), x, y + 14, PALE_GREEN, false);
|
||||
int size = Math.max(1, Math.min((w - 16) / AntPaintCanvas.WIDTH, (h - 54) / AntPaintCanvas.HEIGHT));
|
||||
int cx = x + (w - size * AntPaintCanvas.WIDTH) / 2;
|
||||
int cy = y + 30;
|
||||
int cy = y + 30 + Math.max(0, (h - 54 - size * AntPaintCanvas.HEIGHT) / 2);
|
||||
g.fill(cx - 1, cy - 1, cx + size * AntPaintCanvas.WIDTH + 1, cy + size * AntPaintCanvas.HEIGHT + 1, BLACK);
|
||||
g.fill(cx, cy, cx + size * AntPaintCanvas.WIDTH, cy + size * AntPaintCanvas.HEIGHT, GREEN);
|
||||
for (int py = 0; py < AntPaintCanvas.HEIGHT; py++) for (int px = 0; px < AntPaintCanvas.WIDTH; px++) if (!session.paintCanvas.get(px, py)) g.fill(cx + px * size, cy + py * size, cx + (px + 1) * size, cy + (py + 1) * size, BLACK);
|
||||
g.drawString(font, Component.literal("TOOL " + session.paintTool.name() + " " + (session.paintDirty ? "MODIFIED" : "SAVED")), x, y + h - 16, PALE_GREEN, false);
|
||||
int hoverX = (session.mouseX - cx) / size;
|
||||
int hoverY = (session.mouseY - cy) / size;
|
||||
if (session.mouseX >= cx && session.mouseY >= cy && hoverX >= 0 && hoverX < AntPaintCanvas.WIDTH && hoverY >= 0 && hoverY < AntPaintCanvas.HEIGHT) {
|
||||
int pixelX = cx + hoverX * size;
|
||||
int pixelY = cy + hoverY * size;
|
||||
g.fill(pixelX, pixelY, pixelX + size, pixelY + 1, PALE_GREEN);
|
||||
g.fill(pixelX, pixelY + size - 1, pixelX + size, pixelY + size, PALE_GREEN);
|
||||
g.fill(pixelX, pixelY, pixelX + 1, pixelY + size, PALE_GREEN);
|
||||
g.fill(pixelX + size - 1, pixelY, pixelX + size, pixelY + size, PALE_GREEN);
|
||||
}
|
||||
String paintStatus = "TOOL " + session.paintTool.name() + " " + (session.paintDirty ? "MODIFIED" : "SAVED");
|
||||
if (session.mouseX >= cx && session.mouseY >= cy && hoverX >= 0 && hoverX < AntPaintCanvas.WIDTH && hoverY >= 0 && hoverY < AntPaintCanvas.HEIGHT) paintStatus += " PIXEL " + hoverX + "," + hoverY;
|
||||
g.drawString(font, Component.literal(trimToWidth(paintStatus, w)), x, y + h - 16, PALE_GREEN, false);
|
||||
}
|
||||
|
||||
private void renderTextEditor(GuiGraphics g, int x, int y, int w, int h) {
|
||||
@@ -418,7 +637,7 @@ public final class ComputerScreen extends Screen {
|
||||
session.textPath = fileState.openedPath();
|
||||
session.textContent = fileState.openedContents();
|
||||
}
|
||||
g.drawString(font, Component.literal("ANTTEXT // " + session.textPath + (session.textDirty ? " *" : "")), x, y, GREEN, false);
|
||||
g.drawString(font, Component.literal(session.textRenaming ? "RENAME // " + session.textRename + "_" : "ANTTEXT // " + session.textPath + (session.textDirty ? " *" : "")), x, y, GREEN, false);
|
||||
g.drawString(font, Component.literal("NEW OPEN WRITE SAVE"), x, y + 18, PALE_GREEN, false);
|
||||
g.fill(x + 4, y + 36, x + w - 4, y + h - 4, BLACK);
|
||||
if (session.textListing) {
|
||||
@@ -434,7 +653,7 @@ public final class ComputerScreen extends Screen {
|
||||
} else {
|
||||
wrap(g, session.textContent.isEmpty() ? "TYPE HERE..." : session.textContent, x + 10, y + 46, w - 28, GREEN);
|
||||
}
|
||||
g.drawString(font, Component.literal("[ CTRL+S ] SAVE [ ESC ] CLOSE"), x, y + h - 50, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("[ CTRL+S ] SAVE [ F2 ] RENAME [ ESC ] CLOSE"), x, y + h - 50, PALE_GREEN, false);
|
||||
}
|
||||
|
||||
private void renderAntmail(GuiGraphics g, int x, int y, int h) {
|
||||
@@ -446,40 +665,53 @@ public final class ComputerScreen extends Screen {
|
||||
g.drawString(font, Component.literal("USERNAME // 3-16 CHARACTERS"), x, y + 40, GREEN, false);
|
||||
g.fill(x, y + 56, x + 206, y + 79, BLACK);
|
||||
box(g, x, y + 56, x + 206, y + 79, GREEN);
|
||||
g.drawString(font, Component.literal(session.antmailUsername + "@ANTMAIL.COM"), x + 6, y + 63, GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth(session.antmailUsername + "@antmail.com", 194)), x + 6, y + 63, GREEN, false);
|
||||
g.drawString(font, Component.literal("[ ENTER ] REGISTER ADDRESS"), x, y + 88, GREEN, false);
|
||||
} else {
|
||||
g.drawString(font, Component.literal(result.address()), x, y + 20, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("[ INBOX ] [ SENT ] [ COMPOSE ]"), x, y + 40, GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth(result.address(), 208)), x, y + 20, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("[ INBOX ] [ SENT ]"), x, y + 40, GREEN, false);
|
||||
box(g, x + 122, y + 30, x + 214, y + 53, GREEN);
|
||||
g.drawString(font, Component.literal("CREATE COMPOSE"), x + 127, y + 38, GREEN, false);
|
||||
if (session.antmailMode.equals("compose")) {
|
||||
g.drawString(font, Component.literal("TO"), x, y + 62, GREEN, false);
|
||||
g.drawString(font, Component.literal(session.antmailRecipient), x + 28, y + 62, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth(session.antmailRecipient, 180)), x + 28, y + 62, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("SUBJECT"), x, y + 78, GREEN, false);
|
||||
g.drawString(font, Component.literal(session.antmailSubject), x + 52, y + 78, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth(session.antmailSubject, 156)), x + 52, y + 78, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("BODY"), x, y + 94, GREEN, false);
|
||||
wrap(g, session.antmailBody.isEmpty() ? "TYPE MESSAGE..." : session.antmailBody, x, y + 110, 208, PALE_GREEN);
|
||||
g.drawString(font, Component.literal("[ " + (session.antmailAttachText ? "X" : " ") + " ] TEXT FILE [ " + (session.antmailAttachPaint ? "X" : " ") + " ] PAINTING"), x, y + 142, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth("[ " + (session.antmailAttachText ? "X" : " ") + " ] TEXT FILE [ " + (session.antmailAttachPaint ? "X" : " ") + " ] PAINTING", 208)), x, y + 142, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("[ ENTER ] SEND MESSAGE"), x, y + h - 30, GREEN, false);
|
||||
} else if (session.antmailMode.equals("message")) {
|
||||
AntmailMessage message = selectedAntmailMessage(result);
|
||||
if (message != null) {
|
||||
g.drawString(font, Component.literal("< BACK // INBOX"), x, y + 40, GREEN, false);
|
||||
g.drawString(font, Component.literal(message.sender().fullAddress()), x, y + 62, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(message.subject()), x, y + 78, GREEN, false);
|
||||
wrap(g, message.body(), x, y + 98, 208, PALE_GREEN);
|
||||
g.drawString(font, Component.literal("< BACK // " + (session.antmailSent ? "SENT" : "INBOX")), x, y + 40, GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth(session.antmailSent ? message.recipient().fullAddress() : message.sender().fullAddress(), 208)), x, y + 62, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(trimToWidth(message.subject(), 208)), x, y + 78, GREEN, false);
|
||||
int messageLine = wrap(g, message.body(), x, y + 98, 208, PALE_GREEN) + 4;
|
||||
for (AntmailAttachment attachment : message.attachments()) {
|
||||
if (messageLine > y + h - 38) break;
|
||||
messageLine = wrap(g, "ATTACHMENT // " + attachment.fileName(), x, messageLine, 208, GREEN) + 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
g.drawString(font, Component.literal("INBOX // " + mailboxMessages(result, false).size()), x, y + 62, GREEN, false);
|
||||
List<AntmailMessage> messages = mailboxMessages(result, session.antmailSent);
|
||||
g.drawString(font, Component.literal((session.antmailSent ? "SENT // " : "INBOX // ") + messages.size()), x, y + 62, GREEN, false);
|
||||
int line = y + 80;
|
||||
for (AntmailMessage message : mailboxMessages(result, false)) {
|
||||
for (AntmailMessage message : messages) {
|
||||
if (line > y + h - 38) break;
|
||||
g.drawString(font, Component.literal((message.read() ? " " : "* ") + trimToWidth(message.subject(), 28)), x, line, message.read() ? PALE_GREEN : GREEN, false);
|
||||
line += 14;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!session.antmailStatus.isEmpty()) g.drawString(font, Component.literal(session.antmailStatus), x, y + h - 30, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal(result == null ? "WAITING FOR SERVER" : result.status() == 0 ? "DELIVERY READY" : "SERVER RESPONSE: " + result.detail()), x, y + h - 16, GREEN, false);
|
||||
String displayStatus = result != null && !result.messageId().isBlank() ? antmailStatus(result) : session.antmailStatus;
|
||||
if (!displayStatus.isEmpty()) drawBottomWrapped(g, displayStatus, x, y, h, 208, PALE_GREEN);
|
||||
}
|
||||
|
||||
private String antmailStatus(AntmailResultPayload result) {
|
||||
if (result.status() == 0) return "DELIVERED";
|
||||
if (result.status() == 1) return "QUEUED";
|
||||
return "DELIVERY FAILED // " + (result.detail().isBlank() ? "SERVER REJECTED" : result.detail().toUpperCase());
|
||||
}
|
||||
|
||||
private AntmailMailbox mailbox(AntmailResultPayload result) {
|
||||
@@ -505,9 +737,11 @@ public final class ComputerScreen extends Screen {
|
||||
private void renderGames(GuiGraphics g, int x, int y) {
|
||||
g.drawString(font, Component.literal("INSTALLED GAMES"), x, y, GREEN, false);
|
||||
if (activeWindow != null && activeWindow.gameOpen) { antFarm.render(g, font, x, y + 16, 214, 155); return; }
|
||||
g.drawString(font, Component.literal(antFarm.isGameInstalled() ? "ANT FARM [ ENTER ]" : "ANT FARM [NOT INSTALLED]"), x, y + 22, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("GLIMMER MATCH"), x, y + 38, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("HFCS FACTORY"), x, y + 54, PALE_GREEN, false);
|
||||
if (antFarm.isGameInstalled()) g.drawString(font, Component.literal("ANT FARM [ ENTER ]"), x, y + 22, PALE_GREEN, false);
|
||||
else {
|
||||
g.drawString(font, Component.literal("NO GAMES INSTALLED"), x, y + 22, PALE_GREEN, false);
|
||||
g.drawString(font, Component.literal("FIND GAME DISKS TO INSTALL PROGRAMS"), x, y + 40, PALE_GREEN, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderTrash(GuiGraphics g, int x, int y) {
|
||||
@@ -522,6 +756,15 @@ public final class ComputerScreen extends Screen {
|
||||
return y;
|
||||
}
|
||||
|
||||
private void drawBottomWrapped(GuiGraphics g, String text, int x, int y, int h, int width, int color) {
|
||||
List<net.minecraft.util.FormattedCharSequence> lines = font.split(Component.literal(text), width);
|
||||
int lineY = y + h - 16 - Math.max(0, lines.size() - 1) * 11;
|
||||
for (var line : lines) {
|
||||
g.drawString(font, line, x, lineY, color, false);
|
||||
lineY += 11;
|
||||
}
|
||||
}
|
||||
|
||||
private void box(GuiGraphics g, int x1, int y1, int x2, int y2, int color) {
|
||||
g.fill(x1, y1, x2, y1 + 2, color);
|
||||
g.fill(x1, y2 - 2, x2, y2, color);
|
||||
@@ -553,6 +796,14 @@ public final class ComputerScreen extends Screen {
|
||||
int h = window.maximized ? HEIGHT - 48 : window.height;
|
||||
if (inside(x, y + 20, w, h - 20, mouseX, mouseY)) {
|
||||
activeWindow = window;
|
||||
session.windows.remove(i);
|
||||
session.windows.add(window);
|
||||
if (window.type.equals("SETTINGS") && inside(x + 8, y + 105, 205, 51, mouseX, mouseY)) {
|
||||
List<ResourceLocation> disks = physicalDisks();
|
||||
int index = ((int) mouseY - (y + 105)) / 17;
|
||||
if (index >= 0 && index < disks.size() && index < 3) selectedDisk = disks.get(index);
|
||||
return true;
|
||||
}
|
||||
if (window.type.equals("ARCHIVE")) {
|
||||
List<ComputerGuideData.Entry> entries = ComputerGuideData.entriesFor(computer() == null ? List.of() : computer().diskIds());
|
||||
int archiveX = x + 8;
|
||||
@@ -560,9 +811,11 @@ public final class ComputerScreen extends Screen {
|
||||
if (session.archiveEntryId != null) {
|
||||
if (inside(archiveX, archiveY, w - 16, 20, mouseX, mouseY)) session.archiveEntryId = null;
|
||||
} else {
|
||||
int visible = Math.max(1, (h - 34) / 25);
|
||||
int index = ((int) mouseY - (archiveY + 16)) / 25;
|
||||
if (index >= 0 && index < entries.size() && index < visible && inside(archiveX, archiveY + 16 + index * 25, w - 16, 23, mouseX, mouseY)) session.archiveEntryId = entries.get(index).id();
|
||||
int visible = Math.max(1, (h - 34) / 62);
|
||||
int start = Math.max(0, Math.min(session.archiveScroll, Math.max(0, entries.size() - visible)));
|
||||
int index = start + ((int) mouseY - (archiveY + 16)) / 62;
|
||||
int rowIndex = index - start;
|
||||
if (rowIndex >= 0 && rowIndex < visible && index < entries.size() && inside(archiveX, archiveY + 16 + rowIndex * 62, w - 16, 56, mouseX, mouseY)) session.archiveEntryId = entries.get(index).id();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -576,7 +829,9 @@ public final class ComputerScreen extends Screen {
|
||||
for (String file : files) {
|
||||
String[] fields = file.split("\\t", 3);
|
||||
if (fields.length < 3 || !isDirectChild(fields[1], session.fileExplorerDirectory)) continue;
|
||||
if (row++ != ((int) mouseY - (y + 62)) / 14) continue;
|
||||
int rowTop = y + 34 + row++ * 14;
|
||||
if (!inside(x, rowTop - 2, w, 14, mouseX, mouseY)) continue;
|
||||
session.fileExplorerSelected = fields[1];
|
||||
if (fields[0].equals("DIRECTORY")) session.fileExplorerDirectory = fields[1];
|
||||
else if (fields[0].equals("TEXT")) {
|
||||
ComputerNetworking.openFile(position, fields[1]);
|
||||
@@ -624,10 +879,18 @@ public final class ComputerScreen extends Screen {
|
||||
setupAntmail();
|
||||
return true;
|
||||
}
|
||||
} else if (mouseY < y + 72) {
|
||||
if (mouseX < x + 70) { session.antmailMode = "inbox"; session.antmailSent = false; session.antmailMessageIndex = -1; }
|
||||
else if (mouseX < x + 125) { session.antmailMode = "sent"; session.antmailSent = true; session.antmailMessageIndex = -1; }
|
||||
else { session.antmailMode = "compose"; session.antmailFocused = true; session.antmailField = 1; }
|
||||
} else if (inside(x + 8, y + 54, 54, 27, mouseX, mouseY)) {
|
||||
session.antmailMode = "inbox";
|
||||
session.antmailSent = false;
|
||||
session.antmailMessageIndex = -1;
|
||||
} else if (inside(x + 62, y + 54, 58, 27, mouseX, mouseY)) {
|
||||
session.antmailMode = "sent";
|
||||
session.antmailSent = true;
|
||||
session.antmailMessageIndex = -1;
|
||||
} else if (inside(x + 122, y + 54, 92, 27, mouseX, mouseY)) {
|
||||
session.antmailMode = "compose";
|
||||
session.antmailFocused = true;
|
||||
session.antmailField = 1;
|
||||
} else if (session.antmailMode.equals("inbox") || session.antmailMode.equals("sent")) {
|
||||
int index = ((int) mouseY - (y + 108)) / 14;
|
||||
List<AntmailMessage> messages = mailboxMessages(result, session.antmailSent);
|
||||
@@ -636,10 +899,22 @@ public final class ComputerScreen extends Screen {
|
||||
session.antmailMode = "message";
|
||||
AntmailNetworking.markRead(position, messages.get(index).id());
|
||||
}
|
||||
} else if (session.antmailMode.equals("message")) {
|
||||
if (mouseY < y + 72) {
|
||||
session.antmailMode = session.antmailSent ? "sent" : "inbox";
|
||||
session.antmailMessageIndex = -1;
|
||||
}
|
||||
} else if (session.antmailMode.equals("compose")) {
|
||||
if (mouseY >= y + 160 && mouseY < y + 184) {
|
||||
session.antmailAttachText = mouseX < x + 112;
|
||||
session.antmailAttachPaint = mouseX >= x + 112;
|
||||
if (session.antmailAttachText && session.fileExplorerSelected.endsWith(".txt")) {
|
||||
session.textPath = session.fileExplorerSelected;
|
||||
ComputerNetworking.openFile(position, session.fileExplorerSelected);
|
||||
}
|
||||
if (session.antmailAttachPaint && session.fileExplorerSelected.endsWith(".antpaint")) {
|
||||
ComputerNetworking.openFile(position, session.fileExplorerSelected);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (mouseY < y + 94) {
|
||||
@@ -663,19 +938,18 @@ public final class ComputerScreen extends Screen {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (window.type.equals("SETTINGS") && inside(x + 8, y + 70, 205, 25, mouseX, mouseY)) {
|
||||
if (session.wallpapers.size() > 1) {
|
||||
int current = session.wallpapers.indexOf(session.wallpaperId);
|
||||
String next = session.wallpapers.get((current + 1 + session.wallpapers.size()) % session.wallpapers.size());
|
||||
session.wallpaperId = next;
|
||||
ComputerNetworking.selectWallpaper(position, ResourceLocation.parse(next));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (window.type.equals("SETTINGS") && inside(x + 8, y + 155, 205, 25, mouseX, mouseY)) {
|
||||
ejectSelected();
|
||||
return true;
|
||||
}
|
||||
if (window.type.equals("SETTINGS") && inside(x, y + h - 30, 90, 25, mouseX, mouseY)) {
|
||||
ComputerNetworking.logout(position);
|
||||
loggedIn = false;
|
||||
session.authenticated = false;
|
||||
session.windows.clear();
|
||||
activeWindow = null;
|
||||
return true;
|
||||
}
|
||||
if (inside(x, y + 20, w, h - 20, mouseX, mouseY)) return true;
|
||||
if (inside(x, y, w, 20, mouseX, mouseY)) {
|
||||
if (inside(x + w - 18, y, 18, 20, mouseX, mouseY)) session.windows.remove(i);
|
||||
@@ -741,6 +1015,15 @@ public final class ComputerScreen extends Screen {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean mouseScrolled(double mouseX, double mouseY, double scrollX, double scrollY) {
|
||||
if (loggedIn && activeWindow != null && activeWindow.type.equals("ARCHIVE") && session.archiveEntryId == null) {
|
||||
session.archiveScroll = Math.max(0, session.archiveScroll - (int) Math.signum(scrollY));
|
||||
return true;
|
||||
}
|
||||
return super.mouseScrolled(mouseX, mouseY, scrollX, scrollY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean charTyped(char codePoint, int modifiers) {
|
||||
if (!loggedIn && codePoint >= 32) {
|
||||
@@ -750,6 +1033,14 @@ public final class ComputerScreen extends Screen {
|
||||
password += Character.toUpperCase(codePoint);
|
||||
}
|
||||
}
|
||||
if (loggedIn && activeWindow != null && activeWindow.type.equals("FILES") && session.fileExplorerRenaming && codePoint >= 32 && codePoint != '/' && codePoint != '\\') {
|
||||
if (session.fileExplorerRename.length() < 48) session.fileExplorerRename += codePoint;
|
||||
return true;
|
||||
}
|
||||
if (loggedIn && activeWindow != null && activeWindow.type.equals("TEXT") && session.textRenaming && codePoint >= 32 && codePoint != '/' && codePoint != '\\') {
|
||||
if (session.textRename.length() < 48) session.textRename += codePoint;
|
||||
return true;
|
||||
}
|
||||
if (loggedIn && activeWindow != null) {
|
||||
if (activeWindow.type.equals("TEXT") && session.textFocused && codePoint >= 32) { session.textContent += codePoint; session.textDirty = true; return true; }
|
||||
if (activeWindow.type.equals("TERMINAL") && session.terminalFocused && codePoint >= 32) { session.terminalInput += codePoint; return true; }
|
||||
@@ -780,6 +1071,29 @@ public final class ComputerScreen extends Screen {
|
||||
if (keyCode == GLFW.GLFW_KEY_ESCAPE) { activeWindow.gameOpen = false; return true; }
|
||||
if (antFarm.keyPressed(keyCode)) return true;
|
||||
}
|
||||
if (activeWindow != null && activeWindow.type.equals("FILES")) {
|
||||
if (session.fileExplorerRenaming) {
|
||||
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
|
||||
if (!session.fileExplorerRename.isEmpty()) session.fileExplorerRename = session.fileExplorerRename.substring(0, session.fileExplorerRename.length() - 1);
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||
session.fileExplorerRenaming = false;
|
||||
session.fileExplorerRename = "";
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
|
||||
renameSelectedFile();
|
||||
return true;
|
||||
}
|
||||
} else if (keyCode == GLFW.GLFW_KEY_F2) {
|
||||
beginRenameSelectedFile();
|
||||
return true;
|
||||
} else if (keyCode == GLFW.GLFW_KEY_DELETE) {
|
||||
deleteSelectedFile();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (activeWindow != null && activeWindow.type.equals("TERMINAL") && session.terminalFocused) {
|
||||
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) { if (!session.terminalInput.isEmpty()) session.terminalInput = session.terminalInput.substring(0, session.terminalInput.length() - 1); return true; }
|
||||
if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) { executeTerminal(); return true; }
|
||||
@@ -807,6 +1121,29 @@ public final class ComputerScreen extends Screen {
|
||||
if (keyCode == GLFW.GLFW_KEY_S && hasControl(modifiers)) { saveText(); return true; }
|
||||
if (keyCode == GLFW.GLFW_KEY_ESCAPE) { session.textFocused = false; return true; }
|
||||
}
|
||||
if (activeWindow != null && activeWindow.type.equals("TEXT")) {
|
||||
if (keyCode == GLFW.GLFW_KEY_F2 && !session.textPath.isBlank()) {
|
||||
int slash = session.textPath.lastIndexOf('/');
|
||||
session.textRename = session.textPath.substring(slash + 1);
|
||||
session.textRenaming = true;
|
||||
return true;
|
||||
}
|
||||
if (session.textRenaming) {
|
||||
if (keyCode == GLFW.GLFW_KEY_BACKSPACE) {
|
||||
if (!session.textRename.isEmpty()) session.textRename = session.textRename.substring(0, session.textRename.length() - 1);
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||
session.textRenaming = false;
|
||||
session.textRename = "";
|
||||
return true;
|
||||
}
|
||||
if (keyCode == GLFW.GLFW_KEY_ENTER || keyCode == GLFW.GLFW_KEY_KP_ENTER) {
|
||||
renameTextFile();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (activeWindow != null && activeWindow.type.equals("ARCHIVE") && session.archiveEntryId != null && keyCode == GLFW.GLFW_KEY_ESCAPE) {
|
||||
session.archiveEntryId = null;
|
||||
return true;
|
||||
@@ -848,25 +1185,7 @@ public final class ComputerScreen extends Screen {
|
||||
String input = session.terminalInput.trim();
|
||||
if (input.isEmpty()) return;
|
||||
session.terminalOutput.add(session.terminalDirectory + "> " + input);
|
||||
TerminalCommandParser.ParseResult parsed = TerminalCommandParser.parse(input);
|
||||
if (!parsed.isSuccess()) session.terminalOutput.add(parsed.error());
|
||||
else {
|
||||
String command = parsed.command().name();
|
||||
List<String> args = parsed.command().arguments();
|
||||
if (command.equals("pwd")) session.terminalOutput.add(session.terminalDirectory);
|
||||
else if (command.equals("clear")) session.terminalOutput.clear();
|
||||
else if (command.equals("ls")) ComputerNetworking.listFiles(position);
|
||||
else if (command.equals("open") && args.size() == 1) ComputerNetworking.openFile(position, args.get(0));
|
||||
else if (command.equals("touch") && args.size() == 1) ComputerNetworking.createFile(position, args.get(0), "");
|
||||
else if (command.equals("write") && args.size() >= 1) ComputerNetworking.saveFile(position, args.get(0), args.size() > 1 ? args.get(1) : "");
|
||||
else if (command.equals("cd") && args.size() == 1) {
|
||||
String path = args.get(0).startsWith("/") ? args.get(0) : session.terminalDirectory + "/" + args.get(0);
|
||||
session.terminalDirectory = ComputerFileSystem.normalize(path);
|
||||
}
|
||||
else if (command.equals("help")) session.terminalOutput.add("HELP CLEAR PWD LS CD MKDIR TOUCH CAT WRITE RM RMDIR MV OPEN");
|
||||
else session.terminalOutput.add("COMMAND NOT RECOGNIZED");
|
||||
}
|
||||
while (session.terminalOutput.size() > 40) session.terminalOutput.remove(0);
|
||||
ComputerNetworking.terminalCommand(position, session.terminalDirectory, input);
|
||||
session.terminalInput = "";
|
||||
}
|
||||
|
||||
@@ -877,7 +1196,8 @@ public final class ComputerScreen extends Screen {
|
||||
return;
|
||||
}
|
||||
AntmailNetworking.setup(position, session.antmailUsername);
|
||||
session.antmailStatus = "REGISTERING ADDRESS // WAITING";
|
||||
session.antmailStatus = "REGISTERING ADDRESS";
|
||||
session.antmailRegistrationPending = true;
|
||||
session.antmailFocused = false;
|
||||
}
|
||||
|
||||
@@ -890,6 +1210,14 @@ public final class ComputerScreen extends Screen {
|
||||
session.antmailStatus = "SEND ERROR // SUBJECT AND BODY REQUIRED";
|
||||
return;
|
||||
}
|
||||
if (session.antmailAttachText && (session.textDirty || session.textPath.isBlank() || session.textPath.contains("untitled"))) {
|
||||
session.antmailStatus = "SEND ERROR // SAVE TEXT FILE FIRST";
|
||||
return;
|
||||
}
|
||||
if (session.antmailAttachPaint && (session.paintDirty || session.paintName.isBlank() || session.paintName.startsWith("UNTITLED"))) {
|
||||
session.antmailStatus = "SEND ERROR // SAVE PAINTING FIRST";
|
||||
return;
|
||||
}
|
||||
List<AntmailAttachment> attachments = new ArrayList<>();
|
||||
if (session.antmailAttachText && !session.textContent.isEmpty()) attachments.add(new AntmailAttachment.TextFile(session.textPath.substring(session.textPath.lastIndexOf('/') + 1), session.textContent));
|
||||
if (session.antmailAttachPaint) {
|
||||
@@ -898,7 +1226,7 @@ public final class ComputerScreen extends Screen {
|
||||
attachments.add(new AntmailAttachment.PaintImage(session.paintName, AntPaintCanvas.WIDTH, AntPaintCanvas.HEIGHT, pixels));
|
||||
}
|
||||
AntmailNetworking.send(position, session.antmailRecipient, session.antmailSubject, session.antmailBody, attachments);
|
||||
session.antmailStatus = "TRANSMITTING MESSAGE // WAITING";
|
||||
session.antmailStatus = "MESSAGE SENT";
|
||||
session.antmailMode = "inbox";
|
||||
session.antmailFocused = false;
|
||||
session.antmailRecipient = "";
|
||||
@@ -917,13 +1245,31 @@ public final class ComputerScreen extends Screen {
|
||||
}
|
||||
|
||||
private void writeText() {
|
||||
ComputerNetworking.createFile(position, session.textPath, session.textContent);
|
||||
boolean exists = ComputerFileSystemClientState.get(position).files().stream().anyMatch(entry -> entry.contains("\t" + session.textPath + "\t"));
|
||||
if (exists) ComputerNetworking.saveFile(position, session.textPath, session.textContent);
|
||||
else ComputerNetworking.createFile(position, session.textPath, session.textContent);
|
||||
session.textDirty = false;
|
||||
ComputerNetworking.listFiles(position);
|
||||
}
|
||||
|
||||
private void saveText() {
|
||||
ComputerNetworking.saveFile(position, session.textPath, session.textContent);
|
||||
boolean exists = ComputerFileSystemClientState.get(position).files().stream().anyMatch(entry -> entry.contains("\t" + session.textPath + "\t"));
|
||||
if (exists) ComputerNetworking.saveFile(position, session.textPath, session.textContent);
|
||||
else ComputerNetworking.createFile(position, session.textPath, session.textContent);
|
||||
session.textDirty = false;
|
||||
ComputerNetworking.listFiles(position);
|
||||
}
|
||||
|
||||
private void renameTextFile() {
|
||||
if (!session.textRename.isBlank() && !session.textRename.contains("/") && !ComputerFileSystem.isProtected(session.textPath)) {
|
||||
String parent = parentDirectory(session.textPath);
|
||||
String destination = parent.equals("/") ? "/" + session.textRename : parent + "/" + session.textRename;
|
||||
ComputerNetworking.moveFile(position, session.textPath, destination);
|
||||
session.textPath = destination;
|
||||
ComputerNetworking.listFiles(position);
|
||||
}
|
||||
session.textRenaming = false;
|
||||
session.textRename = "";
|
||||
}
|
||||
|
||||
private void savePaint() {
|
||||
@@ -936,6 +1282,7 @@ public final class ComputerScreen extends Screen {
|
||||
boolean exists = ComputerFileSystemClientState.get(position).files().stream().anyMatch(entry -> entry.contains("\t" + savedPath + "\t"));
|
||||
if (exists) ComputerNetworking.saveFile(position, savedPath, encoded); else ComputerNetworking.createFile(position, savedPath, encoded);
|
||||
session.paintDirty = false;
|
||||
ComputerNetworking.listFiles(position);
|
||||
}
|
||||
|
||||
private void paintTool(int offset) {
|
||||
@@ -981,10 +1328,43 @@ public final class ComputerScreen extends Screen {
|
||||
selectedDisk = null;
|
||||
}
|
||||
|
||||
private void beginRenameSelectedFile() {
|
||||
if (session.fileExplorerSelected.isEmpty() || session.fileExplorerSelected.equals("/") || ComputerFileSystem.isProtected(session.fileExplorerSelected)) return;
|
||||
int slash = session.fileExplorerSelected.lastIndexOf('/');
|
||||
session.fileExplorerRename = session.fileExplorerSelected.substring(slash + 1);
|
||||
session.fileExplorerRenaming = true;
|
||||
}
|
||||
|
||||
private void renameSelectedFile() {
|
||||
if (!session.fileExplorerRename.isBlank() && !session.fileExplorerRename.contains("/")) {
|
||||
String parent = parentDirectory(session.fileExplorerSelected);
|
||||
String destination = parent.equals("/") ? "/" + session.fileExplorerRename : parent + "/" + session.fileExplorerRename;
|
||||
ComputerNetworking.moveFile(position, session.fileExplorerSelected, destination);
|
||||
session.fileExplorerSelected = destination;
|
||||
ComputerNetworking.listFiles(position);
|
||||
}
|
||||
session.fileExplorerRenaming = false;
|
||||
session.fileExplorerRename = "";
|
||||
}
|
||||
|
||||
private void deleteSelectedFile() {
|
||||
if (session.fileExplorerSelected.isEmpty() || session.fileExplorerSelected.equals("/") || ComputerFileSystem.isProtected(session.fileExplorerSelected)) return;
|
||||
ComputerNetworking.deleteFile(position, session.fileExplorerSelected);
|
||||
session.fileExplorerSelected = "";
|
||||
ComputerNetworking.listFiles(position);
|
||||
}
|
||||
|
||||
private void open(String type) {
|
||||
for (Window window : session.windows) if (window.type.equals(type)) { window.minimized = false; session.windows.remove(window); session.windows.add(window); return; }
|
||||
for (Window window : session.windows) if (window.type.equals(type)) {
|
||||
window.minimized = false;
|
||||
session.windows.remove(window);
|
||||
session.windows.add(window);
|
||||
if (type.equals("FILES")) ComputerNetworking.listFiles(position);
|
||||
return;
|
||||
}
|
||||
session.windows.add(new Window(type, TITLES.get(type), 112 + session.windows.size() * 12, 52 + session.windows.size() * 10));
|
||||
if (type.equals("ANTMAIL")) AntmailNetworking.requestState(position);
|
||||
else if (type.equals("FILES")) ComputerNetworking.listFiles(position);
|
||||
}
|
||||
|
||||
private static boolean inside(int x, int y, int w, int h, double mx, double my) { return mx >= x && mx < x + w && my >= y && my < y + h; }
|
||||
@@ -1005,13 +1385,21 @@ public final class ComputerScreen extends Screen {
|
||||
private final List<String> terminalOutput = new ArrayList<>(List.of("ANTINTOSH TERMINAL [READY]", "TYPE HELP FOR COMMANDS"));
|
||||
private String terminalInput = "";
|
||||
private String terminalDirectory = "/";
|
||||
private String terminalResponse = "";
|
||||
private boolean terminalFocused;
|
||||
private String textPath = "/documents/untitled.txt";
|
||||
private String textContent = "";
|
||||
private boolean textDirty;
|
||||
private boolean textFocused;
|
||||
private boolean textListing;
|
||||
private boolean textRenaming;
|
||||
private String textRename = "";
|
||||
private ResourceLocation archiveEntryId;
|
||||
private int archiveScroll;
|
||||
private int archiveMouseX;
|
||||
private int archiveMouseY;
|
||||
private int mouseX;
|
||||
private int mouseY;
|
||||
private AntPaintCanvas paintCanvas = new AntPaintCanvas();
|
||||
private final AntPaintHistory paintHistory = new AntPaintHistory();
|
||||
private AntPaintTool paintTool = AntPaintTool.PENCIL;
|
||||
@@ -1019,6 +1407,7 @@ public final class ComputerScreen extends Screen {
|
||||
private boolean paintDirty;
|
||||
private String antmailUsername = "";
|
||||
private String antmailStatus = "";
|
||||
private boolean antmailRegistrationPending;
|
||||
private boolean antmailFocused;
|
||||
private String antmailMode = "inbox";
|
||||
private String antmailRecipient = "";
|
||||
@@ -1030,6 +1419,9 @@ public final class ComputerScreen extends Screen {
|
||||
private boolean antmailAttachText;
|
||||
private boolean antmailAttachPaint;
|
||||
private String fileExplorerDirectory = "/";
|
||||
private String fileExplorerSelected = "";
|
||||
private String fileExplorerRename = "";
|
||||
private boolean fileExplorerRenaming;
|
||||
private String wallpaperId = ComputerDesktopState.DEFAULT_WALLPAPER.toString();
|
||||
private List<String> wallpapers = List.of(ComputerDesktopState.DEFAULT_WALLPAPER.toString());
|
||||
private boolean desktopRequested;
|
||||
|
||||
+2
-1
@@ -144,8 +144,9 @@ public final class ComputerDesktopState {
|
||||
|
||||
public void load(CompoundTag tag) {
|
||||
clear();
|
||||
selectedWallpaper = parseId(tag.getString(SELECTED_WALLPAPER_TAG));
|
||||
loadIds(tag.getList(UNLOCKED_WALLPAPERS_TAG, 8), unlockedWallpaperIds, MAX_UNLOCKED_WALLPAPERS);
|
||||
ResourceLocation storedSelection = parseId(tag.getString(SELECTED_WALLPAPER_TAG));
|
||||
selectedWallpaper = storedSelection != null && unlockedWallpaperIds.contains(storedSelection) ? storedSelection : DEFAULT_WALLPAPER;
|
||||
loadIds(tag.getList(INSTALLED_PROGRAMS_TAG, 8), installedProgramIds, MAX_INSTALLED_PROGRAMS);
|
||||
ListTag positions = tag.getList(ICON_POSITIONS_TAG, 10);
|
||||
for (int index = 0; index < positions.size() && iconPositions.size() < MAX_ICON_POSITIONS; index++) {
|
||||
|
||||
+24
@@ -52,6 +52,15 @@ public final class ComputerFileSystem {
|
||||
return nodes.values().stream().filter(file -> file.type() == ComputerFile.Type.TEXT).toList();
|
||||
}
|
||||
|
||||
public Result createDirectory(String path) {
|
||||
String normalized = normalize(path);
|
||||
if (normalized.isEmpty() || ROOT.equals(normalized) || isProtected(normalized) || nodes.containsKey(normalized) || nodes.size() >= MAX_NODES) return Result.failure("invalid_path");
|
||||
int slash = normalized.lastIndexOf('/');
|
||||
if (slash > 0 && !nodesDirectory(normalized.substring(0, slash))) return Result.failure("missing_directory");
|
||||
nodes.put(normalized, ComputerFile.directory(normalized));
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
public Result createTextFile(String path, String contents) {
|
||||
String normalized = normalize(path);
|
||||
Result validation = validateTextPath(normalized, contents);
|
||||
@@ -83,6 +92,21 @@ public final class ComputerFileSystem {
|
||||
return nodes.containsKey(normalize(path)) ? writeTextFile(path, contents) : createTextFile(path, contents);
|
||||
}
|
||||
|
||||
public Result move(String source, String destination) {
|
||||
String from = normalize(source);
|
||||
String to = normalize(destination);
|
||||
if (from.isEmpty() || to.isEmpty() || ROOT.equals(from) || ROOT.equals(to) || isProtected(from) || isProtected(to)) return Result.failure("invalid_path");
|
||||
ComputerFile file = nodes.get(from);
|
||||
if (file == null) return Result.failure("not_found");
|
||||
if (nodes.containsKey(to)) return Result.failure("already_exists");
|
||||
int slash = to.lastIndexOf('/');
|
||||
if (slash > 0 && !nodesDirectory(to.substring(0, slash))) return Result.failure("missing_directory");
|
||||
if (file.type() == ComputerFile.Type.DIRECTORY && to.startsWith(from + "/")) return Result.failure("invalid_path");
|
||||
nodes.remove(from);
|
||||
nodes.put(to, file.type() == ComputerFile.Type.DIRECTORY ? ComputerFile.directory(to) : ComputerFile.text(to, file.contents()));
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
public Result delete(String path) {
|
||||
String normalized = normalize(path);
|
||||
if (isProtected(normalized)) return Result.failure("protected");
|
||||
|
||||
+2
-1
@@ -639,7 +639,8 @@ public final class CreativeTabContents {
|
||||
for (String potionPath : ANTARCHY_POTION_FAMILIES) {
|
||||
acceptPotionFamily(output, potionPath);
|
||||
}
|
||||
for (String diskId : List.of("antarchy:introduction", "antarchy:chronosphere", "antarchy:toreterror_arena", "antarchy:high_fructose_corn_syrup")) {
|
||||
for (String diskId : List.of("antarchy:introduction", "antarchy:chronosphere", "antarchy:toreterror_arena", "antarchy:high_fructose_corn_syrup",
|
||||
"antarchy:elythia", "antarchy:cavaryn", "antarchy:thoraxis", "antarchy:temporal_fields", "antarchy:bloodglass", "antarchy:vortex")) {
|
||||
ItemStack disk = new ItemStack(AntarchyObjects.FLOPPY_DISK.get());
|
||||
disk.set(AntarchyObjects.FLOPPY_DISK_COMPONENT.get(), ResourceLocation.parse(diskId));
|
||||
output.accept(disk);
|
||||
|
||||
+14
-5
@@ -1,5 +1,6 @@
|
||||
package com.craisinlord.antarchy.content.guide;
|
||||
|
||||
import com.craisinlord.antarchy.config.AntarchySettings;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
@@ -38,10 +39,16 @@ public final class ComputerGuideData extends SimplePreparableReloadListener<Comp
|
||||
}
|
||||
|
||||
public static List<Entry> entriesFor(List<ResourceLocation> diskIds) {
|
||||
if (AntarchySettings.unlockAllArchives()) {
|
||||
Map<ResourceLocation, Entry> result = new LinkedHashMap<>();
|
||||
result.put(INTRODUCTION, new Entry(INTRODUCTION, "article", "general", "guide.antarchy.entry.introduction.title", "guide.antarchy.entry.introduction.subtitle", List.of("guide.antarchy.entry.introduction.description"), "", "", "", ""));
|
||||
result.putAll(entries);
|
||||
return result.values().stream().sorted(Comparator.comparing(entry -> entry.titleKey().toString())).toList();
|
||||
}
|
||||
Map<ResourceLocation, Entry> result = new LinkedHashMap<>();
|
||||
for (ResourceLocation diskId : diskIds) {
|
||||
if (INTRODUCTION.equals(diskId)) {
|
||||
result.put(INTRODUCTION, new Entry(INTRODUCTION, "article", "general", "guide.antarchy.entry.introduction.title", "guide.antarchy.entry.introduction.subtitle", List.of("guide.antarchy.entry.introduction.description"), "", "", ""));
|
||||
result.put(INTRODUCTION, new Entry(INTRODUCTION, "article", "general", "guide.antarchy.entry.introduction.title", "guide.antarchy.entry.introduction.subtitle", List.of("guide.antarchy.entry.introduction.description"), "", "", "", ""));
|
||||
continue;
|
||||
}
|
||||
Disk disk = disks.get(diskId);
|
||||
@@ -107,9 +114,10 @@ public final class ComputerGuideData extends SimplePreparableReloadListener<Comp
|
||||
String subtitle = string(object, "subtitle", "");
|
||||
List<String> description = strings(object.get("description"));
|
||||
String item = string(object, "item", "");
|
||||
String entity = string(object, "entity", "");
|
||||
String structure = string(object, "structure", "");
|
||||
String dimension = string(object, "dimension", "");
|
||||
target.put(id, new Entry(id, type, category, title, subtitle, description, item, structure, dimension));
|
||||
target.put(id, new Entry(id, type, category, title, subtitle, description, item, entity, structure, dimension));
|
||||
}
|
||||
|
||||
private static void parseDisk(ResourceLocation id, JsonElement element, Map<ResourceLocation, Disk> target) {
|
||||
@@ -131,7 +139,8 @@ public final class ComputerGuideData extends SimplePreparableReloadListener<Comp
|
||||
}
|
||||
}
|
||||
}
|
||||
target.put(id, new Disk(id, category, title, List.copyOf(entryIds)));
|
||||
String wallpaper = string(object, "wallpaper", "");
|
||||
target.put(id, new Disk(id, category, title, List.copyOf(entryIds), wallpaper));
|
||||
}
|
||||
|
||||
private static String string(JsonObject object, String key, String fallback) {
|
||||
@@ -160,10 +169,10 @@ public final class ComputerGuideData extends SimplePreparableReloadListener<Comp
|
||||
}
|
||||
|
||||
public record Entry(ResourceLocation id, String type, String category, String titleKey, String subtitleKey,
|
||||
List<String> descriptionKeys, String itemId, String structureId, String dimensionId) {
|
||||
List<String> descriptionKeys, String itemId, String entityId, String structureId, String dimensionId) {
|
||||
}
|
||||
|
||||
public record Disk(ResourceLocation id, String category, String titleKey, List<ResourceLocation> entries) {
|
||||
public record Disk(ResourceLocation id, String category, String titleKey, List<ResourceLocation> entries, String wallpaper) {
|
||||
}
|
||||
|
||||
record LoadedData(Map<ResourceLocation, Entry> entries, Map<ResourceLocation, Disk> disks) {
|
||||
|
||||
+25
-1
@@ -69,6 +69,8 @@ public final class CavarynHordeManager {
|
||||
|
||||
private static final int GROUP_RADIUS_BLOCKS = 128;
|
||||
private static final int ATTENTION_THRESHOLD = 100;
|
||||
private static final int TIGERS_EYE_TRIGGER_LEVEL = 125;
|
||||
private static final ResourceLocation TIGERS_EYE_BLOCK = ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "tigers_eye_block");
|
||||
private static final int HOSTILE_KILL_ATTENTION = 4;
|
||||
private static final int MOB_KILL_ATTENTION = 3;
|
||||
private static final int EGG_OR_NEST_BREAK_ATTENTION = 5;
|
||||
@@ -129,7 +131,11 @@ public final class CavarynHordeManager {
|
||||
}
|
||||
|
||||
public static void recordBlockBreak(ServerPlayer player, BlockState brokenState, BlockPos pos) {
|
||||
if (!(player.level() instanceof ServerLevel level) || !level.dimension().equals(CAVARYN) || !hordesEnabled(level)) {
|
||||
if (!(player.level() instanceof ServerLevel level)) {
|
||||
return;
|
||||
}
|
||||
triggerTigersEyeBlockBreak(player, level, brokenState);
|
||||
if (!level.dimension().equals(CAVARYN) || !hordesEnabled(level)) {
|
||||
return;
|
||||
}
|
||||
if (!isValidHordeTarget(player) || !isHordeBiome(level, pos) || isPlayerInActiveEncounter(level, player)) {
|
||||
@@ -138,6 +144,24 @@ public final class CavarynHordeManager {
|
||||
addAttention(level, player, scaleActionAttention(level, isEggOrNest(brokenState) ? EGG_OR_NEST_BREAK_ATTENTION : BLOCK_BREAK_ATTENTION));
|
||||
}
|
||||
|
||||
private static void triggerTigersEyeBlockBreak(ServerPlayer player, ServerLevel level, BlockState brokenState) {
|
||||
if (!level.dimension().equals(CAVARYN)
|
||||
|| !hordesEnabled(level)
|
||||
|| !isValidHordeTarget(player)
|
||||
|| !BuiltInRegistries.BLOCK.getKey(brokenState.getBlock()).equals(TIGERS_EYE_BLOCK)) {
|
||||
return;
|
||||
}
|
||||
|
||||
HordeData data = get(level);
|
||||
PlayerAttention attention = data.players.computeIfAbsent(player.getUUID(), ignored -> new PlayerAttention());
|
||||
attention.attention = TIGERS_EYE_TRIGGER_LEVEL;
|
||||
attention.areaKey = areaKey(player.blockPosition());
|
||||
attention.areaTicks = 0;
|
||||
attention.lastSeenGameTime = level.getGameTime();
|
||||
data.setDirty();
|
||||
HordeIntensitySync.send(player, attention.attention / (float) ATTENTION_THRESHOLD);
|
||||
}
|
||||
|
||||
public static boolean isHordeBiome(ServerLevelAccessor level, BlockPos pos) {
|
||||
return level.getBiome(pos).is(AntarchyTags.Biomes.USES_HORDE_SYSTEM);
|
||||
}
|
||||
|
||||
+6
-4
@@ -30,12 +30,14 @@ public final class AntmailServerHandler {
|
||||
public static void handle(ServerPlayer player, AntmailSetupPayload payload) {
|
||||
ComputerBlockEntity computer = computer(player, payload.pos());
|
||||
if (computer == null || !computer.canUseFileSystem(player)) {
|
||||
result(player, payload.pos(), AntmailDeliveryResult.Status.FAILED.ordinal(), "", "", "unauthorized", "");
|
||||
result(player, payload.pos(), AntmailDeliveryResult.Status.FAILED.ordinal(), "", "", "registration_failed:unauthorized", "");
|
||||
return;
|
||||
}
|
||||
AntmailServerData data = AntmailServerData.access(player.server);
|
||||
AntmailServerData.Registration registration = data.register(player.server, player.serverLevel(), payload.pos(), payload.username());
|
||||
result(player, payload.pos(), registration.valid() ? AntmailDeliveryResult.Status.DELIVERED.ordinal() : AntmailDeliveryResult.Status.FAILED.ordinal(), registration.valid() ? registration.address().fullAddress() : "", "", registration.reason(), "");
|
||||
String mailbox = registration.valid() ? AntmailWire.encodeTag(data.mailboxOrCreate(registration.address()).toTag()) : "";
|
||||
String detail = registration.valid() ? "registration_success" : "registration_failed:" + registration.reason();
|
||||
result(player, payload.pos(), registration.valid() ? AntmailDeliveryResult.Status.DELIVERED.ordinal() : AntmailDeliveryResult.Status.FAILED.ordinal(), registration.valid() ? registration.address().fullAddress() : "", "", detail, mailbox);
|
||||
}
|
||||
|
||||
public static void handle(ServerPlayer player, AntmailStateRequestPayload payload) {
|
||||
@@ -71,7 +73,7 @@ public final class AntmailServerHandler {
|
||||
List<AntmailAttachment> attachments = AntmailWire.decodeAttachments(payload.attachments());
|
||||
AntmailMessage message = AntmailMessage.create(sender, recipient, payload.subject(), payload.body(), player.serverLevel().getGameTime(), attachments);
|
||||
AntmailDeliveryResult delivery = data.deliver(player.server, message);
|
||||
result(player, payload.pos(), delivery.status().ordinal(), recipient.fullAddress(), message.id().toString(), delivery.detail(), "");
|
||||
result(player, payload.pos(), delivery.status().ordinal(), sender.fullAddress(), message.id().toString(), delivery.detail(), AntmailWire.encodeTag(data.mailboxOrCreate(sender).toTag()));
|
||||
} catch (RuntimeException exception) {
|
||||
result(player, payload.pos(), AntmailDeliveryResult.Status.MESSAGE_INVALID.ordinal(), "", "", "invalid_message", "");
|
||||
}
|
||||
@@ -94,7 +96,7 @@ public final class AntmailServerHandler {
|
||||
AntmailMailbox mailbox = data.mailboxOrCreate(address);
|
||||
boolean changed = payload.read() ? mailbox.markRead(id) : markUnread(mailbox, id);
|
||||
if (changed) data.setDirty();
|
||||
result(player, payload.pos(), changed ? AntmailDeliveryResult.Status.DELIVERED.ordinal() : AntmailDeliveryResult.Status.FAILED.ordinal(), address.fullAddress(), payload.messageId(), changed ? "" : "not_found", "");
|
||||
result(player, payload.pos(), changed ? AntmailDeliveryResult.Status.DELIVERED.ordinal() : AntmailDeliveryResult.Status.FAILED.ordinal(), address.fullAddress(), payload.messageId(), changed ? "" : "not_found", AntmailWire.encodeTag(mailbox.toTag()));
|
||||
} catch (IllegalArgumentException exception) {
|
||||
result(player, payload.pos(), AntmailDeliveryResult.Status.FAILED.ordinal(), address.fullAddress(), payload.messageId(), "invalid_id", "");
|
||||
}
|
||||
|
||||
+89
@@ -2,6 +2,9 @@ package com.craisinlord.antarchy.content.network;
|
||||
|
||||
import com.craisinlord.antarchy.content.block.entity.ComputerBlockEntity;
|
||||
import com.craisinlord.antarchy.content.computer.ComputerFileSystem;
|
||||
import com.craisinlord.antarchy.content.computer.terminal.TerminalCommandService;
|
||||
import com.craisinlord.antarchy.content.computer.terminal.TerminalFileSystem;
|
||||
import com.craisinlord.antarchy.content.computer.terminal.TerminalResult;
|
||||
import com.craisinlord.antarchy.content.antmail.AntmailWire;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
@@ -51,6 +54,9 @@ public final class ComputerAccessHandler {
|
||||
case ComputerAccessPayload.FILE_OPEN -> fileOpen(player, computer, payload);
|
||||
case ComputerAccessPayload.FILE_CREATE -> fileCreate(player, computer, payload);
|
||||
case ComputerAccessPayload.FILE_SAVE -> fileSave(player, computer, payload);
|
||||
case ComputerAccessPayload.FILE_DELETE -> fileDelete(player, computer, payload);
|
||||
case ComputerAccessPayload.FILE_MOVE -> fileMove(player, computer, payload);
|
||||
case ComputerAccessPayload.TERMINAL_COMMAND -> terminalCommand(player, computer, payload);
|
||||
case ComputerAccessPayload.DESKTOP_STATE -> desktopState(player, computer, payload);
|
||||
case ComputerAccessPayload.DESKTOP_WALLPAPER -> desktopWallpaper(player, computer, payload);
|
||||
default -> send(player, payload, ComputerAccessResultPayload.INVALID);
|
||||
@@ -159,6 +165,89 @@ public final class ComputerAccessHandler {
|
||||
sendFile(player, payload, result.successful(), request[0], result.error());
|
||||
}
|
||||
|
||||
private static void fileDelete(ServerPlayer player, ComputerBlockEntity computer, ComputerAccessPayload payload) {
|
||||
if (!computer.canUseFileSystem(player)) {
|
||||
sendFile(player, payload, false, "", "unauthorized");
|
||||
return;
|
||||
}
|
||||
ComputerFileSystem.Result result = computer.fileSystem().delete(payload.value());
|
||||
if (result.successful()) computer.setChanged();
|
||||
sendFile(player, payload, result.successful(), payload.value(), result.error());
|
||||
}
|
||||
|
||||
private static void fileMove(ServerPlayer player, ComputerBlockEntity computer, ComputerAccessPayload payload) {
|
||||
if (!computer.canUseFileSystem(player)) {
|
||||
sendFile(player, payload, false, "", "unauthorized");
|
||||
return;
|
||||
}
|
||||
String[] request = splitFileRequest(payload.value());
|
||||
if (request == null) {
|
||||
sendFile(player, payload, false, "", "invalid_request");
|
||||
return;
|
||||
}
|
||||
ComputerFileSystem.Result result = computer.fileSystem().move(request[0], request[1]);
|
||||
if (result.successful()) computer.setChanged();
|
||||
sendFile(player, payload, result.successful(), request[1], result.error());
|
||||
}
|
||||
|
||||
private static void terminalCommand(ServerPlayer player, ComputerBlockEntity computer, ComputerAccessPayload payload) {
|
||||
if (!computer.canUseFileSystem(player)) {
|
||||
send(player, payload, ComputerAccessResultPayload.INVALID);
|
||||
return;
|
||||
}
|
||||
String[] request = splitFileRequest(payload.value());
|
||||
if (request == null) {
|
||||
sendTerminal(player, payload, TerminalResult.error("/", "ERROR: INVALID REQUEST"));
|
||||
return;
|
||||
}
|
||||
TerminalResult result = new TerminalCommandService().execute(new ComputerTerminalFileSystem(computer.fileSystem()), request[0], request[1]);
|
||||
if (result.status() != TerminalResult.Status.SUCCESS || !result.lines().isEmpty() || result.clearOutput() || result.openPath() != null) computer.setChanged();
|
||||
sendTerminal(player, payload, result);
|
||||
}
|
||||
|
||||
private static void sendTerminal(ServerPlayer player, ComputerAccessPayload payload, TerminalResult result) {
|
||||
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
|
||||
tag.putString("Directory", result.workingDirectory());
|
||||
tag.putBoolean("Clear", result.clearOutput());
|
||||
tag.putString("Open", result.openPath() == null ? "" : result.openPath());
|
||||
net.minecraft.nbt.ListTag lines = new net.minecraft.nbt.ListTag();
|
||||
for (String line : result.lines()) lines.add(net.minecraft.nbt.StringTag.valueOf(line));
|
||||
tag.put("Lines", lines);
|
||||
resultSender.accept(player, new ComputerAccessResultPayload(payload.pos(), result.status() == TerminalResult.Status.ERROR ? ComputerAccessResultPayload.INVALID : ComputerAccessResultPayload.SUCCESS,
|
||||
true, true, payload.action() + "\0" + AntmailWire.encodeTag(tag)));
|
||||
}
|
||||
|
||||
private static final class ComputerTerminalFileSystem implements TerminalFileSystem {
|
||||
private final ComputerFileSystem fileSystem;
|
||||
|
||||
private ComputerTerminalFileSystem(ComputerFileSystem fileSystem) { this.fileSystem = fileSystem; }
|
||||
|
||||
@Override public java.util.Optional<Entry> find(String path, String workingDirectory) {
|
||||
ComputerFileSystem.ComputerFile file = fileSystem.get(resolve(path, workingDirectory));
|
||||
return file == null ? java.util.Optional.empty() : java.util.Optional.of(new Entry(file.path(), file.path(), file.type() == ComputerFileSystem.ComputerFile.Type.DIRECTORY ? EntryType.DIRECTORY : EntryType.FILE));
|
||||
}
|
||||
@Override public java.util.List<Entry> list(String path, String workingDirectory) {
|
||||
String directory = resolve(path, workingDirectory);
|
||||
return fileSystem.list().stream().filter(file -> {
|
||||
String parent = file.path().lastIndexOf('/') <= 0 ? "/" : file.path().substring(0, file.path().lastIndexOf('/'));
|
||||
return parent.equals(directory) && !file.path().equals(directory);
|
||||
}).map(file -> new Entry(file.path().substring(file.path().lastIndexOf('/') + 1), file.path(), file.type() == ComputerFileSystem.ComputerFile.Type.DIRECTORY ? EntryType.DIRECTORY : EntryType.FILE)).toList();
|
||||
}
|
||||
@Override public boolean createDirectory(String path, String workingDirectory) { return fileSystem.createDirectory(resolve(path, workingDirectory)).successful(); }
|
||||
@Override public boolean createFile(String path, String workingDirectory) { return fileSystem.createTextFile(resolve(path, workingDirectory), "").successful(); }
|
||||
@Override public java.util.Optional<String> readText(String path, String workingDirectory) { ComputerFileSystem.ComputerFile file = fileSystem.get(resolve(path, workingDirectory)); return file != null && file.type() == ComputerFileSystem.ComputerFile.Type.TEXT ? java.util.Optional.of(file.contents()) : java.util.Optional.empty(); }
|
||||
@Override public boolean writeText(String path, String workingDirectory, String contents) { return fileSystem.createOrWriteTextFile(resolve(path, workingDirectory), contents).successful(); }
|
||||
@Override public boolean deleteFile(String path, String workingDirectory) { return fileSystem.delete(resolve(path, workingDirectory)).successful(); }
|
||||
@Override public boolean deleteEmptyDirectory(String path, String workingDirectory) { return fileSystem.delete(resolve(path, workingDirectory)).successful(); }
|
||||
@Override public boolean move(String source, String destination, String workingDirectory) { return fileSystem.move(resolve(source, workingDirectory), resolve(destination, workingDirectory)).successful(); }
|
||||
@Override public String normalize(String path, String workingDirectory) { return resolve(path, workingDirectory); }
|
||||
|
||||
private String resolve(String path, String workingDirectory) {
|
||||
if (path == null || path.isBlank()) return ComputerFileSystem.normalize(workingDirectory);
|
||||
return ComputerFileSystem.normalize(path.startsWith("/") ? path : ComputerFileSystem.normalize(workingDirectory) + "/" + path);
|
||||
}
|
||||
}
|
||||
|
||||
private static void desktopState(ServerPlayer player, ComputerBlockEntity computer, ComputerAccessPayload payload) {
|
||||
if (!computer.canUseFileSystem(player)) {
|
||||
sendDesktop(player, payload, false, "unauthorized");
|
||||
|
||||
+3
@@ -22,6 +22,9 @@ public record ComputerAccessPayload(BlockPos pos, int action, String value) impl
|
||||
public static final int FILE_SAVE = 10;
|
||||
public static final int DESKTOP_STATE = 11;
|
||||
public static final int DESKTOP_WALLPAPER = 12;
|
||||
public static final int FILE_DELETE = 13;
|
||||
public static final int FILE_MOVE = 14;
|
||||
public static final int TERMINAL_COMMAND = 15;
|
||||
public static final Type<ComputerAccessPayload> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(Antarchy.MODID, "computer_access"));
|
||||
public static final StreamCodec<RegistryFriendlyByteBuf, ComputerAccessPayload> STREAM_CODEC = StreamCodec.composite(
|
||||
BlockPos.STREAM_CODEC, ComputerAccessPayload::pos,
|
||||
|
||||
+12
@@ -60,6 +60,18 @@ public final class ComputerNetworking {
|
||||
sender.accept(new ComputerAccessPayload(pos, ComputerAccessPayload.FILE_SAVE, path + "\0" + contents));
|
||||
}
|
||||
|
||||
public static void deleteFile(BlockPos pos, String path) {
|
||||
sender.accept(new ComputerAccessPayload(pos, ComputerAccessPayload.FILE_DELETE, path));
|
||||
}
|
||||
|
||||
public static void moveFile(BlockPos pos, String source, String destination) {
|
||||
sender.accept(new ComputerAccessPayload(pos, ComputerAccessPayload.FILE_MOVE, source + "\0" + destination));
|
||||
}
|
||||
|
||||
public static void terminalCommand(BlockPos pos, String directory, String command) {
|
||||
sender.accept(new ComputerAccessPayload(pos, ComputerAccessPayload.TERMINAL_COMMAND, directory + "\0" + command));
|
||||
}
|
||||
|
||||
public static void requestDesktopState(BlockPos pos) {
|
||||
sender.accept(new ComputerAccessPayload(pos, ComputerAccessPayload.DESKTOP_STATE));
|
||||
}
|
||||
|
||||
@@ -1456,6 +1456,12 @@
|
||||
,"guide.antarchy.disk.chronosphere.title": "CHRONOSPHERE DATA"
|
||||
,"guide.antarchy.disk.toreterror_arena.title": "TORETERROR ARENA DATA"
|
||||
,"guide.antarchy.disk.high_fructose_corn_syrup.title": "CORN SYRUP DATA"
|
||||
,"guide.antarchy.disk.elythia.title": "ELYTHIA ACCESS RECORD"
|
||||
,"guide.antarchy.disk.cavaryn.title": "CAVARYN ACCESS RECORD"
|
||||
,"guide.antarchy.disk.thoraxis.title": "THORAXIS ACCESS RECORD"
|
||||
,"guide.antarchy.disk.temporal_fields.title": "TEMPORAL FIELDS MANUAL"
|
||||
,"guide.antarchy.disk.bloodglass.title": "BLOODGLASS SURVIVAL NOTES"
|
||||
,"guide.antarchy.disk.vortex.title": "VORTEX CONTROL NOTES"
|
||||
,"guide.antarchy.entry.introduction.title": "SYSTEM INITIALIZED"
|
||||
,"guide.antarchy.entry.introduction.subtitle": "A machine for remembering what should have stayed forgotten."
|
||||
,"guide.antarchy.entry.introduction.description": "Insert recovered floppy disks to expand this archive. The machine remembers. The machine does not forgive."
|
||||
@@ -1465,6 +1471,27 @@
|
||||
,"guide.antarchy.entry.toreterror_arena.title": "Toreterror Arena"
|
||||
,"guide.antarchy.entry.toreterror_arena.subtitle": "Structure location fragment"
|
||||
,"guide.antarchy.entry.toreterror_arena.description": "The nearest arena is rumored to lie beyond the current horizon. Directional analysis is pending in this prototype."
|
||||
,"guide.antarchy.entry.elythia.title": "Elythia"
|
||||
,"guide.antarchy.entry.elythia.subtitle": "Dimension and portal access record"
|
||||
,"guide.antarchy.entry.elythia.description": "Elythia is reached through an Elythia portal made with a valid frame. A sacrificed Brown Ant activates the portal. The dimension contains oceans, meadows, forests, coral spikes, and other surface biomes."
|
||||
,"guide.antarchy.entry.cavaryn.title": "Cavaryn"
|
||||
,"guide.antarchy.entry.cavaryn.subtitle": "Dimension and portal access record"
|
||||
,"guide.antarchy.entry.cavaryn.description": "Cavaryn is reached through a Cavaryn portal made with a valid frame. A sacrificed Termite activates the portal. The dimension is a deep network of caves, including Glowcap, Biowart, Moleworm, Wormy, and Brooding Tunnel regions."
|
||||
,"guide.antarchy.entry.thoraxis.title": "Thoraxis"
|
||||
,"guide.antarchy.entry.thoraxis.subtitle": "Dimension and portal access record"
|
||||
,"guide.antarchy.entry.thoraxis.description": "Thoraxis is reached through a Thoraxis portal made with a valid frame. A sacrificed Red Ant activates the portal. Its vertical progression includes Dream Dunes, Umbral Hills, Lucid Pools, and Nadir Forest."
|
||||
,"guide.antarchy.entry.temporal_fields.title": "Temporal Fields"
|
||||
,"guide.antarchy.entry.temporal_fields.subtitle": "Time dilation and Chronosphere reference"
|
||||
,"guide.antarchy.entry.temporal_fields.description": "Time Dilation and Time Contraction alter the rate of affected entities. Chronosphere armor creates a player-centered field at 35 percent rate; higher levels expand its radius."
|
||||
,"guide.antarchy.entry.bloodglass.title": "Bloodglass"
|
||||
,"guide.antarchy.entry.bloodglass.subtitle": "Reactive protection system"
|
||||
,"guide.antarchy.entry.bloodglass.description": "Blood Crystal armor grants Bloodglass Hearts that block an incoming hit, shatter, and recharge. Blood Crystal Apples grant temporary Bloodglass Ward, and the Katana provides launch, dash, and crimson-trail mobility."
|
||||
,"guide.antarchy.entry.vortex.title": "Vortex Systems"
|
||||
,"guide.antarchy.entry.vortex.subtitle": "Vortex Lens and Eye of the Storm reference"
|
||||
,"guide.antarchy.entry.vortex.description": "Redstone power pulls entities into a Vortex Lens beam while Bluestone power blasts them away. The Eye of the Storm launches an updraft and can hurl a homing tornado that carries foes."
|
||||
,"guide.antarchy.entry.nightmare.title": "Nightmare"
|
||||
,"guide.antarchy.entry.nightmare.subtitle": "Thoraxis hostile entity record"
|
||||
,"guide.antarchy.entry.nightmare.description": "A hostile entity recorded in the deepest Thoraxis regions. The recovered model is presented in monochrome archive mode."
|
||||
,"guide.antarchy.entry.high_fructose_corn_syrup.title": "High Fructose Corn Syrup"
|
||||
,"guide.antarchy.entry.high_fructose_corn_syrup.subtitle": "Nutritional and operational notes"
|
||||
,"guide.antarchy.entry.high_fructose_corn_syrup.description": "A sweet substance of uncertain strategic value. Doctoral enthusiasm surrounding it is statistically suspicious."
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"category": "thoraxis",
|
||||
"title": "guide.antarchy.disk.bloodglass.title",
|
||||
"entries": ["antarchy:bloodglass"],
|
||||
"wallpaper": "antarchy:bloodglass"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"category": "cavaryn",
|
||||
"title": "guide.antarchy.disk.cavaryn.title",
|
||||
"entries": ["antarchy:cavaryn"],
|
||||
"wallpaper": "antarchy:cavaryn"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"category": "elythia",
|
||||
"title": "guide.antarchy.disk.elythia.title",
|
||||
"entries": ["antarchy:elythia"],
|
||||
"wallpaper": "antarchy:elythia"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"category": "thoraxis",
|
||||
"title": "guide.antarchy.disk.temporal_fields.title",
|
||||
"entries": ["antarchy:temporal_fields"],
|
||||
"wallpaper": "antarchy:temporal_fields"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"category": "thoraxis",
|
||||
"title": "guide.antarchy.disk.thoraxis.title",
|
||||
"entries": ["antarchy:thoraxis", "antarchy:nightmare"],
|
||||
"wallpaper": "antarchy:thoraxis"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"category": "thoraxis",
|
||||
"title": "guide.antarchy.disk.vortex.title",
|
||||
"entries": ["antarchy:vortex"],
|
||||
"wallpaper": "antarchy:vortex"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"type": "article",
|
||||
"category": "thoraxis",
|
||||
"title": "guide.antarchy.entry.bloodglass.title",
|
||||
"subtitle": "guide.antarchy.entry.bloodglass.subtitle",
|
||||
"description": ["guide.antarchy.entry.bloodglass.description"]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"type": "dimension",
|
||||
"category": "cavaryn",
|
||||
"title": "guide.antarchy.entry.cavaryn.title",
|
||||
"subtitle": "guide.antarchy.entry.cavaryn.subtitle",
|
||||
"description": ["guide.antarchy.entry.cavaryn.description"],
|
||||
"dimension": "antarchy:cavaryn"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"type": "dimension",
|
||||
"category": "elythia",
|
||||
"title": "guide.antarchy.entry.elythia.title",
|
||||
"subtitle": "guide.antarchy.entry.elythia.subtitle",
|
||||
"description": ["guide.antarchy.entry.elythia.description"],
|
||||
"dimension": "antarchy:elythia"
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"type": "mob",
|
||||
"category": "thoraxis",
|
||||
"title": "guide.antarchy.entry.nightmare.title",
|
||||
"subtitle": "guide.antarchy.entry.nightmare.subtitle",
|
||||
"description": ["guide.antarchy.entry.nightmare.description"],
|
||||
"entity": "antarchy:nightmare"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"type": "article",
|
||||
"category": "thoraxis",
|
||||
"title": "guide.antarchy.entry.temporal_fields.title",
|
||||
"subtitle": "guide.antarchy.entry.temporal_fields.subtitle",
|
||||
"description": ["guide.antarchy.entry.temporal_fields.description"]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"type": "dimension",
|
||||
"category": "thoraxis",
|
||||
"title": "guide.antarchy.entry.thoraxis.title",
|
||||
"subtitle": "guide.antarchy.entry.thoraxis.subtitle",
|
||||
"description": ["guide.antarchy.entry.thoraxis.description"],
|
||||
"dimension": "antarchy:thoraxis"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"type": "article",
|
||||
"category": "thoraxis",
|
||||
"title": "guide.antarchy.entry.vortex.title",
|
||||
"subtitle": "guide.antarchy.entry.vortex.subtitle",
|
||||
"description": ["guide.antarchy.entry.vortex.description"]
|
||||
}
|
||||
+26
@@ -16,6 +16,32 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:floppy_disk",
|
||||
"weight": 4,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_components",
|
||||
"components": {
|
||||
"antarchy:floppy_disk": "antarchy:elythia"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:floppy_disk",
|
||||
"weight": 4,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_components",
|
||||
"components": {
|
||||
"antarchy:floppy_disk": "antarchy:cavaryn"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"type": "minecraft:chest",
|
||||
"pools": [
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:uranium_ingot",
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 1,
|
||||
"max": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:tigers_eye",
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 1,
|
||||
"max": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rolls": 1,
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "antarchy:titanium_nugget",
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"rolls": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 4
|
||||
},
|
||||
"entries": [
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:bone",
|
||||
"weight": 10,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:string",
|
||||
"weight": 10,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:coal",
|
||||
"weight": 8,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:torch",
|
||||
"weight": 8,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:rotten_flesh",
|
||||
"weight": 8,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "minecraft:item",
|
||||
"name": "minecraft:arrow",
|
||||
"weight": 6,
|
||||
"functions": [
|
||||
{
|
||||
"function": "minecraft:set_count",
|
||||
"count": {
|
||||
"type": "minecraft:uniform",
|
||||
"min": 2,
|
||||
"max": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"random_sequence": "antarchy:chests/tigers_eye_shrine/treasure"
|
||||
}
|
||||
+4
@@ -1,4 +1,8 @@
|
||||
{"type":"minecraft:chest","pools":[{"rolls":{"type":"minecraft:uniform","min":5,"max":8},"entries":[
|
||||
{"type":"minecraft:item","name":"antarchy:floppy_disk","weight":6,"functions":[{"function":"minecraft:set_components","components":{"antarchy:floppy_disk":"antarchy:thoraxis"}}]},
|
||||
{"type":"minecraft:item","name":"antarchy:floppy_disk","weight":5,"functions":[{"function":"minecraft:set_components","components":{"antarchy:floppy_disk":"antarchy:temporal_fields"}}]},
|
||||
{"type":"minecraft:item","name":"antarchy:floppy_disk","weight":5,"functions":[{"function":"minecraft:set_components","components":{"antarchy:floppy_disk":"antarchy:bloodglass"}}]},
|
||||
{"type":"minecraft:item","name":"antarchy:floppy_disk","weight":5,"functions":[{"function":"minecraft:set_components","components":{"antarchy:floppy_disk":"antarchy:vortex"}}]},
|
||||
{"type":"minecraft:item","name":"minecraft:arrow","weight":16,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":10,"max":28}}]},
|
||||
{"type":"minecraft:item","name":"minecraft:tipped_arrow","weight":9,"functions":[{"function":"minecraft:set_count","count":{"type":"minecraft:uniform","min":2,"max":6}},{"function":"minecraft:set_potion","id":"antarchy:inversion"}]},
|
||||
{"type":"minecraft:item","name":"minecraft:iron_pickaxe","weight":10},{"type":"minecraft:item","name":"minecraft:iron_sword","weight":8},
|
||||
|
||||
BIN
Binary file not shown.
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"#antarchy:is_cavaryn"
|
||||
]
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"type": "integrated_api:generic_structure",
|
||||
"start_pool": "antarchy:tigers_eye_shrine/tigers_eye_shrine",
|
||||
"size": 1,
|
||||
"terrain_height_radius_check": 4,
|
||||
"allowed_terrain_height_range": 14,
|
||||
"valid_biome_radius_check": 1,
|
||||
"biomes": "#antarchy:has_structure/tigers_eye_shrine_biomes",
|
||||
"step": "surface_structures",
|
||||
"enhanced_terrain_adaptation": {
|
||||
"type": "integrated_api:none"
|
||||
},
|
||||
"project_start_to_heightmap": "WORLD_SURFACE_WG",
|
||||
"start_height": {
|
||||
"type": "minecraft:constant",
|
||||
"value": {
|
||||
"absolute": 0
|
||||
}
|
||||
},
|
||||
"spawn_overrides": {},
|
||||
"liquid_settings": "ignore_waterlogging"
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"structures": [
|
||||
{
|
||||
"structure": "antarchy:tigers_eye_shrine",
|
||||
"weight": 1
|
||||
}
|
||||
],
|
||||
"placement": {
|
||||
"salt": 149275031,
|
||||
"spacing": 24,
|
||||
"separation": 16,
|
||||
"type": "integrated_api:advanced_random_spread"
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "antarchy:tigers_eye_shrine/tigers_eye_shrine",
|
||||
"fallback": "minecraft:empty",
|
||||
"elements": [
|
||||
{
|
||||
"weight": 1,
|
||||
"element": {
|
||||
"location": "antarchy:tigers_eye_shrine/tigers_eye_shrine",
|
||||
"processors": "antarchy:generic_processor",
|
||||
"projection": "rigid",
|
||||
"enhanced_terrain_adaptation": {
|
||||
"type": "integrated_api:custom",
|
||||
"carves": true,
|
||||
"beards": true,
|
||||
"kernel_size": 35,
|
||||
"kernel_distance": 35
|
||||
},
|
||||
"element_type": "integrated_api:integrated_api_single_pool_element"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user