diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d7ab3b31..d0c5254f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: build on: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0bf6438f..3a9660a1 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,3 +1,4 @@ +#file: noinspection UndefinedAction,UndefinedParamsPresent name: publish on: diff --git a/.gitignore b/.gitignore index 1c1a301a..57d7ad86 100644 --- a/.gitignore +++ b/.gitignore @@ -34,7 +34,7 @@ forge*changelog.txt #vscode .vscode -#libs/ +libs/*.jar # Don't ignore bin from scripts !/src/main/scripts/bin/ diff --git a/build.gradle b/build.gradle index f6602bfd..ee4a0c32 100644 --- a/build.gradle +++ b/build.gradle @@ -8,14 +8,15 @@ plugins { } apply plugin: 'org.spongepowered.mixin' -apply from: "minecraft.gradle" apply plugin: "java" jarJar.enable() allprojects { gradle.projectsEvaluated { - tasks.withType(JavaCompile) { - options.compilerArgs << "-Xmaxerrs" << "1000" + tasks.withType(JavaCompile).tap { + configureEach { + options.compilerArgs << "-Xmaxerrs" << "1000" + } } } } @@ -98,7 +99,6 @@ dependencies { minecraftLibrary "org.apache.commons:commons-collections4:4.4" implementation fg.deobf("curse.maven:architectury-api-419699:5137938") - implementation fg.deobf("curse.maven:markdownmanual-502485:4873115") compileOnly fg.deobf("mezz.jei:jei-1.20.1-common-api:15.3.0.4") @@ -137,16 +137,16 @@ dependencies { System.setProperty("line.separator", "\n") -task packageScripts(type: Zip) { +tasks.register('packageScripts', Zip) { archiveFileName = "scripts.zip" - destinationDirectory = file("$buildDir/resources/main/data/oc2r/file_systems") + destinationDirectory = file("${layout.buildDirectory.get()}/resources/main/data/oc2r/file_systems") from "src/main/scripts" filter { line -> line } } -task copyLicensesToResources(type: Copy) { +tasks.register('copyLicensesToResources', Copy) { from "." - into file("$buildDir/resources/main") + into file("${layout.buildDirectory.get()}/resources/main") include "LICENSE*" } @@ -162,7 +162,7 @@ minecraft { accessTransformer = file("src/main/resources/META-INF/accesstransformer.cfg") runs { - all { + configureEach { property "forge.logging.markers", "REGISTRIES" property "forge.logging.console.level", "debug" @@ -203,7 +203,7 @@ mixin { // quiet } -task copyGeneratedResources(type: Copy) { +tasks.register('copyGeneratedResources', Copy) { from "src/generated" into "src/main" exclude "resources/.cache" @@ -228,7 +228,7 @@ jar { } } -task apiJar(type: Jar) { +tasks.register('apiJar', Jar) { archiveClassifier.set("api") from sourceSets.main.allSource from sourceSets.main.output @@ -239,29 +239,6 @@ artifacts { archives apiJar } -publishing { - publications { - mavenJava(MavenPublication) { - groupId = project.group - artifactId = project.name - version = semver - artifact jar - artifact apiJar - jarJar.component(it) - } - } - repositories { - maven { - name = "GitHubPackages" - url = System.getenv("GITHUB_MAVEN_URL") ?: "" - credentials { - username = System.getenv("GITHUB_ACTOR") - password = System.getenv("GITHUB_TOKEN") - } - } - } -} - curseforge { apiKey = System.getenv("CURSEFORGE_API_KEY") ?: "" project { diff --git a/gradle.properties b/gradle.properties index e0b02713..41aada2f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,9 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -forge_version=47.3.0 +forge_version=47.3.38 +minecraft_version = 1.20.1 +minecraft_sdk = forge semver=0.0.0 diff --git a/libs/gitignore b/libs/gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/libs/gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/minecraft.gradle b/minecraft.gradle deleted file mode 100644 index 073b4683..00000000 --- a/minecraft.gradle +++ /dev/null @@ -1,4 +0,0 @@ -ext { - minecraft_version = '1.20.1' - minecraft_sdk = 'forge' -} diff --git a/settings.gradle b/settings.gradle index b1c88ce2..0984aa77 100644 --- a/settings.gradle +++ b/settings.gradle @@ -5,12 +5,10 @@ pluginManagement { maven { url "https://repo.spongepowered.org/repository/maven-public/" } } } - -apply from: 'minecraft.gradle' rootProject.name = "oc2r-${minecraft_version}-${minecraft_sdk}" def substituteLocal(final directoryName, final libraryName) { - final def path = new File("../${directoryName}"); + final def path = new File("../${directoryName}") if (path.exists()) { println("Found local [${directoryName}] project, substituting...") includeBuild(path) { diff --git a/src/main/java/li/cil/oc2/api/bus/device/DeviceType.java b/src/main/java/li/cil/oc2/api/bus/device/DeviceType.java index fbd949a0..3775ddc4 100644 --- a/src/main/java/li/cil/oc2/api/bus/device/DeviceType.java +++ b/src/main/java/li/cil/oc2/api/bus/device/DeviceType.java @@ -21,7 +21,7 @@ public interface DeviceType { /** * The registry name of the registry holding device types. */ - ResourceKey> REGISTRY = ResourceKey.createRegistryKey(new ResourceLocation(API.MOD_ID, "device_type")); + ResourceKey> REGISTRY = ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "device_type")); /** * The tag representing this device type. diff --git a/src/main/java/li/cil/oc2/api/bus/device/DeviceTypes.java b/src/main/java/li/cil/oc2/api/bus/device/DeviceTypes.java index b21632b1..96157012 100644 --- a/src/main/java/li/cil/oc2/api/bus/device/DeviceTypes.java +++ b/src/main/java/li/cil/oc2/api/bus/device/DeviceTypes.java @@ -9,16 +9,17 @@ import net.minecraftforge.registries.RegistryObject; /** * Lists built-in device types for convenience. */ +@SuppressWarnings("unused") public final class DeviceTypes { - public static final DeviceType MEMORY = (DeviceType) RegistryObject.create(new ResourceLocation(API.MOD_ID, "memory"), new ResourceLocation(API.MOD_ID, "device_type"), API.MOD_ID).get(); + public static final DeviceType MEMORY = (DeviceType) RegistryObject.create(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "memory"), ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "device_type"), API.MOD_ID).get(); - public static final DeviceType HARD_DRIVE = (DeviceType) RegistryObject.create(new ResourceLocation(API.MOD_ID, "hard_drive"), new ResourceLocation(API.MOD_ID, "device_type"), API.MOD_ID).get(); + public static final DeviceType HARD_DRIVE = (DeviceType) RegistryObject.create(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "hard_drive"), ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "device_type"), API.MOD_ID).get(); - public static final DeviceType FLASH_MEMORY = (DeviceType) RegistryObject.create(new ResourceLocation(API.MOD_ID, "flash_memory"), new ResourceLocation(API.MOD_ID, "device_type"), API.MOD_ID).get(); - public static final DeviceType CARD = (DeviceType) RegistryObject.create(new ResourceLocation(API.MOD_ID, "card"), new ResourceLocation(API.MOD_ID, "device_type"), API.MOD_ID).get(); - public static final DeviceType ROBOT_MODULE = (DeviceType) RegistryObject.create(new ResourceLocation(API.MOD_ID, "robot_module"), new ResourceLocation(API.MOD_ID, "device_type"), API.MOD_ID).get(); + public static final DeviceType FLASH_MEMORY = (DeviceType) RegistryObject.create(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "flash_memory"), ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "device_type"), API.MOD_ID).get(); + public static final DeviceType CARD = (DeviceType) RegistryObject.create(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "card"), ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "device_type"), API.MOD_ID).get(); + public static final DeviceType ROBOT_MODULE = (DeviceType) RegistryObject.create(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "robot_module"), ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "device_type"), API.MOD_ID).get(); - public static final DeviceType FLOPPY = (DeviceType) RegistryObject.create(new ResourceLocation(API.MOD_ID, "floppy"), new ResourceLocation(API.MOD_ID, "device_type"), API.MOD_ID).get(); - public static final DeviceType NETWORK_TUNNEL = (DeviceType) RegistryObject.create(new ResourceLocation(API.MOD_ID, "network_tunnel"), new ResourceLocation(API.MOD_ID, "device_type"), API.MOD_ID).get(); - public static final DeviceType CPU = (DeviceType) RegistryObject.create(new ResourceLocation(API.MOD_ID, "cpu"), new ResourceLocation(API.MOD_ID, "device_type"), API.MOD_ID).get(); + public static final DeviceType FLOPPY = (DeviceType) RegistryObject.create(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "floppy"), ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "device_type"), API.MOD_ID).get(); + public static final DeviceType NETWORK_TUNNEL = (DeviceType) RegistryObject.create(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "network_tunnel"), ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "device_type"), API.MOD_ID).get(); + public static final DeviceType CPU = (DeviceType) RegistryObject.create(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "cpu"), ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "device_type"), API.MOD_ID).get(); } diff --git a/src/main/java/li/cil/oc2/api/util/Registries.java b/src/main/java/li/cil/oc2/api/util/Registries.java index 3d01cdb0..fdd9fd0b 100644 --- a/src/main/java/li/cil/oc2/api/util/Registries.java +++ b/src/main/java/li/cil/oc2/api/util/Registries.java @@ -38,6 +38,6 @@ public final class Registries { /////////////////////////////////////////////////////////////////// private static ResourceKey> key(final String name) { - return ResourceKey.createRegistryKey(new ResourceLocation(API.MOD_ID, name)); + return ResourceKey.createRegistryKey(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, name)); } } diff --git a/src/main/java/li/cil/oc2/client/ClientSetup.java b/src/main/java/li/cil/oc2/client/ClientSetup.java index 0fa3d85d..05bfe530 100644 --- a/src/main/java/li/cil/oc2/client/ClientSetup.java +++ b/src/main/java/li/cil/oc2/client/ClientSetup.java @@ -16,18 +16,18 @@ import li.cil.oc2.common.block.Blocks; import li.cil.oc2.common.blockentity.BlockEntities; import li.cil.oc2.common.container.Containers; import li.cil.oc2.common.entity.Entities; -import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.MenuScreens; -import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; import net.minecraftforge.client.event.EntityRenderersEvent; import net.minecraftforge.client.event.ModelEvent.RegisterGeometryLoaders; +import net.minecraftforge.client.event.RegisterColorHandlersEvent; import net.minecraftforge.client.event.RenderGuiOverlayEvent; import net.minecraftforge.client.gui.overlay.VanillaGuiOverlay; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +@SuppressWarnings("unused") public final class ClientSetup { @SubscribeEvent public static void handleSetupEvent(final FMLClientSetupEvent event) { @@ -51,10 +51,6 @@ public final class ClientSetup { MenuScreens.register(Containers.ROBOT_TERMINAL.get(), RobotTerminalScreen::new); MenuScreens.register(Containers.NETWORK_TUNNEL.get(), NetworkTunnelScreen::new); - //noinspection deprecation - ItemBlockRenderTypes.setRenderLayer(Blocks.BUS_CABLE.get(), renderType -> true); - Minecraft.getInstance().getBlockColors().register(new BusCableBlockColor(), Blocks.BUS_CABLE.get()); - // We need to register this manually, because static init throws errors when running data generation. MinecraftForge.EVENT_BUS.register(ProjectorDepthRenderer.class); }); @@ -74,6 +70,11 @@ public final class ClientSetup { } } + @SubscribeEvent + public static void handleColorHandler(final RegisterColorHandlersEvent.Block event) { + event.register(new BusCableBlockColor(), Blocks.BUS_CABLE.get()); + } + @SubscribeEvent public static void handleEntityRendererRegisterEvent(final EntityRenderersEvent.RegisterRenderers event) { event.registerEntityRenderer(Entities.ROBOT.get(), RobotRenderer::new); diff --git a/src/main/java/li/cil/oc2/client/gui/AbstractMachineTerminalScreen.java b/src/main/java/li/cil/oc2/client/gui/AbstractMachineTerminalScreen.java index 8e1c2c8a..e1832272 100644 --- a/src/main/java/li/cil/oc2/client/gui/AbstractMachineTerminalScreen.java +++ b/src/main/java/li/cil/oc2/client/gui/AbstractMachineTerminalScreen.java @@ -30,7 +30,8 @@ public abstract class AbstractMachineTerminalScreen getExtraAreas() { final List list = new ArrayList<>(); list.add(new Rect2i( @@ -81,14 +78,27 @@ public abstract class AbstractMachineTerminalScreen { + if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.SGR_MOUSE)) { + terminal.putInput("\033[<" + button + ";" + position.x + ";" + position.y + "M"); + return true; + } + else if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.UTF8_MOUSE)) + { + byte[] csiMBytes = "\033[M".getBytes(StandardCharsets.UTF_8); + byte[] buttonBytes = utf8(button + 32); + byte[] colBytes = utf8(position.x + 32); + byte[] rowBytes = utf8(position.y + 32); + byte[] finalBytes = new byte[csiMBytes.length + buttonBytes.length + colBytes.length + rowBytes.length]; + + System.arraycopy(csiMBytes, 0, finalBytes, 0, csiMBytes.length); + System.arraycopy(buttonBytes, 0, finalBytes, csiMBytes.length, buttonBytes.length); + System.arraycopy(colBytes, 0, finalBytes, csiMBytes.length + buttonBytes.length, colBytes.length); + System.arraycopy(rowBytes, 0, finalBytes, csiMBytes.length + buttonBytes.length + colBytes.length, rowBytes.length); + + terminal.putInput(ByteBuffer.wrap(finalBytes)); + return true; + } + else if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.URXVT_MOUSE)) + { + terminal.putInput("\033[" + (button + 32) + ";" + position.x + ";" + position.y + "M"); + } + else + { + terminal.putInput('\033'); + terminal.putInput('['); + terminal.putInput('M'); + terminal.putInput((byte) (button + 32)); + terminal.putInput((byte) (position.x + 32)); + terminal.putInput((byte) (position.y + 32)); + return true; + } + } + default -> System.out.println("ERR: Unsupported primary mode"); + } } return false; } public boolean mouseReleased(double x, double y, int button) { - int mx = (int) x; - int my = (int) y; - int sx = (int)((x - MachineTerminalWidget.TERMINAL_X) / MachineTerminalWidget.TERMINAL_WIDTH * Terminal.WIDTH); - int sy = (int)((y - MachineTerminalWidget.TERMINAL_Y) / MachineTerminalWidget.TERMINAL_HEIGHT * Terminal.HEIGHT); - boolean overTerminal = isMouseOverTerminal(mx, my); + MouseMode currentMouseMode = terminal.currentPrivateModeState.getMouseMode(); + if (currentMouseMode.isMouseDisabled()) return false; + Vector2i position = getMousePosition(x, y); + boolean overTerminal = isMouseOverTerminal((int)x, (int)y); if (overTerminal && shouldCaptureInput()) { - // terminal.putInput((byte) 0x1b); - // terminal.putInput((byte) '['); - // terminal.putInput((byte) 3); - // terminal.putInput((byte) sx); - // terminal.putInput((byte) sy); - return true; + switch(currentMouseMode.PrimaryMode) { + case PrivateMode.X11MM, PrivateMode.CELL_MOTION_MOUSE -> { + if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.SGR_MOUSE)) { + terminal.putInput("\033[<" + button + ";" + position.x + ";" + position.y + "m"); + return true; + } + else if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.UTF8_MOUSE)) + { + byte[] csiMBytes = "\033[M".getBytes(StandardCharsets.UTF_8); + byte[] buttonBytes = utf8(35); + byte[] colBytes = utf8(position.x + 32); + byte[] rowBytes = utf8(position.y + 32); + byte[] finalBytes = new byte[csiMBytes.length + buttonBytes.length + colBytes.length + rowBytes.length]; + + System.arraycopy(csiMBytes, 0, finalBytes, 0, csiMBytes.length); + System.arraycopy(buttonBytes, 0, finalBytes, csiMBytes.length, buttonBytes.length); + System.arraycopy(colBytes, 0, finalBytes, csiMBytes.length + buttonBytes.length, colBytes.length); + System.arraycopy(rowBytes, 0, finalBytes, csiMBytes.length + buttonBytes.length + colBytes.length, rowBytes.length); + + terminal.putInput(ByteBuffer.wrap(finalBytes)); + return true; + } + else if (currentMouseMode.isSecondaryModeEnabled(PrivateMode.URXVT_MOUSE)) + { + terminal.putInput("\033[" + 35 + ";" + position.x + ";" + position.y + "M"); + } + else + { + terminal.putInput('\033'); + terminal.putInput('['); + terminal.putInput('M'); + terminal.putInput((byte) 35); + terminal.putInput((byte) (position.x + 32)); + terminal.putInput((byte) (position.y + 32)); + return true; + } + } + default -> System.out.println("ERR: Unsupported primary mode"); + } } return false; } + private byte[] utf8(int value) { + return new String(new int[]{value}, 0, 1).getBytes(StandardCharsets.UTF_8); + } + + private Vector2i getMousePosition(double x, double y) { + int tx = TERMINAL_WIDTH / Terminal.WIDTH; + int ty = TERMINAL_HEIGHT / Terminal.HEIGHT; + int sx = (int)(((x - leftPos) - MachineTerminalWidget.TERMINAL_X) / tx) + 1; + int sy = (int)(((y - topPos) - MachineTerminalWidget.TERMINAL_Y) / ty) + 1; + + return new Vector2i(sx, sy); + } + public boolean charTyped(final char ch, final int modifier) { if (modifier == 0 || modifier == GLFW.GLFW_MOD_SHIFT) { terminal.putInput((byte) ch); @@ -158,6 +250,7 @@ public final class MachineTerminalWidget { return true; } + @SuppressWarnings("unused") public boolean keyPressed(final int keyCode, final int scanCode, final int modifiers) { if (!shouldCaptureInput() && keyCode == GLFW.GLFW_KEY_ESCAPE) { return false; @@ -165,11 +258,17 @@ public final class MachineTerminalWidget { if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0 && keyCode == GLFW.GLFW_KEY_V) { final String value = getClient().keyboardHandler.getClipboard(); + boolean bracketed = terminal.currentPrivateModeState.SET_BRACKETED_PASTE; + if(bracketed) terminal.putInput("\033[200~"); for (final char ch : value.toCharArray()) { terminal.putInput((byte) ch); } + if(bracketed) terminal.putInput("\033[201~"); } else { - final byte[] sequence = TerminalInput.getSequence(keyCode, modifiers); + byte[] sequence; + if (terminal.currentPrivateModeState.DECCKM && (keyCode == GLFW.GLFW_KEY_UP || keyCode == GLFW.GLFW_KEY_DOWN || keyCode == GLFW.GLFW_KEY_LEFT || keyCode == GLFW.GLFW_KEY_RIGHT)) + sequence = TerminalInput.getDECCKMSequence(keyCode, modifiers); + else sequence = TerminalInput.getSequence(keyCode, modifiers); if (sequence != null) { for (final byte b : sequence) { terminal.putInput(b); @@ -183,12 +282,9 @@ public final class MachineTerminalWidget { public void init() { this.leftPos = (parent.width - WIDTH) / 2; this.topPos = (parent.height - HEIGHT) / 2; - - //getClient().keyboardHandler.setSendRepeatsToGui(true); } public void onClose() { - //getClient().keyboardHandler.setSendRepeatsToGui(false); if (rendererView != null) { terminal.releaseRenderer(rendererView); rendererView = null; @@ -202,7 +298,7 @@ public final class MachineTerminalWidget { } private boolean shouldCaptureInput() { - return isMouseOverTerminal && AbstractMachineTerminalScreen.isInputCaptureEnabled() && + return isMouseOverTerminal && isInputCaptureEnabled && container.getVirtualMachine().isRunning(); } diff --git a/src/main/java/li/cil/oc2/client/gui/MonitorDisplayWidget.java b/src/main/java/li/cil/oc2/client/gui/MonitorDisplayWidget.java index 8f9a785d..f079b492 100644 --- a/src/main/java/li/cil/oc2/client/gui/MonitorDisplayWidget.java +++ b/src/main/java/li/cil/oc2/client/gui/MonitorDisplayWidget.java @@ -9,7 +9,7 @@ import li.cil.oc2.common.bus.device.vm.block.MonitorDevice; import li.cil.oc2.common.container.AbstractMonitorContainer; import li.cil.oc2.common.network.Network; import li.cil.oc2.common.network.message.MonitorInputMessage; -import li.cil.oc2.common.vm.Terminal; +import li.cil.oc2.common.vm.terminal.Terminal; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; @@ -24,6 +24,8 @@ import javax.annotation.Nullable; @OnlyIn(Dist.CLIENT) public final class MonitorDisplayWidget { + public boolean isInputCaptureEnabled; + private static final int TERMINAL_WIDTH = Terminal.WIDTH * Terminal.CHAR_WIDTH / 2; private static final int TERMINAL_HEIGHT = Terminal.HEIGHT * Terminal.CHAR_HEIGHT / 2; @@ -55,7 +57,7 @@ public final class MonitorDisplayWidget { Sprites.MONITOR_SCREEN.draw(graphics, leftPos, topPos); if (shouldCaptureInput()) { - Sprites.TERMINAL_FOCUSED.draw(graphics, leftPos, topPos); + Sprites.MONITOR_FOCUSED.draw(graphics, leftPos, topPos); } } @@ -142,7 +144,7 @@ public final class MonitorDisplayWidget { } private boolean shouldCaptureInput() { - return isMouseOverTerminal && AbstractMachineTerminalScreen.isInputCaptureEnabled(); + return isMouseOverTerminal && isInputCaptureEnabled; } private boolean isMouseOverTerminal(final int mouseX, final int mouseY) { diff --git a/src/main/java/li/cil/oc2/client/gui/Sprites.java b/src/main/java/li/cil/oc2/client/gui/Sprites.java index 0e27f8f2..dfa67695 100644 --- a/src/main/java/li/cil/oc2/client/gui/Sprites.java +++ b/src/main/java/li/cil/oc2/client/gui/Sprites.java @@ -15,6 +15,7 @@ public final class Sprites { public static final Sprite NETWORK_INTERFACE_CARD_SCREEN = new Sprite(NETWORK_INTERFACE_CARD_SCREEN_TEXTURE); public static final Sprite NETWORK_TUNNEL_SCREEN = new Sprite(NETWORK_TUNNEL_SCREEN_TEXTURE); + public static final Sprite MONITOR_FOCUSED = new Sprite(MONITOR_FOCUSED_TEXTURE); public static final Sprite TERMINAL_FOCUSED = new Sprite(TERMINAL_FOCUSED_TEXTURE); public static final Sprite SLOT_SELECTION = new Sprite(SLOT_SELECTION_TEXTURE, 18, 18, 0, 0); public static final Sprite INFO_ICON = new Sprite(INFO_ICON_TEXTURE); diff --git a/src/main/java/li/cil/oc2/client/gui/Textures.java b/src/main/java/li/cil/oc2/client/gui/Textures.java index 37629866..f05a09ad 100644 --- a/src/main/java/li/cil/oc2/client/gui/Textures.java +++ b/src/main/java/li/cil/oc2/client/gui/Textures.java @@ -13,6 +13,7 @@ public final class Textures { public static final Texture NETWORK_INTERFACE_CARD_SCREEN_TEXTURE = new Texture("textures/gui/widget/network_interface_card_screen.png", 176, 130); public static final Texture NETWORK_TUNNEL_SCREEN_TEXTURE = new Texture("textures/gui/widget/network_tunnel_screen.png", 176, 197); + public static final Texture MONITOR_FOCUSED_TEXTURE = new Texture("textures/gui/overlay/monitor_focused.png", 265, 208); public static final Texture TERMINAL_FOCUSED_TEXTURE = new Texture("textures/gui/overlay/terminal_focused.png", 336, 208); public static final Texture SLOT_SELECTION_TEXTURE = new Texture("textures/gui/overlay/slot_selection.png", 18, 270); public static final Texture INFO_ICON_TEXTURE = new Texture("textures/gui/overlay/slot_info.png", 28, 28); diff --git a/src/main/java/li/cil/oc2/client/gui/terminal/TerminalInput.java b/src/main/java/li/cil/oc2/client/gui/terminal/TerminalInput.java index d3bf4797..9a1f1d20 100644 --- a/src/main/java/li/cil/oc2/client/gui/terminal/TerminalInput.java +++ b/src/main/java/li/cil/oc2/client/gui/terminal/TerminalInput.java @@ -9,6 +9,7 @@ import javax.annotation.Nullable; public final class TerminalInput { private static final Int2ObjectArrayMap> KEYCODE_SEQUENCES = new Int2ObjectArrayMap<>(); + private static final Int2ObjectArrayMap> DECCKM_KEYCODE_SEQUENCES = new Int2ObjectArrayMap<>(); static { addSequence(GLFW.GLFW_KEY_ENTER, '\r'); @@ -71,6 +72,11 @@ public final class TerminalInput { addSequence(GLFW.GLFW_MOD_CONTROL | GLFW.GLFW_MOD_SHIFT, GLFW.GLFW_KEY_BACKSLASH, (byte) '\034'); addSequence(GLFW.GLFW_MOD_CONTROL, GLFW.GLFW_KEY_RIGHT_BRACKET, (byte) '\035'); addSequence(GLFW.GLFW_MOD_CONTROL | GLFW.GLFW_MOD_SHIFT, GLFW.GLFW_KEY_RIGHT_BRACKET, (byte) '\035'); + + addDECCKMSequence(GLFW.GLFW_KEY_UP, "\033OA"); + addDECCKMSequence(GLFW.GLFW_KEY_DOWN, "\033OB"); + addDECCKMSequence(GLFW.GLFW_KEY_RIGHT, "\033OC"); + addDECCKMSequence(GLFW.GLFW_KEY_LEFT, "\033OD"); } /////////////////////////////////////////////////////////////////// @@ -91,6 +97,22 @@ public final class TerminalInput { /////////////////////////////////////////////////////////////////// + @Nullable + public static byte[] getDECCKMSequence(final int keyCode) { + return getDECCKMSequence(keyCode, 0); + } + + @Nullable + public static byte[] getDECCKMSequence(final int keyCode, final int modifiers) { + final Int2ObjectArrayMap map = DECCKM_KEYCODE_SEQUENCES.get(modifiers); + if (map == null) { + return null; + } + return map.get(keyCode); + } + + /////////////////////////////////////////////////////////////////// + private static void addSequence(final int keyCode, final char ch) { addSequence(keyCode, (byte) ch); } @@ -117,4 +139,33 @@ public final class TerminalInput { .computeIfAbsent(modifiers, i -> new Int2ObjectArrayMap<>()) .put(keyCode, sequence); } + + /////////////////////////////////////////////////////////////////// + + private static void addDECCKMSequence(final int keyCode, final char ch) { + addDECCKMSequence(keyCode, (byte) ch); + } + + private static void addDECCKMSequence(final int keyCode, final byte... sequence) { + addDECCKMSequence(0, keyCode, sequence); + } + + private static void addDECCKMSequence(final int keyCode, final String sequence) { + addDECCKMSequence(0, keyCode, sequence); + } + + private static void addDECCKMSequence(final int modifiers, final int keyCode, final String sequence) { + final byte[] bytes = new byte[sequence.length()]; + final char[] chars = sequence.toCharArray(); + for (int i = 0; i < chars.length; i++) { + bytes[i] = (byte) chars[i]; + } + addDECCKMSequence(modifiers, keyCode, bytes); + } + + private static void addDECCKMSequence(final int modifiers, final int keyCode, final byte... sequence) { + DECCKM_KEYCODE_SEQUENCES + .computeIfAbsent(modifiers, i -> new Int2ObjectArrayMap<>()) + .put(keyCode, sequence); + } } diff --git a/src/main/java/li/cil/oc2/client/gui/widget/Texture.java b/src/main/java/li/cil/oc2/client/gui/widget/Texture.java index 62bdb6b5..b280b6c6 100644 --- a/src/main/java/li/cil/oc2/client/gui/widget/Texture.java +++ b/src/main/java/li/cil/oc2/client/gui/widget/Texture.java @@ -10,7 +10,7 @@ public final class Texture { public final int width, height; public Texture(final String location, final int width, final int height) { - this(new ResourceLocation(API.MOD_ID, location), width, height); + this(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, location), width, height); } public Texture(final ResourceLocation location, final int width, final int height) { diff --git a/src/main/java/li/cil/oc2/client/item/CustomItemColors.java b/src/main/java/li/cil/oc2/client/item/CustomItemColors.java index 6178db40..4cfd31b8 100644 --- a/src/main/java/li/cil/oc2/client/item/CustomItemColors.java +++ b/src/main/java/li/cil/oc2/client/item/CustomItemColors.java @@ -10,6 +10,7 @@ import net.minecraft.world.item.DyeableLeatherItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; +@SuppressWarnings("unused") public final class CustomItemColors { public static final int BLACK = 0xFF404040; public static final int GREY = 0xFF555555; @@ -35,6 +36,7 @@ public final class CustomItemColors { /////////////////////////////////////////////////////////////////// + @SuppressWarnings("deprecation") public static void initialize() { final ItemColors itemColors = Minecraft.getInstance().getItemColors(); itemColors.register((stack, layer) -> layer == 1 ? getColor(stack) : NO_TINT, @@ -42,7 +44,6 @@ public final class CustomItemColors { Items.HARD_DRIVE_MEDIUM.get(), Items.HARD_DRIVE_LARGE.get(), Items.HARD_DRIVE_EXTRA_LARGE.get(), - Items.HARD_DRIVE_CUSTOM.get(), Items.FLOPPY.get(), Items.FLOPPY_MODERN.get()); } diff --git a/src/main/java/li/cil/oc2/client/item/CustomItemModelProperties.java b/src/main/java/li/cil/oc2/client/item/CustomItemModelProperties.java index db49879b..2817e11e 100644 --- a/src/main/java/li/cil/oc2/client/item/CustomItemModelProperties.java +++ b/src/main/java/li/cil/oc2/client/item/CustomItemModelProperties.java @@ -8,7 +8,7 @@ import net.minecraft.client.renderer.item.ItemProperties; import net.minecraft.resources.ResourceLocation; public final class CustomItemModelProperties { - public static final ResourceLocation COLOR_PROPERTY = new ResourceLocation(API.MOD_ID, "color"); + public static final ResourceLocation COLOR_PROPERTY = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "color"); /////////////////////////////////////////////////////////////////// @@ -21,8 +21,6 @@ public final class CustomItemModelProperties { (stack, leve, entity, seed) -> CustomItemColors.getColor(stack)); ItemProperties.register(Items.HARD_DRIVE_EXTRA_LARGE.get(), CustomItemModelProperties.COLOR_PROPERTY, (stack, leve, entity, seed) -> CustomItemColors.getColor(stack)); - ItemProperties.register(Items.HARD_DRIVE_CUSTOM.get(), CustomItemModelProperties.COLOR_PROPERTY, - (stack, level, entity, seed) -> CustomItemColors.getColor(stack)); ItemProperties.register(Items.FLOPPY.get(), CustomItemModelProperties.COLOR_PROPERTY, (stack, level, entity, seed) -> CustomItemColors.getColor(stack)); ItemProperties.register(Items.FLOPPY_MODERN.get(), CustomItemModelProperties.COLOR_PROPERTY, diff --git a/src/main/java/li/cil/oc2/client/manual/Manuals.java b/src/main/java/li/cil/oc2/client/manual/Manuals.java index b5f5c3da..7a310e01 100644 --- a/src/main/java/li/cil/oc2/client/manual/Manuals.java +++ b/src/main/java/li/cil/oc2/client/manual/Manuals.java @@ -37,12 +37,12 @@ public final class Manuals { /////////////////////////////////////////////////////////////////// - public static void initialize() { - MANUALS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + MANUALS.register(context.getModEventBus()); - PATH_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus()); - CONTENT_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus()); - TABS.register(FMLJavaModLoadingContext.get().getModEventBus()); + PATH_PROVIDERS.register(context.getModEventBus()); + CONTENT_PROVIDERS.register(context.getModEventBus()); + TABS.register(context.getModEventBus()); PATH_PROVIDERS.register("path_provider", () -> new NamespacePathProvider(API.MOD_ID)); CONTENT_PROVIDERS.register("content_provider", () -> new NamespaceDocumentProvider(API.MOD_ID, "doc")); @@ -50,7 +50,7 @@ public final class Manuals { TABS.register("home", () -> new TextureTab( ManualModel.LANGUAGE_KEY + "/index.md", Component.translatable("manual." + API.MOD_ID + ".home"), - new ResourceLocation(API.MOD_ID, "textures/gui/manual/home.png"))); + ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "textures/gui/manual/home.png"))); TABS.register("blocks", () -> new ItemStackTab( ManualModel.LANGUAGE_KEY + "/block/index.md", Component.translatable("manual." + API.MOD_ID + ".blocks"), diff --git a/src/main/java/li/cil/oc2/client/manual/ModManualScreenStyle.java b/src/main/java/li/cil/oc2/client/manual/ModManualScreenStyle.java index 9d76f805..83ac0c91 100644 --- a/src/main/java/li/cil/oc2/client/manual/ModManualScreenStyle.java +++ b/src/main/java/li/cil/oc2/client/manual/ModManualScreenStyle.java @@ -15,17 +15,17 @@ public final class ModManualScreenStyle implements ManualScreenStyle { @Override public ResourceLocation getWindowBackground() { - return new ResourceLocation(API.MOD_ID, "textures/gui/manual/manual.png"); + return ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "textures/gui/manual/manual.png"); } @Override public ResourceLocation getScrollButtonTexture() { - return new ResourceLocation(API.MOD_ID, "textures/gui/manual/scroll_button.png"); + return ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "textures/gui/manual/scroll_button.png"); } @Override public ResourceLocation getTabButtonTexture() { - return new ResourceLocation(API.MOD_ID, "textures/gui/manual/tab_button.png"); + return ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "textures/gui/manual/tab_button.png"); } @Override diff --git a/src/main/java/li/cil/oc2/client/model/BusCableModel.java b/src/main/java/li/cil/oc2/client/model/BusCableModel.java index d2f82a28..4fae10fe 100644 --- a/src/main/java/li/cil/oc2/client/model/BusCableModel.java +++ b/src/main/java/li/cil/oc2/client/model/BusCableModel.java @@ -15,8 +15,8 @@ import java.util.function.Function; import static java.util.Objects.requireNonNull; public final class BusCableModel implements IUnbakedGeometry { - private static final ResourceLocation BUS_CABLE_STRAIGHT_MODEL = new ResourceLocation(API.MOD_ID, "block/cable_straight"); - private static final ResourceLocation BUS_CABLE_SUPPORT_MODEL = new ResourceLocation(API.MOD_ID, "block/cable_support"); + private static final ResourceLocation BUS_CABLE_STRAIGHT_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/cable_straight"); + private static final ResourceLocation BUS_CABLE_SUPPORT_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/cable_support"); private final IUnbakedGeometry proxy; BusCableModel(final IUnbakedGeometry proxy) { diff --git a/src/main/java/li/cil/oc2/client/renderer/ModShaders.java b/src/main/java/li/cil/oc2/client/renderer/ModShaders.java index bca42421..79983041 100644 --- a/src/main/java/li/cil/oc2/client/renderer/ModShaders.java +++ b/src/main/java/li/cil/oc2/client/renderer/ModShaders.java @@ -17,11 +17,12 @@ import net.minecraftforge.fml.common.Mod; import javax.annotation.Nullable; import java.io.IOException; +@SuppressWarnings("unused") @Mod.EventBusSubscriber(value = Dist.CLIENT, modid = API.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public final class ModShaders { public static final int MAX_PROJECTORS = 3; - private static final ResourceLocation PROJECTORS_SHADER_LOCATION = new ResourceLocation(API.MOD_ID, "projectors"); + private static final ResourceLocation PROJECTORS_SHADER_LOCATION = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "projectors"); private static final String[] PROJECTOR_COLOR_NAMES = {"ProjectorColor0", "ProjectorColor1", "ProjectorColor2"}; private static final String[] PROJECTOR_DEPTH_NAMES = {"ProjectorDepth0", "ProjectorDepth1", "ProjectorDepth2"}; private static final String[] PROJECTOR_CAMERA_NAMES = {"ProjectorCamera0", "ProjectorCamera1", "ProjectorCamera2"}; diff --git a/src/main/java/li/cil/oc2/client/renderer/MonitorGUIRenderer.java b/src/main/java/li/cil/oc2/client/renderer/MonitorGUIRenderer.java index 56ea2868..4b1927f1 100644 --- a/src/main/java/li/cil/oc2/client/renderer/MonitorGUIRenderer.java +++ b/src/main/java/li/cil/oc2/client/renderer/MonitorGUIRenderer.java @@ -148,7 +148,7 @@ public class MonitorGUIRenderer { RenderSystem.blendFunc(GlStateManager.SourceFactor.ONE, GlStateManager.DestFactor.ONE); RenderSystem.colorMask(true, true, true, true); - //RenderSystem.depthMask(false); + RenderSystem.depthMask(false); final ShaderInstance shader = GameRenderer.getPositionTexShader(); @@ -178,6 +178,8 @@ public class MonitorGUIRenderer { RenderSystem.restoreProjectionMatrix(); RenderSystem.getModelViewStack().popPose(); RenderSystem.applyModelViewMatrix(); + + RenderSystem.depthMask(true); } } } diff --git a/src/main/java/li/cil/oc2/client/renderer/blockentity/ChargerRenderer.java b/src/main/java/li/cil/oc2/client/renderer/blockentity/ChargerRenderer.java index ce58305d..562bc0bc 100644 --- a/src/main/java/li/cil/oc2/client/renderer/blockentity/ChargerRenderer.java +++ b/src/main/java/li/cil/oc2/client/renderer/blockentity/ChargerRenderer.java @@ -18,7 +18,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.inventory.InventoryMenu; public final class ChargerRenderer implements BlockEntityRenderer { - public static final ResourceLocation EFFECT_LOCATION = new ResourceLocation(API.MOD_ID, "block/charger/effect"); + public static final ResourceLocation EFFECT_LOCATION = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/charger/effect"); private static final Material TEXTURE_EFFECT = new Material(InventoryMenu.BLOCK_ATLAS, EFFECT_LOCATION); diff --git a/src/main/java/li/cil/oc2/client/renderer/blockentity/ComputerRenderer.java b/src/main/java/li/cil/oc2/client/renderer/blockentity/ComputerRenderer.java index ed3f5a25..1c5a6739 100644 --- a/src/main/java/li/cil/oc2/client/renderer/blockentity/ComputerRenderer.java +++ b/src/main/java/li/cil/oc2/client/renderer/blockentity/ComputerRenderer.java @@ -16,7 +16,7 @@ import li.cil.oc2.client.renderer.ModRenderType; import li.cil.oc2.common.block.ComputerBlock; import li.cil.oc2.common.blockentity.ComputerBlockEntity; import li.cil.oc2.common.util.ChainableVertexConsumer; -import li.cil.oc2.common.vm.Terminal; +import li.cil.oc2.common.vm.terminal.Terminal; import net.minecraft.client.gui.Font; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; @@ -39,11 +39,12 @@ import java.time.Duration; import java.util.List; import java.util.concurrent.ExecutionException; +@SuppressWarnings("unused") @Mod.EventBusSubscriber(value = Dist.CLIENT, modid = API.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public final class ComputerRenderer implements BlockEntityRenderer { - public static final ResourceLocation OVERLAY_POWER_LOCATION = new ResourceLocation(API.MOD_ID, "block/computer/computer_overlay_power"); - public static final ResourceLocation OVERLAY_STATUS_LOCATION = new ResourceLocation(API.MOD_ID, "block/computer/computer_overlay_status"); - public static final ResourceLocation OVERLAY_TERMINAL_LOCATION = new ResourceLocation(API.MOD_ID, "block/computer/computer_overlay_terminal"); + public static final ResourceLocation OVERLAY_POWER_LOCATION = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/computer/computer_overlay_power"); + public static final ResourceLocation OVERLAY_STATUS_LOCATION = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/computer/computer_overlay_status"); + public static final ResourceLocation OVERLAY_TERMINAL_LOCATION = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/computer/computer_overlay_terminal"); private static final Material TEXTURE_POWER = new Material(InventoryMenu.BLOCK_ATLAS, OVERLAY_POWER_LOCATION); private static final Material TEXTURE_STATUS = new Material(InventoryMenu.BLOCK_ATLAS, OVERLAY_STATUS_LOCATION); @@ -206,25 +207,25 @@ public final class ComputerRenderer implements BlockEntityRenderer wrappedText = fontRenderer.getSplitter().splitLines(text, maxWidth, Style.EMPTY); if (wrappedText.size() == 1) { final int textWidth = fontRenderer.width(text); - draw(fontRenderer, stack, text, (maxWidth - textWidth) * 0.5f, 0, 0xEE3322); + draw(fontRenderer, stack, text, (maxWidth - textWidth) * 0.5f); } else { for (int i = 0; i < wrappedText.size(); i++) { - draw(fontRenderer, stack, wrappedText.get(i).getString(), 0, i * fontRenderer.lineHeight, 0xEE3322); + draw(fontRenderer, stack, wrappedText.get(i).getString(), i * fontRenderer.lineHeight); } } stack.popPose(); } - private void draw(Font font, PoseStack stack, Component text, float x, float y, int color) { + private void draw(Font font, PoseStack stack, Component text, float x) { var batch = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder()); - font.drawInBatch(text, x, y, color, false, stack.last().pose(), batch, Font.DisplayMode.NORMAL, 0, 15728880); + font.drawInBatch(text, x, (float) 0, 15610658, false, stack.last().pose(), batch, Font.DisplayMode.NORMAL, 0, 15728880); batch.endBatch(); } - private void draw(Font font, PoseStack stack, String text, float x, float y, int color) { + private void draw(Font font, PoseStack stack, String text, float y) { var batch = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder()); - font.drawInBatch(text, x, y, color, false, stack.last().pose(), batch, Font.DisplayMode.NORMAL, 0, 15728880, false); + font.drawInBatch(text, (float) 0, y, 15610658, false, stack.last().pose(), batch, Font.DisplayMode.NORMAL, 0, 15728880, false); batch.endBatch(); } diff --git a/src/main/java/li/cil/oc2/client/renderer/blockentity/MonitorRenderer.java b/src/main/java/li/cil/oc2/client/renderer/blockentity/MonitorRenderer.java index 930130c6..814b6922 100644 --- a/src/main/java/li/cil/oc2/client/renderer/blockentity/MonitorRenderer.java +++ b/src/main/java/li/cil/oc2/client/renderer/blockentity/MonitorRenderer.java @@ -41,10 +41,11 @@ import java.time.Duration; import java.util.List; import java.util.concurrent.ExecutionException; +@SuppressWarnings("unused") @Mod.EventBusSubscriber(value = Dist.CLIENT, modid = API.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public final class MonitorRenderer implements BlockEntityRenderer { - public static final ResourceLocation OVERLAY_POWER_LOCATION = new ResourceLocation(API.MOD_ID, "block/monitor/monitor_overlay_power"); - public static final ResourceLocation OVERLAY_TERMINAL_LOCATION = new ResourceLocation(API.MOD_ID, "block/computer/computer_overlay_terminal"); + public static final ResourceLocation OVERLAY_POWER_LOCATION = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/monitor/monitor_overlay_power"); + public static final ResourceLocation OVERLAY_TERMINAL_LOCATION = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/computer/computer_overlay_terminal"); private static final Material TEXTURE_POWER = new Material(InventoryMenu.BLOCK_ATLAS, OVERLAY_POWER_LOCATION); private static final Material TEXTURE_TERMINAL = new Material(InventoryMenu.BLOCK_ATLAS, OVERLAY_TERMINAL_LOCATION); @@ -180,25 +181,25 @@ public final class MonitorRenderer implements BlockEntityRenderer wrappedText = fontRenderer.getSplitter().splitLines(text, maxWidth, Style.EMPTY); if (wrappedText.size() == 1) { final int textWidth = fontRenderer.width(text); - draw(fontRenderer, stack, text, (maxWidth - textWidth) * 0.5f, 0, 0xEE3322); + draw(fontRenderer, stack, text, (maxWidth - textWidth) * 0.5f); } else { for (int i = 0; i < wrappedText.size(); i++) { - draw(fontRenderer, stack, wrappedText.get(i).getString(), 0, i * fontRenderer.lineHeight, 0xEE3322); + draw(fontRenderer, stack, wrappedText.get(i).getString(), i * fontRenderer.lineHeight); } } stack.popPose(); } - private void draw(Font font, PoseStack stack, Component text, float x, float y, int color) { + private void draw(Font font, PoseStack stack, Component text, float x) { var batch = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder()); - font.drawInBatch(text, x, y, color, false, stack.last().pose(), batch, Font.DisplayMode.NORMAL, 0, 15728880); + font.drawInBatch(text, x, (float) 0, 15610658, false, stack.last().pose(), batch, Font.DisplayMode.NORMAL, 0, 15728880); batch.endBatch(); } - private void draw(Font font, PoseStack stack, String text, float x, float y, int color) { + private void draw(Font font, PoseStack stack, String text, float y) { var batch = MultiBufferSource.immediate(Tesselator.getInstance().getBuilder()); - font.drawInBatch(text, x, y, color, false, stack.last().pose(), batch, Font.DisplayMode.NORMAL, 0, 15728880, false); + font.drawInBatch(text, (float) 0, y, 15610658, false, stack.last().pose(), batch, Font.DisplayMode.NORMAL, 0, 15728880, false); batch.endBatch(); } diff --git a/src/main/java/li/cil/oc2/client/renderer/entity/model/RobotModel.java b/src/main/java/li/cil/oc2/client/renderer/entity/model/RobotModel.java index 20606be5..726d6414 100644 --- a/src/main/java/li/cil/oc2/client/renderer/entity/model/RobotModel.java +++ b/src/main/java/li/cil/oc2/client/renderer/entity/model/RobotModel.java @@ -19,8 +19,8 @@ import net.minecraft.resources.ResourceLocation; import net.minecraftforge.common.util.TransformationHelper; public final class RobotModel extends EntityModel { - public static final ModelLayerLocation ROBOT_MODEL_LAYER = new ModelLayerLocation(new ResourceLocation(API.MOD_ID, "robot"), "main"); - public static final ResourceLocation ROBOT_ENTITY_TEXTURE = new ResourceLocation(API.MOD_ID, "textures/entity/robot/robot.png"); + public static final ModelLayerLocation ROBOT_MODEL_LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "robot"), "main"); + public static final ResourceLocation ROBOT_ENTITY_TEXTURE = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "textures/entity/robot/robot.png"); /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/client/renderer/font/MonospaceFontRenderer.java b/src/main/java/li/cil/oc2/client/renderer/font/MonospaceFontRenderer.java index cd24a499..ec41b6d7 100644 --- a/src/main/java/li/cil/oc2/client/renderer/font/MonospaceFontRenderer.java +++ b/src/main/java/li/cil/oc2/client/renderer/font/MonospaceFontRenderer.java @@ -10,7 +10,7 @@ import net.minecraft.resources.ResourceLocation; public final class MonospaceFontRenderer extends BitmapFontRenderer { public static final FontRenderer INSTANCE = new MonospaceFontRenderer(); - private static final ResourceLocation LOCATION_FONT_TEXTURE = new ResourceLocation(API.MOD_ID, "textures/font/monospace.png"); + private static final ResourceLocation LOCATION_FONT_TEXTURE = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "textures/font/monospace.png"); private static final String CHARS = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; @Override diff --git a/src/main/java/li/cil/oc2/common/ConfigManager.java b/src/main/java/li/cil/oc2/common/ConfigManager.java index c4436198..ecf61640 100644 --- a/src/main/java/li/cil/oc2/common/ConfigManager.java +++ b/src/main/java/li/cil/oc2/common/ConfigManager.java @@ -6,11 +6,11 @@ import li.cil.oc2.api.API; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.common.ForgeConfigSpec; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.IConfigSpec; import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.config.ModConfigEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -28,6 +28,7 @@ import java.util.UUID; import java.util.function.Function; import java.util.function.Supplier; +@SuppressWarnings("unused") @Mod.EventBusSubscriber(modid = API.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD) public final class ConfigManager { @Retention(RetentionPolicy.RUNTIME) @@ -68,7 +69,6 @@ public final class ConfigManager { PARSERS.put(short.class, ConfigManager::parseShortField); PARSERS.put(long.class, ConfigManager::parseLongField); PARSERS.put(double.class, ConfigManager::parseDoubleField); - PARSERS.put(boolean.class, ConfigManager::parseBooleanField); PARSERS.put(String.class, ConfigManager::parseStringField); PARSERS.put(UUID.class, ConfigManager::parseUUIDField); PARSERS.put(ResourceLocation.class, ConfigManager::parseResourceLocationField); @@ -87,11 +87,11 @@ public final class ConfigManager { CONFIGS.put(config.getValue(), new ConfigDefinition(config.getKey(), values)); } - public static void initialize() { + public static void initialize(FMLJavaModLoadingContext context) { CONFIGS.forEach((spec, config) -> { final Type typeAnnotation = config.instance.getClass().getAnnotation(Type.class); final ModConfig.Type configType = typeAnnotation != null ? typeAnnotation.value() : ModConfig.Type.COMMON; - ModLoadingContext.get().registerConfig(configType, spec); + context.registerConfig(configType, spec); }); } @@ -196,7 +196,7 @@ public final class ConfigManager { final ForgeConfigSpec.ConfigValue configValue = builder.define(path, defaultValue.toString()); - return new ConfigFieldPair<>(field, configValue, ResourceLocation::new); + return new ConfigFieldPair<>(field, configValue, ResourceLocation::parse); } private static String getPath(@Nullable final String prefix, final Field field) { diff --git a/src/main/java/li/cil/oc2/common/Main.java b/src/main/java/li/cil/oc2/common/Main.java index b2358e63..6a295014 100644 --- a/src/main/java/li/cil/oc2/common/Main.java +++ b/src/main/java/li/cil/oc2/common/Main.java @@ -32,41 +32,41 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @Mod(API.MOD_ID) public final class Main { - public Main() { - EventBuses.registerModEventBus(API.MOD_ID, FMLJavaModLoadingContext.get().getModEventBus()); + public Main(FMLJavaModLoadingContext context) { + EventBuses.registerModEventBus(API.MOD_ID, context.getModEventBus()); Ceres.initialize(); Sedna.initialize(); DeviceTreeProviders.initialize(); Serializers.initialize(); ConfigManager.add(Config::new); - ConfigManager.initialize(); + ConfigManager.initialize(context); RegistryUtils.begin(); ItemTags.initialize(); BlockTags.initialize(); - Blocks.initialize(); - Items.initialize(); - BlockEntities.initialize(); - Entities.initialize(); - Containers.initialize(); - RecipeSerializers.initialize(); - SoundEvents.initialize(); + Blocks.initialize(context); + Items.initialize(context); + BlockEntities.initialize(context); + Entities.initialize(context); + Containers.initialize(context); + RecipeSerializers.initialize(context); + SoundEvents.initialize(context); - ProviderRegistry.initialize(); - DeviceTypes.initialize(); + ProviderRegistry.initialize(context); + DeviceTypes.initialize(context); - BlockDeviceDataRegistry.initialize(); - FirmwareRegistry.initialize(); + BlockDeviceDataRegistry.initialize(context); + FirmwareRegistry.initialize(context); - RegistryUtils.finish(); + RegistryUtils.finish(context); - FMLJavaModLoadingContext.get().getModEventBus().register(CommonSetup.class); - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> Manuals::initialize); + context.getModEventBus().register(CommonSetup.class); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> Manuals.initialize(context)); DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> - FMLJavaModLoadingContext.get().getModEventBus().register(ClientSetup.class)); + context.getModEventBus().register(ClientSetup.class)); - ItemGroup.TAB_REGISTER.register(FMLJavaModLoadingContext.get().getModEventBus()); + ItemGroup.TAB_REGISTER.register(context.getModEventBus()); } } diff --git a/src/main/java/li/cil/oc2/common/block/Blocks.java b/src/main/java/li/cil/oc2/common/block/Blocks.java index 1d796d85..2ed5c87f 100644 --- a/src/main/java/li/cil/oc2/common/block/Blocks.java +++ b/src/main/java/li/cil/oc2/common/block/Blocks.java @@ -34,7 +34,7 @@ public final class Blocks { /////////////////////////////////////////////////////////////////// - public static void initialize() { - BLOCKS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + BLOCKS.register(context.getModEventBus()); } } diff --git a/src/main/java/li/cil/oc2/common/block/DiskDriveBlock.java b/src/main/java/li/cil/oc2/common/block/DiskDriveBlock.java index dd184f87..6babea94 100644 --- a/src/main/java/li/cil/oc2/common/block/DiskDriveBlock.java +++ b/src/main/java/li/cil/oc2/common/block/DiskDriveBlock.java @@ -41,6 +41,19 @@ public final class DiskDriveBlock extends HorizontalDirectionalBlock implements return super.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); } + @Override + public void playerWillDestroy(final Level level, final BlockPos pos, final BlockState state, final Player player) { + final BlockEntity blockEntity = level.getBlockEntity(pos); + if (!level.isClientSide() && blockEntity instanceof final DiskDriveBlockEntity diskDrive) { + if (!diskDrive.getDiskItemStack().isEmpty()) { + final ItemStack stack = diskDrive.getDiskItemStack(); + popResource(level, pos, stack); + } + } + + super.playerWillDestroy(level, pos, state, player); + } + @SuppressWarnings("deprecation") @Override public InteractionResult use(final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final BlockHitResult hit) { diff --git a/src/main/java/li/cil/oc2/common/block/FlashMemoryFlasherBlock.java b/src/main/java/li/cil/oc2/common/block/FlashMemoryFlasherBlock.java index 0475ad83..112ff23e 100644 --- a/src/main/java/li/cil/oc2/common/block/FlashMemoryFlasherBlock.java +++ b/src/main/java/li/cil/oc2/common/block/FlashMemoryFlasherBlock.java @@ -69,6 +69,19 @@ public final class FlashMemoryFlasherBlock extends HorizontalDirectionalBlock im return super.use(state, level, pos, player, hand, hit); } + @Override + public void playerWillDestroy(final Level level, final BlockPos pos, final BlockState state, final Player player) { + final BlockEntity blockEntity = level.getBlockEntity(pos); + if (!level.isClientSide() && blockEntity instanceof final FlashMemoryFlasherBlockEntity flashFlasher) { + if (!flashFlasher.getDiskItemStack().isEmpty()) { + final ItemStack stack = flashFlasher.getDiskItemStack(); + popResource(level, pos, stack); + } + } + + super.playerWillDestroy(level, pos, state, player); + } + /////////////////////////////////////////////////////////////////// // EntityBlock diff --git a/src/main/java/li/cil/oc2/common/block/RedstoneInterfaceBlock.java b/src/main/java/li/cil/oc2/common/block/RedstoneInterfaceBlock.java index 1d1ef02c..0ffc616e 100644 --- a/src/main/java/li/cil/oc2/common/block/RedstoneInterfaceBlock.java +++ b/src/main/java/li/cil/oc2/common/block/RedstoneInterfaceBlock.java @@ -63,6 +63,7 @@ public final class RedstoneInterfaceBlock extends HorizontalDirectionalBlock imp } @Override + @SuppressWarnings({"deprecation", "DataFlowIssue"}) public void neighborChanged(BlockState state, Level worldIn, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) { RedstoneInterfaceBlockEntity ribe = (RedstoneInterfaceBlockEntity) worldIn.getBlockEntity(pos); ribe.neighborChanged(fromPos); diff --git a/src/main/java/li/cil/oc2/common/blockentity/BlockEntities.java b/src/main/java/li/cil/oc2/common/blockentity/BlockEntities.java index 3268f667..002285cf 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/BlockEntities.java +++ b/src/main/java/li/cil/oc2/common/blockentity/BlockEntities.java @@ -37,8 +37,8 @@ public final class BlockEntities { /////////////////////////////////////////////////////////////////// - public static void initialize() { - BLOCK_ENTITIES.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + BLOCK_ENTITIES.register(context.getModEventBus()); } /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/blockentity/ComputerBlockEntity.java b/src/main/java/li/cil/oc2/common/blockentity/ComputerBlockEntity.java index 8de996f6..f8d7f3e0 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/ComputerBlockEntity.java +++ b/src/main/java/li/cil/oc2/common/blockentity/ComputerBlockEntity.java @@ -26,6 +26,7 @@ import li.cil.oc2.common.network.message.ComputerTerminalOutputMessage; import li.cil.oc2.common.serialization.NBTSerialization; import li.cil.oc2.common.util.*; import li.cil.oc2.common.vm.*; +import li.cil.oc2.common.vm.terminal.Terminal; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/li/cil/oc2/common/blockentity/RedstoneInterfaceBlockEntity.java b/src/main/java/li/cil/oc2/common/blockentity/RedstoneInterfaceBlockEntity.java index 1e72a968..16908285 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/RedstoneInterfaceBlockEntity.java +++ b/src/main/java/li/cil/oc2/common/blockentity/RedstoneInterfaceBlockEntity.java @@ -15,7 +15,6 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.util.Mth; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.state.BlockState; -import java.util.Collection; import net.minecraftforge.fml.ModList; import java.util.*; import javax.annotation.Nullable; @@ -24,6 +23,7 @@ import com.google.gson.JsonObject; import li.cil.oc2.api.bus.device.rpc.*; import static java.util.Collections.singletonList; +@SuppressWarnings("unused") public final class RedstoneInterfaceBlockEntity extends ModBlockEntity implements NamedDevice, DocumentedDevice, RPCEventSource { private static final String OUTPUT_TAG_NAME = "output"; private static final String BUNDLED_TAG_NAME = "bundled"; @@ -40,7 +40,7 @@ public final class RedstoneInterfaceBlockEntity extends ModBlockEntity implement private static final String VALUES = "values"; private static final String COLOUR = "colour"; - private final HashMap subscribers = new HashMap(); + private final HashMap subscribers = new HashMap<>(); /////////////////////////////////////////////////////////////////// @@ -298,7 +298,7 @@ public final class RedstoneInterfaceBlockEntity extends ModBlockEntity implement } public void neighborChanged(BlockPos fromPos) { - int sl = 0; + int sl; if (level == null) { return; } @@ -310,9 +310,10 @@ public final class RedstoneInterfaceBlockEntity extends ModBlockEntity implement final ChunkPos chunkPos = new ChunkPos(fromPos); if (!level.hasChunk(chunkPos.x, chunkPos.z)) { sl = 0; + } else { + sl = level.getSignal(fromPos, direction); } - sl = level.getSignal(fromPos, direction); JsonObject msg = new JsonObject(); msg.addProperty("event", "redstone"); msg.addProperty("side", ""+direction); diff --git a/src/main/java/li/cil/oc2/common/bus/AbstractBlockDeviceBusElement.java b/src/main/java/li/cil/oc2/common/bus/AbstractBlockDeviceBusElement.java index 8a1b26ec..44f83dfc 100644 --- a/src/main/java/li/cil/oc2/common/bus/AbstractBlockDeviceBusElement.java +++ b/src/main/java/li/cil/oc2/common/bus/AbstractBlockDeviceBusElement.java @@ -163,7 +163,7 @@ public abstract class AbstractBlockDeviceBusElement extends AbstractGroupingDevi super.onEntryRemoved(dataKey, tag, query); assert query != null : "Passed null query for block device bus element."; final IForgeRegistry registry = Providers.blockDeviceProviderRegistry(); - final BlockDeviceProvider provider = registry.getValue(new ResourceLocation(dataKey)); + final BlockDeviceProvider provider = registry.getValue(ResourceLocation.parse(dataKey)); if (provider != null) { provider.unmount(query, tag); } diff --git a/src/main/java/li/cil/oc2/common/bus/AbstractItemDeviceBusElement.java b/src/main/java/li/cil/oc2/common/bus/AbstractItemDeviceBusElement.java index 5229b628..e4f5651a 100644 --- a/src/main/java/li/cil/oc2/common/bus/AbstractItemDeviceBusElement.java +++ b/src/main/java/li/cil/oc2/common/bus/AbstractItemDeviceBusElement.java @@ -85,6 +85,7 @@ public abstract class AbstractItemDeviceBusElement extends AbstractGroupingDevic return new ItemQueryResult(query, entries); } + @SuppressWarnings("ConstantValue") protected void collectSyntheticDevices(final ItemDeviceQuery query, final HashSet entries) { if (entries.isEmpty()) { return; @@ -99,7 +100,7 @@ public abstract class AbstractItemDeviceBusElement extends AbstractGroupingDevic protected void onEntryRemoved(final String dataKey, final CompoundTag tag, @Nullable final ItemDeviceQuery query) { super.onEntryRemoved(dataKey, tag, query); final IForgeRegistry registry = Providers.itemDeviceProviderRegistry(); - final ItemDeviceProvider provider = registry.getValue(new ResourceLocation(dataKey)); + final ItemDeviceProvider provider = registry.getValue(ResourceLocation.parse(dataKey)); if (provider != null) { provider.unmount(query, tag); } diff --git a/src/main/java/li/cil/oc2/common/bus/device/DeviceTypes.java b/src/main/java/li/cil/oc2/common/bus/device/DeviceTypes.java index 62985505..d82e4304 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/DeviceTypes.java +++ b/src/main/java/li/cil/oc2/common/bus/device/DeviceTypes.java @@ -28,8 +28,8 @@ public final class DeviceTypes { /////////////////////////////////////////////////////////////////// - public static void initialize() { - DEVICE_TYPES.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + DEVICE_TYPES.register(context.getModEventBus()); register(ItemTags.DEVICES_MEMORY); register(ItemTags.DEVICES_HARD_DRIVE); @@ -47,7 +47,7 @@ public final class DeviceTypes { final String id = tag.location().getPath().replaceFirst("^devices/", ""); DEVICE_TYPES.register(id, () -> new DeviceTypeImpl( tag, - new ResourceLocation(API.MOD_ID, "item/" + id + "_slot"), + ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "item/" + id + "_slot"), text("gui.{mod}.device_type." + id) )); } diff --git a/src/main/java/li/cil/oc2/common/bus/device/data/BlockDeviceDataRegistry.java b/src/main/java/li/cil/oc2/common/bus/device/data/BlockDeviceDataRegistry.java index e1fecdc0..e8927841 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/data/BlockDeviceDataRegistry.java +++ b/src/main/java/li/cil/oc2/common/bus/device/data/BlockDeviceDataRegistry.java @@ -16,6 +16,7 @@ import javax.annotation.Nullable; import java.util.function.Supplier; import java.util.stream.Stream; +@SuppressWarnings("unused") public final class BlockDeviceDataRegistry { private static final DeferredRegister INITIALIZER = DeferredRegister.create(Registries.BLOCK_DEVICE_DATA, API.MOD_ID); @@ -29,8 +30,8 @@ public final class BlockDeviceDataRegistry { /////////////////////////////////////////////////////////////////// - public static void initialize() { - INITIALIZER.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + INITIALIZER.register(context.getModEventBus()); } @Nullable diff --git a/src/main/java/li/cil/oc2/common/bus/device/data/FileSystems.java b/src/main/java/li/cil/oc2/common/bus/device/data/FileSystems.java index f4d803f6..c9696b70 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/data/FileSystems.java +++ b/src/main/java/li/cil/oc2/common/bus/device/data/FileSystems.java @@ -23,6 +23,7 @@ import net.minecraftforge.fml.common.Mod; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import javax.annotation.Nullable; import java.io.InputStream; import java.io.InputStreamReader; import java.util.*; @@ -31,6 +32,7 @@ import java.util.concurrent.Executor; import static li.cil.oc2.common.util.TextFormatUtils.formatSize; +@SuppressWarnings("unused") @Mod.EventBusSubscriber(modid = API.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public final class FileSystems { private static final Logger LOGGER = LogManager.getLogger(); @@ -50,6 +52,7 @@ public final class FileSystems { return blocksByName.get(name); } + @Nullable public static ResourceLocation getKeyByValue(BlockDeviceData value) { for (Map.Entry entry : BLOCK_DEVICE_DATA.entrySet()) { if (Objects.equals(value, entry.getValue())) { @@ -109,7 +112,7 @@ public final class FileSystems { final String type = json.getAsJsonPrimitive("type").getAsString(); switch (type) { case "layer" -> { - final ResourceLocation location = new ResourceLocation(json.getAsJsonPrimitive("location").getAsString()); + final ResourceLocation location = ResourceLocation.parse(json.getAsJsonPrimitive("location").getAsString()); final ZipStreamFileSystem fileSystem; try (final InputStream stream = resourceManager.getResource(location).get().open()) { @@ -132,7 +135,7 @@ public final class FileSystems { } } case "block" -> { - final ResourceLocation location = new ResourceLocation(json.getAsJsonPrimitive("location").getAsString()); + final ResourceLocation location = ResourceLocation.parse(json.getAsJsonPrimitive("location").getAsString()); if (BlockDeviceDataRegistry.getValue(location) != null) { LOGGER.error("Block device from datapack collides with already registered location [{}].", location); continue; diff --git a/src/main/java/li/cil/oc2/common/bus/device/data/FirmwareRegistry.java b/src/main/java/li/cil/oc2/common/bus/device/data/FirmwareRegistry.java index 893f3626..8894b9fa 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/data/FirmwareRegistry.java +++ b/src/main/java/li/cil/oc2/common/bus/device/data/FirmwareRegistry.java @@ -29,11 +29,11 @@ public final class FirmwareRegistry { /////////////////////////////////////////////////////////////////// - public static void initialize() { - INITIALIZER.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + INITIALIZER.register(context.getModEventBus()); } - @Nullable + @SuppressWarnings("unused") public static ResourceLocation getKey(final Firmware firmware) { return INITIALIZER.getRegistryName(); } diff --git a/src/main/java/li/cil/oc2/common/bus/device/provider/ProviderRegistry.java b/src/main/java/li/cil/oc2/common/bus/device/provider/ProviderRegistry.java index f49f2698..0223ba13 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/provider/ProviderRegistry.java +++ b/src/main/java/li/cil/oc2/common/bus/device/provider/ProviderRegistry.java @@ -27,9 +27,9 @@ public final class ProviderRegistry { /////////////////////////////////////////////////////////////////// - public static void initialize() { - ITEM_DEVICE_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus()); - BLOCK_DEVICE_PROVIDERS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + ITEM_DEVICE_PROVIDERS.register(context.getModEventBus()); + BLOCK_DEVICE_PROVIDERS.register(context.getModEventBus()); ITEM_DEVICE_PROVIDERS.register("memory", MemoryItemDeviceProvider::new); ITEM_DEVICE_PROVIDERS.register("hard_drive", HardDriveItemDeviceProvider::new); diff --git a/src/main/java/li/cil/oc2/common/bus/device/rpc/item/SoundCardItemDevice.java b/src/main/java/li/cil/oc2/common/bus/device/rpc/item/SoundCardItemDevice.java index 43fe006d..8ce97e16 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/rpc/item/SoundCardItemDevice.java +++ b/src/main/java/li/cil/oc2/common/bus/device/rpc/item/SoundCardItemDevice.java @@ -21,6 +21,7 @@ import java.util.List; import java.util.Optional; import java.util.function.Supplier; +@SuppressWarnings("unused") public final class SoundCardItemDevice extends AbstractItemRPCDevice { private final int COOLDOWN_IN_TICKS = TickUtils.toTicks(Duration.ofSeconds(Config.soundCardCoolDownSeconds)); private static final int MAX_FIND_RESULTS = 25; @@ -68,7 +69,7 @@ public final class SoundCardItemDevice extends AbstractItemRPCDevice { gameTimeCooldownExpiresAt = gameTime + COOLDOWN_IN_TICKS; - final SoundEvent soundEvent = ForgeRegistries.SOUND_EVENTS.getValue(new ResourceLocation(name)); + final SoundEvent soundEvent = ForgeRegistries.SOUND_EVENTS.getValue(ResourceLocation.parse(name)); if (soundEvent == null) throw new IllegalArgumentException("Sound not found."); level.playSound(null, location.blockPos(), soundEvent, SoundSource.BLOCKS, volume, pitch); })); @@ -76,7 +77,7 @@ public final class SoundCardItemDevice extends AbstractItemRPCDevice { @Callback public List findSound(@Nullable @Parameter("name") final String name) { - if (name == null || name.length() == 0) throw new IllegalArgumentException(); + if (name == null || name.isEmpty()) throw new IllegalArgumentException(); final ArrayList matches = new ArrayList<>(); diff --git a/src/main/java/li/cil/oc2/common/container/AbstractComputerContainer.java b/src/main/java/li/cil/oc2/common/container/AbstractComputerContainer.java index 8446379c..8c4f4a8c 100644 --- a/src/main/java/li/cil/oc2/common/container/AbstractComputerContainer.java +++ b/src/main/java/li/cil/oc2/common/container/AbstractComputerContainer.java @@ -10,7 +10,7 @@ import li.cil.oc2.common.network.message.ComputerPowerMessage; import li.cil.oc2.common.network.message.ComputerTerminalInputMessage; import li.cil.oc2.common.network.message.OpenComputerInventoryMessage; import li.cil.oc2.common.network.message.OpenComputerTerminalMessage; -import li.cil.oc2.common.vm.Terminal; +import li.cil.oc2.common.vm.terminal.Terminal; import li.cil.oc2.common.vm.VirtualMachine; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.ContainerLevelAccess; diff --git a/src/main/java/li/cil/oc2/common/container/AbstractMachineTerminalContainer.java b/src/main/java/li/cil/oc2/common/container/AbstractMachineTerminalContainer.java index 3c96f5fd..da9c295b 100644 --- a/src/main/java/li/cil/oc2/common/container/AbstractMachineTerminalContainer.java +++ b/src/main/java/li/cil/oc2/common/container/AbstractMachineTerminalContainer.java @@ -2,7 +2,7 @@ package li.cil.oc2.common.container; -import li.cil.oc2.common.vm.Terminal; +import li.cil.oc2.common.vm.terminal.Terminal; import net.minecraft.world.inventory.MenuType; import java.nio.ByteBuffer; diff --git a/src/main/java/li/cil/oc2/common/container/AbstractRobotContainer.java b/src/main/java/li/cil/oc2/common/container/AbstractRobotContainer.java index 267d61fb..0f430c05 100644 --- a/src/main/java/li/cil/oc2/common/container/AbstractRobotContainer.java +++ b/src/main/java/li/cil/oc2/common/container/AbstractRobotContainer.java @@ -10,7 +10,7 @@ import li.cil.oc2.common.network.message.OpenRobotInventoryMessage; import li.cil.oc2.common.network.message.OpenRobotTerminalMessage; import li.cil.oc2.common.network.message.RobotPowerMessage; import li.cil.oc2.common.network.message.RobotTerminalInputMessage; -import li.cil.oc2.common.vm.Terminal; +import li.cil.oc2.common.vm.terminal.Terminal; import li.cil.oc2.common.vm.VirtualMachine; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.MenuType; diff --git a/src/main/java/li/cil/oc2/common/container/Containers.java b/src/main/java/li/cil/oc2/common/container/Containers.java index a25eaeab..a63134c9 100644 --- a/src/main/java/li/cil/oc2/common/container/Containers.java +++ b/src/main/java/li/cil/oc2/common/container/Containers.java @@ -24,7 +24,7 @@ public final class Containers { /////////////////////////////////////////////////////////////////// - public static void initialize() { - CONTAINERS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + CONTAINERS.register(context.getModEventBus()); } } diff --git a/src/main/java/li/cil/oc2/common/entity/Entities.java b/src/main/java/li/cil/oc2/common/entity/Entities.java index 4bcb392c..76db4c4b 100644 --- a/src/main/java/li/cil/oc2/common/entity/Entities.java +++ b/src/main/java/li/cil/oc2/common/entity/Entities.java @@ -22,12 +22,13 @@ public final class Entities { /////////////////////////////////////////////////////////////////// - public static void initialize() { - ENTITIES.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + ENTITIES.register(context.getModEventBus()); } /////////////////////////////////////////////////////////////////// + @SuppressWarnings("SameParameterValue") private static RegistryObject> register(final String name, final EntityType.EntityFactory factory, final MobCategory classification, final Function, EntityType.Builder> customizer) { return ENTITIES.register(name, () -> customizer.apply(EntityType.Builder.of(factory, classification)).build(name)); } diff --git a/src/main/java/li/cil/oc2/common/entity/Robot.java b/src/main/java/li/cil/oc2/common/entity/Robot.java index 584f24da..fee89d47 100644 --- a/src/main/java/li/cil/oc2/common/entity/Robot.java +++ b/src/main/java/li/cil/oc2/common/entity/Robot.java @@ -30,6 +30,7 @@ import li.cil.oc2.common.util.NBTTagIds; import li.cil.oc2.common.util.NBTUtils; import li.cil.oc2.common.util.TerminalUtils; import li.cil.oc2.common.vm.*; +import li.cil.oc2.common.vm.terminal.Terminal; import net.minecraft.core.BlockPos; import net.minecraft.core.Cursor3D; import net.minecraft.core.Direction; diff --git a/src/main/java/li/cil/oc2/common/integration/IMC.java b/src/main/java/li/cil/oc2/common/integration/IMC.java index 142fad22..03b96da2 100644 --- a/src/main/java/li/cil/oc2/common/integration/IMC.java +++ b/src/main/java/li/cil/oc2/common/integration/IMC.java @@ -2,13 +2,13 @@ package li.cil.oc2.common.integration; +import dev.architectury.platform.forge.EventBuses; import li.cil.oc2.api.API; import li.cil.oc2.api.imc.RPCMethodParameterTypeAdapter; import li.cil.oc2.common.bus.device.rpc.RPCMethodParameterTypeAdapters; import net.minecraft.Util; import net.minecraftforge.fml.InterModComms; import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -30,7 +30,7 @@ public final class IMC { /////////////////////////////////////////////////////////////////// public static void initialize() { - FMLJavaModLoadingContext.get().getModEventBus().addListener(IMC::handleIMCMessages); + EventBuses.getModEventBus(API.MOD_ID).get().addListener(IMC::handleIMCMessages); } /////////////////////////////////////////////////////////////////// @@ -56,7 +56,7 @@ public final class IMC { }); } - @SuppressWarnings("unchecked") + @SuppressWarnings({"unchecked", "SameParameterValue"}) private static Optional getMessageParameter(final InterModComms.IMCMessage message, final Class type) { final Object value = message.messageSupplier().get(); if (type.isInstance(value)) { diff --git a/src/main/java/li/cil/oc2/common/integration/jei/ExtraGuiAreasJEIPlugin.java b/src/main/java/li/cil/oc2/common/integration/jei/ExtraGuiAreasJEIPlugin.java index b633e9a1..9a88d67d 100644 --- a/src/main/java/li/cil/oc2/common/integration/jei/ExtraGuiAreasJEIPlugin.java +++ b/src/main/java/li/cil/oc2/common/integration/jei/ExtraGuiAreasJEIPlugin.java @@ -20,10 +20,11 @@ import java.util.HashSet; import java.util.List; @JeiPlugin +@SuppressWarnings("unused") public class ExtraGuiAreasJEIPlugin implements IModPlugin { @Override public ResourceLocation getPluginUid() { - return new ResourceLocation(API.MOD_ID, "extra_gui_areas"); + return ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "extra_gui_areas"); } @Override diff --git a/src/main/java/li/cil/oc2/common/integration/jei/ExtraItemsJEIPlugin.java b/src/main/java/li/cil/oc2/common/integration/jei/ExtraItemsJEIPlugin.java index b202b6d2..7035e33c 100644 --- a/src/main/java/li/cil/oc2/common/integration/jei/ExtraItemsJEIPlugin.java +++ b/src/main/java/li/cil/oc2/common/integration/jei/ExtraItemsJEIPlugin.java @@ -27,17 +27,17 @@ import static li.cil.oc2.common.Constants.BLOCK_ENTITY_TAG_NAME_IN_ITEM; import static li.cil.oc2.common.Constants.ITEMS_TAG_NAME; @JeiPlugin +@SuppressWarnings("unused") public class ExtraItemsJEIPlugin implements IModPlugin { @Override public ResourceLocation getPluginUid() { - return new ResourceLocation(API.MOD_ID, "extra_items"); + return ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "extra_items"); } @Override public void registerItemSubtypes(final ISubtypeRegistration registration) { registration.registerSubtypeInterpreter(VanillaTypes.ITEM_STACK, Items.COMPUTER.get(), new ComputerSubtypeInterpreter()); registration.registerSubtypeInterpreter(VanillaTypes.ITEM_STACK, Items.ROBOT.get(), new RobotSubtypeInterpreter()); - registration.registerSubtypeInterpreter(VanillaTypes.ITEM_STACK, Items.HARD_DRIVE_CUSTOM.get(), new BlockDeviceSubtypeInterpreter()); registration.registerSubtypeInterpreter(VanillaTypes.ITEM_STACK, Items.FLASH_MEMORY_CUSTOM.get(), new BlockDeviceSubtypeInterpreter()); } diff --git a/src/main/java/li/cil/oc2/common/item/AbstractBlockDeviceItem.java b/src/main/java/li/cil/oc2/common/item/AbstractBlockDeviceItem.java index 8b7b7354..835af470 100644 --- a/src/main/java/li/cil/oc2/common/item/AbstractBlockDeviceItem.java +++ b/src/main/java/li/cil/oc2/common/item/AbstractBlockDeviceItem.java @@ -44,7 +44,7 @@ public abstract class AbstractBlockDeviceItem extends ModItem { ResourceLocation location = defaultData; if (!StringUtil.isNullOrEmpty(registryName)) { try { - location = new ResourceLocation(registryName); + location = ResourceLocation.parse(registryName); } catch (final ResourceLocationException ignored) { } } @@ -67,6 +67,7 @@ public abstract class AbstractBlockDeviceItem extends ModItem { return stack; } + @SuppressWarnings("unused") public ItemStack withData(final BlockDeviceData data) { return withData(new ItemStack(this), data); } @@ -87,6 +88,7 @@ public abstract class AbstractBlockDeviceItem extends ModItem { /////////////////////////////////////////////////////////////////// + @SuppressWarnings("unused") protected ResourceLocation getDefaultData() { return defaultData; } diff --git a/src/main/java/li/cil/oc2/common/item/FlashMemoryWithExternalDataItem.java b/src/main/java/li/cil/oc2/common/item/FlashMemoryWithExternalDataItem.java index d1c3a10b..53c76f9c 100644 --- a/src/main/java/li/cil/oc2/common/item/FlashMemoryWithExternalDataItem.java +++ b/src/main/java/li/cil/oc2/common/item/FlashMemoryWithExternalDataItem.java @@ -42,7 +42,7 @@ public final class FlashMemoryWithExternalDataItem extends ModItem { ResourceLocation location = defaultData; if (!StringUtil.isNullOrEmpty(registryName)) { try { - location = new ResourceLocation(registryName); + location = ResourceLocation.parse(registryName); } catch (final ResourceLocationException ignored) { } } @@ -56,15 +56,13 @@ public final class FlashMemoryWithExternalDataItem extends ModItem { } final ResourceLocation key = FirmwareRegistry.getKey(firmware); - if (key == null) { - return ItemStack.EMPTY; - } ItemStackUtils.getOrCreateModDataTag(stack).putString(FIRMWARE_TAG_NAME, key.toString()); return stack; } + @SuppressWarnings("unused") public ItemStack withFirmware(final Firmware firmware) { return withFirmware(new ItemStack(this), firmware); } diff --git a/src/main/java/li/cil/oc2/common/item/HardDriveItem.java b/src/main/java/li/cil/oc2/common/item/HardDriveItem.java index aacff7da..92fae739 100644 --- a/src/main/java/li/cil/oc2/common/item/HardDriveItem.java +++ b/src/main/java/li/cil/oc2/common/item/HardDriveItem.java @@ -35,7 +35,7 @@ public final class HardDriveItem extends AbstractStorageItem implements DyeableL @Override protected String getOrCreateDescriptionId() { if (descriptionId == null) { - descriptionId = Util.makeDescriptionId("item", new ResourceLocation(API.MOD_ID, "hard_drive")); + descriptionId = Util.makeDescriptionId("item", ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "hard_drive")); } return descriptionId; } diff --git a/src/main/java/li/cil/oc2/common/item/HardDriveWithExternalDataItem.java b/src/main/java/li/cil/oc2/common/item/HardDriveWithExternalDataItem.java index 2cf91160..0117082f 100644 --- a/src/main/java/li/cil/oc2/common/item/HardDriveWithExternalDataItem.java +++ b/src/main/java/li/cil/oc2/common/item/HardDriveWithExternalDataItem.java @@ -35,7 +35,7 @@ public final class HardDriveWithExternalDataItem extends AbstractBlockDeviceItem @Override protected String getOrCreateDescriptionId() { if (descriptionId == null) { - descriptionId = Util.makeDescriptionId("item", new ResourceLocation(API.MOD_ID, "hard_drive")); + descriptionId = Util.makeDescriptionId("item", ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "hard_drive")); } return descriptionId; } diff --git a/src/main/java/li/cil/oc2/common/item/ItemGroup.java b/src/main/java/li/cil/oc2/common/item/ItemGroup.java index 3ea3639a..5f0accf5 100644 --- a/src/main/java/li/cil/oc2/common/item/ItemGroup.java +++ b/src/main/java/li/cil/oc2/common/item/ItemGroup.java @@ -53,6 +53,7 @@ public final class ItemGroup { output.accept(Items.CPU_TIER_2.get()); output.accept(Items.CPU_TIER_3.get()); output.accept(Items.CPU_TIER_4.get()); + output.accept(Items.CPU_TIER_INF.get()); output.accept(Items.FLASH_MEMORY.get()); output.accept(Items.FLASH_MEMORY_CUSTOM.get()); output.accept(Items.FLOPPY.get()); diff --git a/src/main/java/li/cil/oc2/common/item/ItemRenameHandler.java b/src/main/java/li/cil/oc2/common/item/ItemRenameHandler.java index 2f26df71..f45e9a7f 100644 --- a/src/main/java/li/cil/oc2/common/item/ItemRenameHandler.java +++ b/src/main/java/li/cil/oc2/common/item/ItemRenameHandler.java @@ -13,11 +13,11 @@ import java.util.Map; import java.util.Objects; import java.util.function.Supplier; +@SuppressWarnings("unused") public final class ItemRenameHandler { private static final Map> RENAMES = Util.make(() -> { final Map> map = new HashMap<>(); - map.put("hard_drive_buildroot", Items.HARD_DRIVE_CUSTOM::get); map.put("flash_memory_buildroot", Items.FLASH_MEMORY_CUSTOM::get); return map; @@ -28,6 +28,7 @@ public final class ItemRenameHandler { /////////////////////////////////////////////////////////////////// @SubscribeEvent + @SuppressWarnings({"rawtypes", "unchecked"}) private static void handleMissingMappings(final MissingMappingsEvent event) { for (final MissingMappingsEvent.Mapping mapping : event.getAllMappings(ResourceKey.createRegistryKey(event.getKey().location()))) { diff --git a/src/main/java/li/cil/oc2/common/item/Items.java b/src/main/java/li/cil/oc2/common/item/Items.java index ed493b25..e3841d1f 100644 --- a/src/main/java/li/cil/oc2/common/item/Items.java +++ b/src/main/java/li/cil/oc2/common/item/Items.java @@ -14,11 +14,11 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; -import li.cil.oc2.common.bus.device.data.FileSystems; import java.util.function.Function; import java.util.function.Supplier; +@SuppressWarnings("unused") public final class Items { private static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.ITEMS, API.MOD_ID); @@ -67,9 +67,6 @@ public final class Items { new HardDriveItem(4 * Config.diskSizeFactor, DyeColor.CYAN)); public static final RegistryObject HARD_DRIVE_EXTRA_LARGE = register("hard_drive_extra_large", () -> new HardDriveItem(16 * Config.diskSizeFactor, DyeColor.YELLOW)); - public static final RegistryObject HARD_DRIVE_CUSTOM = register - ("hard_drive_custom", () -> - new HardDriveWithExternalDataItem(FileSystems.getKeyByValue(FileSystems.getBlockByName("rootfs")), DyeColor.BROWN)); public static final RegistryObject CPU_TIER_1 = register("cpu_tier_1", () -> new CPUItem(25_000_000)); @@ -79,6 +76,8 @@ public final class Items { new CPUItem(100_000_000)); public static final RegistryObject CPU_TIER_4 = register("cpu_tier_4", () -> new CPUItem(200_000_000)); + public static final RegistryObject CPU_TIER_INF = register("cpu_tier_inf", () -> + new CPUItem(1_000_000_000)); public static final RegistryObject FLASH_MEMORY = register("flash_memory", () -> new FlashMemoryItem(12 * Constants.MEGABYTE)); public static final RegistryObject FLASH_MEMORY_CUSTOM = register("flash_memory_custom", () -> @@ -109,8 +108,8 @@ public final class Items { /////////////////////////////////////////////////////////////////// - public static void initialize() { - ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + ITEMS.register(context.getModEventBus()); } /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/item/MemoryItem.java b/src/main/java/li/cil/oc2/common/item/MemoryItem.java index a8aee5bc..be3458c3 100644 --- a/src/main/java/li/cil/oc2/common/item/MemoryItem.java +++ b/src/main/java/li/cil/oc2/common/item/MemoryItem.java @@ -22,7 +22,7 @@ public final class MemoryItem extends AbstractStorageItem { @Override protected String getOrCreateDescriptionId() { if (descriptionId == null) { - descriptionId = Util.makeDescriptionId("item", new ResourceLocation(API.MOD_ID, "memory")); + descriptionId = Util.makeDescriptionId("item", ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "memory")); } return descriptionId; } diff --git a/src/main/java/li/cil/oc2/common/item/crafting/RecipeSerializers.java b/src/main/java/li/cil/oc2/common/item/crafting/RecipeSerializers.java index d0e70608..3775eb86 100644 --- a/src/main/java/li/cil/oc2/common/item/crafting/RecipeSerializers.java +++ b/src/main/java/li/cil/oc2/common/item/crafting/RecipeSerializers.java @@ -18,7 +18,7 @@ public final class RecipeSerializers { /////////////////////////////////////////////////////////////////// - public static void initialize() { - RECIPE_SERIALIZERS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + RECIPE_SERIALIZERS.register(context.getModEventBus()); } } diff --git a/src/main/java/li/cil/oc2/common/network/Network.java b/src/main/java/li/cil/oc2/common/network/Network.java index d49e3db0..a9291163 100644 --- a/src/main/java/li/cil/oc2/common/network/Network.java +++ b/src/main/java/li/cil/oc2/common/network/Network.java @@ -25,7 +25,7 @@ public final class Network { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel( - new ResourceLocation(API.MOD_ID, "main"), + ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals diff --git a/src/main/java/li/cil/oc2/common/serialization/ceres/ColorDataSerializer.java b/src/main/java/li/cil/oc2/common/serialization/ceres/ColorDataSerializer.java new file mode 100644 index 00000000..af496b42 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/serialization/ceres/ColorDataSerializer.java @@ -0,0 +1,31 @@ +package li.cil.oc2.common.serialization.ceres; + +import com.google.gson.Gson; +import li.cil.ceres.api.DeserializationVisitor; +import li.cil.ceres.api.SerializationException; +import li.cil.ceres.api.SerializationVisitor; +import li.cil.ceres.api.Serializer; +import li.cil.oc2.common.vm.terminal.Terminal; +import org.jetbrains.annotations.Nullable; + +public class ColorDataSerializer implements Serializer { + @Override + public void serialize(final SerializationVisitor serializationVisitor, final Class aClass, final Object o) throws SerializationException { + final String json = new Gson().toJson(o); + serializationVisitor.putObject("value", String.class, json); + } + + @Override + public Terminal.ColorData deserialize(final DeserializationVisitor deserializationVisitor, final Class aClass, @Nullable final Object o) throws SerializationException { + if (!deserializationVisitor.exists("value")) { + return new Terminal.ColorData(); + } + + final String json = (String) deserializationVisitor.getObject("value", String.class, null); + if (json == null) { + return new Terminal.ColorData(); + } + + return new Gson().fromJson(json, Terminal.ColorData.class); + } +} diff --git a/src/main/java/li/cil/oc2/common/serialization/ceres/ColorModeSerializer.java b/src/main/java/li/cil/oc2/common/serialization/ceres/ColorModeSerializer.java new file mode 100644 index 00000000..f47830f6 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/serialization/ceres/ColorModeSerializer.java @@ -0,0 +1,32 @@ +package li.cil.oc2.common.serialization.ceres; + +import com.google.gson.Gson; +import li.cil.ceres.api.DeserializationVisitor; +import li.cil.ceres.api.SerializationException; +import li.cil.ceres.api.SerializationVisitor; +import li.cil.ceres.api.Serializer; +import li.cil.oc2.common.vm.terminal.Terminal; +import org.jetbrains.annotations.Nullable; + +public class ColorModeSerializer implements Serializer { + + @Override + public void serialize(final SerializationVisitor serializationVisitor, final Class aClass, final Object o) throws SerializationException { + final String json = new Gson().toJson(o); + serializationVisitor.putObject("value", String.class, json); + } + + @Override + public Terminal.ColorMode deserialize(final DeserializationVisitor deserializationVisitor, final Class aClass, @Nullable final Object value) throws SerializationException { + if (!deserializationVisitor.exists("value")) { + return Terminal.ColorMode.SIXTEEN_COLOR; + } + + final String json = (String) deserializationVisitor.getObject("value", String.class, null); + if (json == null) { + return Terminal.ColorMode.SIXTEEN_COLOR; + } + + return new Gson().fromJson(json, Terminal.ColorMode.class); + } +} diff --git a/src/main/java/li/cil/oc2/common/serialization/ceres/Serializers.java b/src/main/java/li/cil/oc2/common/serialization/ceres/Serializers.java index 7dddaf78..b0a76815 100644 --- a/src/main/java/li/cil/oc2/common/serialization/ceres/Serializers.java +++ b/src/main/java/li/cil/oc2/common/serialization/ceres/Serializers.java @@ -4,6 +4,7 @@ package li.cil.oc2.common.serialization.ceres; import com.google.gson.JsonArray; import li.cil.ceres.Ceres; +import li.cil.oc2.common.vm.terminal.Terminal; import li.cil.oc2.common.vm.context.global.MemoryRangeList; import li.cil.sedna.api.memory.MemoryRange; import net.minecraft.network.chat.Component; @@ -26,5 +27,7 @@ public final class Serializers { Ceres.putSerializer(Component.class, new TextComponentSerializer()); Ceres.putSerializer(MemoryRange.class, new MemoryRangeSerializer()); Ceres.putSerializer(MemoryRangeList.class, new MemoryRangeListSerializer()); + Ceres.putSerializer(Terminal.ColorMode.class, new ColorModeSerializer()); + Ceres.putSerializer(Terminal.ColorData.class, new ColorDataSerializer()); } } diff --git a/src/main/java/li/cil/oc2/common/tags/BlockTags.java b/src/main/java/li/cil/oc2/common/tags/BlockTags.java index 18fed1e6..d91cc850 100644 --- a/src/main/java/li/cil/oc2/common/tags/BlockTags.java +++ b/src/main/java/li/cil/oc2/common/tags/BlockTags.java @@ -21,6 +21,6 @@ public final class BlockTags { /////////////////////////////////////////////////////////////////// private static TagKey tag(final String name) { - return TagKey.create(Registries.BLOCK, new ResourceLocation(API.MOD_ID, name)); + return TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath(API.MOD_ID, name)); } } diff --git a/src/main/java/li/cil/oc2/common/tags/ItemTags.java b/src/main/java/li/cil/oc2/common/tags/ItemTags.java index 6a96597b..c97b3293 100644 --- a/src/main/java/li/cil/oc2/common/tags/ItemTags.java +++ b/src/main/java/li/cil/oc2/common/tags/ItemTags.java @@ -31,6 +31,6 @@ public final class ItemTags { /////////////////////////////////////////////////////////////////// private static TagKey tag(final String name) { - return TagKey.create(Registries.ITEM, new ResourceLocation(API.MOD_ID, name)); + return TagKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(API.MOD_ID, name)); } } diff --git a/src/main/java/li/cil/oc2/common/util/RegistryUtils.java b/src/main/java/li/cil/oc2/common/util/RegistryUtils.java index 0598ce9e..57ff6175 100644 --- a/src/main/java/li/cil/oc2/common/util/RegistryUtils.java +++ b/src/main/java/li/cil/oc2/common/util/RegistryUtils.java @@ -13,11 +13,13 @@ import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import net.minecraftforge.registries.DeferredRegister; import net.minecraftforge.registries.IForgeRegistry; +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Optional; +@SuppressWarnings("unused") public abstract class RegistryUtils { private enum Phase { PRE_INIT, @@ -49,12 +51,12 @@ public abstract class RegistryUtils { phase = Phase.INIT; } - public static void finish() { + public static void finish(FMLJavaModLoadingContext context) { if (phase != Phase.INIT) throw new IllegalStateException(); phase = Phase.POST_INIT; for (final DeferredRegister register : ENTRIES) { - register.register(FMLJavaModLoadingContext.get().getModEventBus()); + register.register(context.getModEventBus()); } ENTRIES.clear(); @@ -64,7 +66,7 @@ public abstract class RegistryUtils { return Objects.requireNonNull(registryEntry.getName()).toString(); } - public static Optional optionalKey(final T registryEntry) { + public static Optional optionalKey(@Nullable final T registryEntry) { if(registryEntry == null) { return Optional.empty(); } diff --git a/src/main/java/li/cil/oc2/common/util/SoundEvents.java b/src/main/java/li/cil/oc2/common/util/SoundEvents.java index ac1e32de..f225e5aa 100644 --- a/src/main/java/li/cil/oc2/common/util/SoundEvents.java +++ b/src/main/java/li/cil/oc2/common/util/SoundEvents.java @@ -23,13 +23,13 @@ public final class SoundEvents { /////////////////////////////////////////////////////////////////// - public static void initialize() { - SOUNDS.register(FMLJavaModLoadingContext.get().getModEventBus()); + public static void initialize(FMLJavaModLoadingContext context) { + SOUNDS.register(context.getModEventBus()); } /////////////////////////////////////////////////////////////////// private static RegistryObject register(final String name) { - return SOUNDS.register(name, () -> SoundEvent.createVariableRangeEvent(new ResourceLocation(API.MOD_ID, name))); + return SOUNDS.register(name, () -> SoundEvent.createVariableRangeEvent(ResourceLocation.fromNamespaceAndPath(API.MOD_ID, name))); } } diff --git a/src/main/java/li/cil/oc2/common/util/TerminalUtils.java b/src/main/java/li/cil/oc2/common/util/TerminalUtils.java index e0cb0d88..fca0eb16 100644 --- a/src/main/java/li/cil/oc2/common/util/TerminalUtils.java +++ b/src/main/java/li/cil/oc2/common/util/TerminalUtils.java @@ -2,7 +2,7 @@ package li.cil.oc2.common.util; -import li.cil.oc2.common.vm.Terminal; +import li.cil.oc2.common.vm.terminal.Terminal; import java.nio.ByteBuffer; import java.util.function.Consumer; diff --git a/src/main/java/li/cil/oc2/common/vm/AbstractTerminalVMRunner.java b/src/main/java/li/cil/oc2/common/vm/AbstractTerminalVMRunner.java index 0928f717..d2dfa6e2 100644 --- a/src/main/java/li/cil/oc2/common/vm/AbstractTerminalVMRunner.java +++ b/src/main/java/li/cil/oc2/common/vm/AbstractTerminalVMRunner.java @@ -3,6 +3,7 @@ package li.cil.oc2.common.vm; import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue; +import li.cil.oc2.common.vm.terminal.Terminal; import li.cil.sedna.device.serial.UART16550A; import java.nio.ByteBuffer; diff --git a/src/main/java/li/cil/oc2/common/vm/Terminal.java b/src/main/java/li/cil/oc2/common/vm/OldTerminal.java similarity index 65% rename from src/main/java/li/cil/oc2/common/vm/Terminal.java rename to src/main/java/li/cil/oc2/common/vm/OldTerminal.java index c5007c09..ea832c70 100644 --- a/src/main/java/li/cil/oc2/common/vm/Terminal.java +++ b/src/main/java/li/cil/oc2/common/vm/OldTerminal.java @@ -2,6 +2,7 @@ package li.cil.oc2.common.vm; +import com.google.gson.annotations.SerializedName; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.*; import org.joml.Matrix4f; @@ -26,11 +27,15 @@ import java.util.WeakHashMap; import java.util.concurrent.atomic.AtomicInteger; // VT100 emulation: https://vt100.net/docs/vt100-ug/chapter3.html +// Still around in case of needing to look back when new bugs surface @Serialized -public final class Terminal { +@SuppressWarnings("all") +public final class OldTerminal { public static final int WIDTH = 80, HEIGHT = 24; public static final int CHAR_WIDTH = 8; public static final int CHAR_HEIGHT = 16; + public MouseMode CurrentMouseMode = MouseMode.None; + public boolean Use1006 = false; private static final int TAB_WIDTH = 4; @@ -74,7 +79,10 @@ public final class Terminal { private static final byte DEFAULT_COLORS = Color.WHITE << COLOR_FOREGROUND_SHIFT; private static final byte DEFAULT_STYLE = 0; - /////////////////////////////////////////////////////////////////// + private static final ColorData DEFAULT_TRUE_COLOR_FOREGROUND = new ColorData(238, 238, 238); + private static final ColorData DEFAULT_TRUE_COLOR_BACKGROUND = new ColorData(0, 0, 0); + + /// //////////////////////////////////////////////////////////////// public enum State { // Must be public for serialization. NORMAL, // Reading characters normally. @@ -82,22 +90,72 @@ public final class Terminal { SHIFT_IN_CHARACTER_SET, // Shift in character set. SHIFT_OUT_CHARACTER_SET, // Shift out character set. HASH, // Escape sequence with # intermediate. + DCS, + OSC, CONTROL_SEQUENCE, // Know what sequence we have, now parsing it. } + public static class ColorData { + public int R; + public int G; + public int B; + + public ColorData() { + R = 0; + G = 0; + B = 0; + } + + public ColorData(final int r, final int g, final int b) { + R = r; + G = g; + B = b; + } + + public int asInt() { + return (((R & 0b11111111) << 16) | ((G & 0b11111111) << 8) | (B & 0b11111111)); + } + } + + public ColorData fromByte(byte color) { + return new ColorData(color, 0, 0); + } + + public enum ColorMode { + @SerializedName("0") + SIXTEEN_COLOR, + @SerializedName("1") + TWO_FIFTY_SIX_COLOR, + @SerializedName("2") + TWENTY_FOUR_BIT_COLOR + } + + public enum MouseMode { + @SerializedName("0") + None, + @SerializedName("1") + X10Compat, + @SerializedName("2") + Normal, + @SerializedName("3") + MouseHilite + } + public interface RendererView { void render(final PoseStack stack, final Matrix4f projectionMatrix); } - /////////////////////////////////////////////////////////////////// + /// //////////////////////////////////////////////////////////////// private final ByteArrayFIFOQueue input = new ByteArrayFIFOQueue(32); private final byte[] buffer = new byte[WIDTH * HEIGHT]; - private final byte[] colors = new byte[WIDTH * HEIGHT]; + private final ColorMode[] colorModes = new ColorMode[WIDTH * HEIGHT]; + private final ColorData[] colors = new ColorData[WIDTH * HEIGHT]; + private final ColorData[] colorsBackground = new ColorData[WIDTH * HEIGHT]; // only used for TrueColor private final byte[] styles = new byte[WIDTH * HEIGHT]; private final boolean[] tabs = new boolean[WIDTH]; private State state = State.NORMAL; - private final int[] args = new int[4]; + private final int[] args = new int[5]; private int argCount = 0; private int modes; private int scrollFirst = 0, scrollLast = HEIGHT - 1; @@ -107,7 +165,15 @@ public final class Terminal { // Color info packed into one byte for compact storage // 0-2: background color (index) // 3-5: foreground color (index) - private byte color; + private ColorData color; + // 256 color + private boolean enable256; + private byte foregroundColor256; + private byte backgroundColor256; + // true color + private boolean trueColor; + private ColorData backgroundColor; + private ColorData foregroundColor; // Style info packed into one byte for compact storage private byte style; @@ -115,14 +181,15 @@ public final class Terminal { private final transient Set renderers = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>())); private transient boolean displayOnly; // Set on client to not send responses to status requests. private transient boolean hasPendingBell; + private char lastChar; - /////////////////////////////////////////////////////////////////// + /// //////////////////////////////////////////////////////////////// - public Terminal() { + public OldTerminal() { RIS(); } - /////////////////////////////////////////////////////////////////// + /// //////////////////////////////////////////////////////////////// public int getWidth() { return WIDTH * CHAR_WIDTH; @@ -183,6 +250,10 @@ public final class Terminal { } } + public synchronized void putInput(final String value) { + putInput(ByteBuffer.wrap(value.getBytes())); + } + public synchronized void putInput(final ByteBuffer values) { while (values.hasRemaining()) { input.enqueue(values.get()); @@ -195,6 +266,8 @@ public final class Terminal { } } + public synchronized void putInput(final char value) { putInput((byte) value); } + public synchronized void putInput(final byte value) { input.enqueue(value); } @@ -206,8 +279,10 @@ public final class Terminal { switch (value) { case '\007' -> hasPendingBell = true; case '\033' -> state = State.ESCAPE; - case '\016' -> { } // SO - case '\017' -> { } // SI + case '\016' -> { + } // SO + case '\017' -> { + } // SI case (byte) '\r' /* 015 */ -> setCursorPos(0, y); case (byte) '\n' /* 012 */, '\013', '\014' -> { @@ -240,6 +315,10 @@ public final class Terminal { state = State.SHIFT_OUT_CHARACTER_SET; } else if (ch == '#') { // # Intermediate state = State.HASH; + } else if (ch == 'P') { + state = State.DCS; + } else if (ch == ']') { + state = State.OSC; } else { state = State.NORMAL; switch (ch) { @@ -250,8 +329,11 @@ public final class Terminal { case '8' -> DECRC(); // DECRC – Restore Cursor (DEC Private) case 'H' -> HTS(); // HTS – Horizontal Tabulation Set case 'c' -> RIS(); // RIS – Reset To Initial State - case '=' -> { } // DECKPAM – Keypad Application Mode (DEC Private) - case '>' -> { } // DECKPNM – Keypad Numeric Mode (DEC Private) + case '=' -> { + } // DECKPAM – Keypad Application Mode (DEC Private) + case '>' -> { + } // DECKPNM – Keypad Numeric Mode (DEC Private) + default -> System.out.println("Invalid escape: " + ch); } } } @@ -295,32 +377,87 @@ public final class Terminal { case 'l' -> RM(); // RM – Reset Mode case 'n' -> DSR(); // DSR – Device Status Report case 'c' -> DA(); // DA – Device Attributes + case 'd' -> { + setClampedCursorPos(x, args[0] - 1); + } + case 'G' -> { + setClampedCursorPos(args[0] - 1, y); + } + case 't' -> { + if (args[0] == 14) { + putInput("\033[4;80;24t"); + } + } + case 'L' -> IL(); + case 'M' -> DL(); + case '>' -> { + if (args[0] == 6) { + putInput("\033[" + (y + 1) + ";" + (x + 1) + "R"); + return; + } else if (args[0] == 0) { + //putInput("\033[0>"); // Don't respond? + return; + } + System.out.println("Invalid parameter: " + args[0]); + } + case '%' -> { + System.out.println("%: " + argCount); + + for(int i = 0; i < argCount; i++) System.out.println(args[i]); + } + default -> { + System.out.println("Control sequence: " + ch); + } } } } case SHIFT_IN_CHARACTER_SET, SHIFT_OUT_CHARACTER_SET -> { state = State.NORMAL; switch (ch) { - case 'A' -> { } // United Kingdom Set - case 'B' -> { } // ASCII Set - case '0' -> { } // Special Graphics - case '1' -> { } // Alternate Character ROM Standard Character Set - case '2' -> { } // Alternate Character ROM Special Graphics + case 'A' -> { + } // United Kingdom Set + case 'B' -> { + } // ASCII Set + case '0' -> { + } // Special Graphics + case '1' -> { + } // Alternate Character ROM Standard Character Set + case '2' -> { + } // Alternate Character ROM Special Graphics } } case HASH -> { state = State.NORMAL; switch (ch) { - case '3' -> { } // Change this line to double-height top half (DECDHL) - case '4' -> { } // Change this line to double-height bottom half (DECDHL) - case '5' -> { } // Change this line to single-width single-height (DECSWL) - case '6' -> { } // Change this line to double-width single-height (DECDWL) + case '3' -> { + } // Change this line to double-height top half (DECDHL) + case '4' -> { + } // Change this line to double-height bottom half (DECDHL) + case '5' -> { + } // Change this line to single-width single-height (DECSWL) + case '6' -> { + } // Change this line to double-width single-height (DECDWL) case '8' -> { // Fill Screen with Es (DECALN) Arrays.fill(buffer, (byte) 'E'); renderers.forEach(model -> model.getDirtyMask().set(-1)); } } } + case DCS -> { + if (lastChar == '\033' && ch == '\\') { + state = State.NORMAL; + } else { + lastChar = ch; + } + // Used for mapping Function keys and possibly other things + } + case OSC -> { + if (lastChar == '\033' && ch == '\\' || ch == '\007') { + state = State.NORMAL; + } else { + lastChar = ch; + } + } } } @@ -359,6 +496,24 @@ public final class Terminal { y = savedY; } + private void IL() { + int lines = args[0]; + + shiftLines(y, scrollLast-1, (Math.max(1, lines))); + } + + private void DL() { + int lines = args[0]; + + setCursorPos(0, y); + + for (int i = 0; i < Math.max(1, lines); i++) { + clearLine(y + i); + } + + shiftLines(y + (Math.max(1, lines)), scrollLast, -(Math.max(1, lines))); + } + private void HTS() { if (x >= 0 && x < WIDTH) { tabs[x] = true; @@ -366,8 +521,14 @@ public final class Terminal { } private void RIS() { - color = DEFAULT_COLORS; + enable256 = false; + trueColor = false; + Use1006 = false; + color = fromByte(DEFAULT_COLORS); + backgroundColor = null; + foregroundColor = null; style = DEFAULT_STYLE; + CurrentMouseMode = MouseMode.None; clear(); Arrays.fill(tabs, false); for (int i = 1; i < WIDTH; i++) { @@ -402,6 +563,35 @@ public final class Terminal { } private void SGR() { + if (args[0] == 38 || args[0] == 48) { + if (args[0] == 38) { + if (args[1] == 5) { + // 256 + enable256 = true; + trueColor = false; + foregroundColor256 = (byte) args[2]; + } else if (args[1] == 2) { + // true color + enable256 = false; + trueColor = true; + foregroundColor = new ColorData(args[2], args[3], args[4]); + } + } else { + if (args[1] == 5) { + // 256 + enable256 = true; + trueColor = false; + backgroundColor256 = (byte) args[2]; + } else if (args[1] == 2) { + // true color + enable256 = false; + trueColor = true; + backgroundColor = new ColorData(args[2], args[3], args[4]); + } + } + + return; + } for (int i = 0; i < argCount; i++) { selectStyle(args[i]); } @@ -469,6 +659,31 @@ public final class Terminal { private void SM() { for (int i = 0; i < argCount; i++) { final int mode = args[i]; + if (mode == 1000) { + CurrentMouseMode = MouseMode.Normal; + System.out.println("Current mouse mode: " + CurrentMouseMode); + continue; + } else if (mode == 1001) { + CurrentMouseMode = MouseMode.MouseHilite; + System.out.println("Current mouse mode: " + CurrentMouseMode); + continue; + } else if (mode == 9) { + CurrentMouseMode = MouseMode.X10Compat; + System.out.println("Current mouse mode: " + CurrentMouseMode); + continue; + } else if (mode == 1005) { + System.out.println("bad1"); + } else if (mode == 1006) { + Use1006 = true; + continue; + } else if (mode == 1015) { + System.out.println("bad3"); + continue; + } else if (mode == 1016) { + System.out.println("bad4"); + continue; + } + if (mode != 0) { setMode(mode); } @@ -481,6 +696,14 @@ public final class Terminal { private void RM() { for (int i = 0; i < argCount; i++) { final int mode = args[i]; + if (mode == 9 || mode == 1000 || mode == 1001) { + CurrentMouseMode = MouseMode.None; + System.out.println("Current mouse mode: " + CurrentMouseMode); + continue; + } else if (mode == 1006) { + Use1006 = false; + continue; + } if (mode != 0) { resetMode(mode); } @@ -536,8 +759,14 @@ public final class Terminal { private void selectStyle(final int sgr) { switch (sgr) { case 0 -> { // Reset / Normal - color = DEFAULT_COLORS; + color = fromByte(DEFAULT_COLORS); style = DEFAULT_STYLE; + enable256 = false; + trueColor = false; + foregroundColor256 = 0; + backgroundColor256 = 0; + foregroundColor = null; + backgroundColor = null; } case 1 -> // Bold or increased intensity style |= STYLE_BOLD_MASK; @@ -550,7 +779,9 @@ public final class Terminal { case 7 -> // Negative (reverse) image style |= STYLE_INVERT_MASK; case 8 -> // Conceal aka Hide + { style |= STYLE_HIDDEN_MASK; + } case 22 -> // Normal color or intensity style &= ~(STYLE_BOLD_MASK | STYLE_DIM_MASK); case 24 -> // Underline off @@ -560,14 +791,21 @@ public final class Terminal { case 27 -> // Reverse/invert off style &= ~STYLE_INVERT_MASK; case 28 -> // Reveal conceal off + { style &= ~STYLE_HIDDEN_MASK; + } case 30, 31, 32, 33, 34, 35, 36, 37 -> { // Set foreground color + enable256 = false; + trueColor = false; final int color = sgr - 30; - this.color = (byte) ((this.color & ~(COLOR_MASK << COLOR_FOREGROUND_SHIFT)) | (color << COLOR_FOREGROUND_SHIFT)); + System.out.println(color); + this.color = fromByte((byte) ((this.color.R & ~(COLOR_MASK << COLOR_FOREGROUND_SHIFT)) | (color << COLOR_FOREGROUND_SHIFT))); } case 40, 41, 42, 43, 44, 45, 46, 47 -> { //–47 Set background color + enable256 = false; + trueColor = false; final int color = sgr - 40; - this.color = (byte) ((this.color & ~COLOR_MASK) | color); + this.color = fromByte((byte) ((this.color.R & ~COLOR_MASK) | color)); } } } @@ -607,23 +845,31 @@ public final class Terminal { private void setChar(final int x, final int y, final char ch) { final int index = x + y * WIDTH; - if (buffer[index] == ch && - colors[index] == color && - styles[index] == style) { - return; - } buffer[index] = (byte) ch; - colors[index] = color; + if (!enable256 && !trueColor) { + colorModes[index] = ColorMode.SIXTEEN_COLOR; + colors[index] = color; + } else if (enable256) { + colorModes[index] = ColorMode.TWO_FIFTY_SIX_COLOR; + colors[index] = new ColorData((backgroundColor256 & ~(0b11111111 << 8)) | (foregroundColor256 << 8), 0, 0); + } else { + colorModes[index] = ColorMode.TWENTY_FOUR_BIT_COLOR; + colors[index] = (foregroundColor != null) ? foregroundColor : DEFAULT_TRUE_COLOR_FOREGROUND; + colorsBackground[index] = (backgroundColor != null) ? backgroundColor : DEFAULT_TRUE_COLOR_BACKGROUND; + } + styles[index] = style; renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(1 << y, (prev, next) -> prev | next)); } private void clear() { Arrays.fill(buffer, (byte) ' '); - Arrays.fill(colors, DEFAULT_COLORS); + Arrays.fill(colorModes, ColorMode.SIXTEEN_COLOR); + Arrays.fill(colors, fromByte(DEFAULT_COLORS)); + Arrays.fill(colorsBackground, fromByte(DEFAULT_COLORS)); Arrays.fill(styles, DEFAULT_STYLE); - setCursorPos(0,0); + setCursorPos(0, 0); renderers.forEach(model -> model.getDirtyMask().set(-1)); } @@ -632,8 +878,12 @@ public final class Terminal { } private void clearLine(final int y, final int fromIndex, final int toIndex) { + enable256 = false; + trueColor = false; Arrays.fill(buffer, y * WIDTH + fromIndex, y * WIDTH + toIndex, (byte) ' '); - Arrays.fill(colors, y * WIDTH + fromIndex, y * WIDTH + toIndex, DEFAULT_COLORS); + Arrays.fill(colorModes, y * WIDTH + fromIndex, y * WIDTH + toIndex, ColorMode.SIXTEEN_COLOR); + Arrays.fill(colors, y * WIDTH + fromIndex, y * WIDTH + toIndex, fromByte(DEFAULT_COLORS)); + Arrays.fill(colorsBackground, y * WIDTH + fromIndex, y * WIDTH + toIndex, fromByte(DEFAULT_COLORS)); Arrays.fill(styles, y * WIDTH + fromIndex, y * WIDTH + toIndex, DEFAULT_STYLE); renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(1 << y, (prev, next) -> prev | next)); } @@ -655,7 +905,9 @@ public final class Terminal { final int dstIndex = srcIndex + count * WIDTH; System.arraycopy(buffer, srcIndex, buffer, dstIndex, charCount); + System.arraycopy(colorModes, srcIndex, colorModes, dstIndex, charCount); System.arraycopy(colors, srcIndex, colors, dstIndex, charCount); + System.arraycopy(colorsBackground, srcIndex, colorsBackground, dstIndex, charCount); System.arraycopy(styles, srcIndex, styles, dstIndex, charCount); final int clearIndex = count > 0 ? srcIndex : (dstIndex + charCount); @@ -663,7 +915,9 @@ public final class Terminal { Arrays.fill(buffer, clearIndex, clearIndex + clearCount, (byte) ' '); // TODO Copy color and style from last line. // TODO Copy color and style from last line. - Arrays.fill(colors, clearIndex, clearIndex + clearCount, DEFAULT_COLORS); + Arrays.fill(colorModes, clearIndex, clearIndex + clearCount, ColorMode.SIXTEEN_COLOR); + Arrays.fill(colors, clearIndex, clearIndex + clearCount, fromByte(DEFAULT_COLORS)); + Arrays.fill(colorsBackground, clearIndex, clearIndex + clearCount, fromByte(DEFAULT_COLORS)); Arrays.fill(styles, clearIndex, clearIndex + clearCount, DEFAULT_STYLE); int dirtyLinesMask = 0; @@ -674,9 +928,12 @@ public final class Terminal { } final int finalDirtyLinesMask = dirtyLinesMask; renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + + enable256 = false; + trueColor = false; } - /////////////////////////////////////////////////////////////////// + /// //////////////////////////////////////////////////////////////// private interface RendererModel { AtomicInteger getDirtyMask(); @@ -686,14 +943,14 @@ public final class Terminal { @OnlyIn(Dist.CLIENT) private static final class Renderer implements RendererModel, RendererView { - private static final ResourceLocation LOCATION_FONT_TEXTURE = new ResourceLocation(API.MOD_ID, "textures/font/terminus.png"); + private static final ResourceLocation LOCATION_FONT_TEXTURE = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "textures/font/terminus.png"); private static final int TEXTURE_RESOLUTION = 256; private static final float ONE_OVER_TEXTURE_RESOLUTION = 1.0f / (float) TEXTURE_RESOLUTION; private static final int TEXTURE_COLUMNS = 16; private static final int TEXTURE_BOLD_SHIFT = TEXTURE_COLUMNS; // Bold chars are in right half of texture. private static final int[] COLORS = { - 0x010101, // Black + 0x555555, // Black 0xEE3322, // Red 0x33DD44, // Green 0xFFCC11, // Yellow @@ -714,20 +971,49 @@ public final class Terminal { 0x777777, // White }; - /////////////////////////////////////////////////////////////// + private static final int[] COLORS_256 = { + 0x000000, 0x800000, 0x008000, 0x808000, 0x000080, 0x800080, 0x008080, 0xc0c0c0, 0x808080, 0xff0000, + 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff, 0x000000, 0x00005f, 0x000087, 0x0000af, + 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, 0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, + 0x008787, 0x0087af, 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, + 0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, 0x00ff87, 0x00ffaf, + 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, + 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, + 0x5faf00, 0x5faf5f, 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af, + 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, 0x870000, 0x87005f, + 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, 0x875f87, 0x875faf, 0x875fd7, 0x875fff, + 0x878700, 0x87875f, 0x878787, 0x8787af, 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, + 0x87afd7, 0x87afff, 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f, + 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, 0xaf00d7, 0xaf00ff, + 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, + 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f, 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, + 0xafd787, 0xafd7af, 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, + 0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, 0xd75f87, 0xd75faf, + 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af, 0xd787d7, 0xd787ff, 0xdfaf00, 0xdfaf5f, + 0xdfaf87, 0xdfafaf, 0xdfafdf, 0xdfafff, 0xdfdf00, 0xdfdf5f, 0xdfdf87, 0xdfdfaf, 0xdfdfdf, 0xdfdfff, + 0xdfff00, 0xdfff5f, 0xdfff87, 0xdfffaf, 0xdfffdf, 0xdfffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af, + 0xff00df, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fdf, 0xff5fff, 0xff8700, 0xff875f, + 0xff8787, 0xff87af, 0xff87df, 0xff87ff, 0xffaf00, 0xffaf5f, 0xffaf87, 0xffafaf, 0xffafdf, 0xffafff, + 0xffdf00, 0xffdf5f, 0xffdf87, 0xffdfaf, 0xffdfdf, 0xffdfff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, + 0xffffdf, 0xffffff, 0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, + 0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, 0xa8a8a8, 0xb2b2b2, + 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee + }; - private final Terminal terminal; + /// //////////////////////////////////////////////////////////// + + private final OldTerminal terminal; private final VertexBuffer[] lines = new VertexBuffer[HEIGHT]; private final AtomicInteger dirty = new AtomicInteger(-1); - /////////////////////////////////////////////////////////////// + /// //////////////////////////////////////////////////////////// - public Renderer(final Terminal terminal) { + public Renderer(final OldTerminal terminal) { this.terminal = terminal; } - /////////////////////////////////////////////////////////////// + /// //////////////////////////////////////////////////////////// @Override public void render(final PoseStack stack, final Matrix4f projectionMatrix) { @@ -755,7 +1041,7 @@ public final class Terminal { } } - /////////////////////////////////////////////////////////////// + /// //////////////////////////////////////////////////////////// private int findLineIndex(VertexBuffer[] vba, VertexBuffer vb) { int i = 0; @@ -799,7 +1085,6 @@ public final class Terminal { } - final int mask = dirty.getAndSet(0); for (int row = 0; row < lines.length; row++) { if ((mask & (1 << row)) == 0) { @@ -818,12 +1103,12 @@ public final class Terminal { if (lines[row] == null) { lines[row] = new VertexBuffer(VertexBuffer.Usage.DYNAMIC); - }else if (lines[row] != null) { + } else if (lines[row] != null) { lines[row].close(); lines[row] = new VertexBuffer(VertexBuffer.Usage.DYNAMIC); } - if (!lines[row].isInvalid()){ + if (!lines[row].isInvalid()) { lines[row].bind(); lines[row].upload(rb); VertexBuffer.unbind(); @@ -838,16 +1123,34 @@ public final class Terminal { float tx = 0f; for (int col = 0, index = row * WIDTH; col < WIDTH; col++, index++) { - final byte colors = terminal.colors[index]; + final ColorMode colorMode = terminal.colorModes[index]; + final ColorData colors = terminal.colors[index]; final byte style = terminal.styles[index]; if ((style & STYLE_HIDDEN_MASK) != 0) continue; final int[] palette = (style & STYLE_DIM_MASK) != 0 ? DIM_COLORS : COLORS; - - final int foregroundIndex = (colors >> COLOR_FOREGROUND_SHIFT) & COLOR_MASK; - final int backgroundIndex = colors & COLOR_MASK; - final int background = palette[(style & STYLE_INVERT_MASK) == 0 ? backgroundIndex : foregroundIndex]; + int background; + int foregroundIndex; + int backgroundIndex; + switch (colorMode) { + case SIXTEEN_COLOR: + foregroundIndex = (colors.R >> COLOR_FOREGROUND_SHIFT) & COLOR_MASK; + backgroundIndex = colors.R & COLOR_MASK; + background = palette[(style & STYLE_INVERT_MASK) == 0 ? backgroundIndex : foregroundIndex]; + break; + case TWO_FIFTY_SIX_COLOR: + foregroundIndex = (char)((colors.R >> 8) & 0b11111111); + backgroundIndex = (char)(colors.R & 0b11111111); + background = COLORS_256[(style & STYLE_INVERT_MASK) == 0 ? backgroundIndex : foregroundIndex]; + break; + case TWENTY_FOUR_BIT_COLOR: + background = terminal.colorsBackground[index].asInt(); + break; + default: + background = colors.R & COLOR_MASK; + break; + } final boolean hadBackground = backgroundStartX >= 0; final boolean hasBackground = background != palette[0]; @@ -890,16 +1193,34 @@ public final class Terminal { private void renderForeground(final Matrix4f matrix, final BufferBuilder buffer, final int row) { float tx = 0f; for (int col = 0, index = row * WIDTH; col < WIDTH; col++, index++) { - final byte colors = terminal.colors[index]; + final ColorMode colorMode = terminal.colorModes[index]; + final ColorData color = terminal.colors[index]; final byte style = terminal.styles[index]; if ((style & STYLE_HIDDEN_MASK) != 0) continue; - final int[] palette = (style & STYLE_DIM_MASK) != 0 ? DIM_COLORS : COLORS; - - final int foregroundIndex = (colors >> COLOR_FOREGROUND_SHIFT) & COLOR_MASK; - final int backgroundIndex = colors & COLOR_MASK; - final int foreground = palette[(style & STYLE_INVERT_MASK) == 0 ? foregroundIndex : backgroundIndex]; + int foreground; + int foregroundIndex; + int backgroundIndex; + switch (colorMode) { + case SIXTEEN_COLOR: + final int[] palette = (style & STYLE_DIM_MASK) != 0 ? DIM_COLORS : COLORS; + foregroundIndex = (color.R >> COLOR_FOREGROUND_SHIFT) & COLOR_MASK; + backgroundIndex = color.R & COLOR_MASK; + foreground = palette[(style & STYLE_INVERT_MASK) == 0 ? foregroundIndex : backgroundIndex]; + break; + case TWO_FIFTY_SIX_COLOR: + foregroundIndex = (char)((color.R >> 8) & 0b11111111); + backgroundIndex = (char)(color.R & 0b11111111); + foreground = COLORS_256[(style & STYLE_INVERT_MASK) == 0 ? foregroundIndex : backgroundIndex]; + break; + case TWENTY_FOUR_BIT_COLOR: + foreground = terminal.colors[index].asInt(); + break; + default: + foreground = color.R & COLOR_MASK; + break; + } final int character = terminal.buffer[index] & 0xFF; @@ -980,3 +1301,5 @@ public final class Terminal { } } } + + diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/Terminal.java b/src/main/java/li/cil/oc2/common/vm/terminal/Terminal.java new file mode 100644 index 00000000..d084dfd0 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/Terminal.java @@ -0,0 +1,1128 @@ +package li.cil.oc2.common.vm.terminal; + +import com.google.gson.annotations.SerializedName; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue; +import li.cil.ceres.api.Serialized; +import li.cil.oc2.common.vm.terminal.escapes.apc.APCManager; +import li.cil.oc2.common.vm.terminal.escapes.csi.CSIManager; +import li.cil.oc2.common.vm.terminal.escapes.*; +import li.cil.oc2.common.vm.terminal.escapes.dcs.DCSManager; +import li.cil.oc2.common.vm.terminal.escapes.osc.OSCManager; +import li.cil.oc2.common.vm.terminal.fonts.FontHandling; +import li.cil.oc2.common.vm.terminal.fonts.Glyph; +import li.cil.oc2.common.vm.terminal.modes.ModeState; +import li.cil.oc2.common.vm.terminal.modes.PrivateModeState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.client.resources.sounds.SimpleSoundInstance; +import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.joml.Matrix4f; + +import javax.annotation.Nullable; +import java.nio.ByteBuffer; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; + +@Serialized +public class Terminal { + public boolean Use1006 = false; + + // Constants + public static final int WIDTH = 80, HEIGHT = 24; + public static final int CHAR_WIDTH = 8; + public static final int CHAR_HEIGHT = 16; + + public static final int STYLE_BOLD_MASK = 1; + public static final int STYLE_DIM_MASK = 1 << 1; + public static final int STYLE_UNDERLINE_MASK = 1 << 2; + public static final int STYLE_BLINK_MASK = 1 << 3; + public static final int STYLE_INVERT_MASK = 1 << 4; + public static final int STYLE_HIDDEN_MASK = 1 << 5; + + // Default Styles + public static final ColorData DEFAULT_COLORS = new ColorData(Color.WHITE, Color.BLACK, 0, ColorMode.SIXTEEN_COLOR); + public static final byte DEFAULT_STYLE = 0; + public static final ColorData DEFAULT_256_COLORS = new ColorData(Color.WHITE, Color.BLACK, 0, ColorMode.TWO_FIFTY_SIX_COLOR); + public static final ColorData DEFAULT_TRUE_COLOR_FOREGROUND = new ColorData(238, 238, 238, ColorMode.TRUE_COLOR); + public static final ColorData DEFAULT_TRUE_COLOR_BACKGROUND = new ColorData(0, 0, 0, ColorMode.TRUE_COLOR); + public static final int TAB_WIDTH = 4; + + // Current Color Data + public ColorMode currentForegroundColorMode = ColorMode.SIXTEEN_COLOR; + public ColorMode currentBackgroundColorMode = ColorMode.SIXTEEN_COLOR; + public ColorData sixteenColor; + // 256 Color + public ColorData twoFiftySixColor; + // True Color + public ColorData backgroundColor; + public ColorData foregroundColor; + // Style info packed into one byte for compact storage + public byte style; + + // Rendering Data + public final int SCROLL_BACK_COUNT = 20; + public final ByteArrayFIFOQueue input = new ByteArrayFIFOQueue(32); + public final int[] buffer = new int[WIDTH * HEIGHT * SCROLL_BACK_COUNT]; + public final ColorData[] colors = new ColorData[WIDTH * HEIGHT * SCROLL_BACK_COUNT]; + public final ColorData[] colorsBackground = new ColorData[WIDTH * HEIGHT * SCROLL_BACK_COUNT]; + public final byte[] styles = new byte[WIDTH * HEIGHT * SCROLL_BACK_COUNT]; + public final boolean[] tabs = new boolean[WIDTH]; + public State state = State.NORMAL; + public int scrollFirst = 0, scrollLast = HEIGHT - 1; + public int x, y; + public int savedX, savedY, altSavedX, altSavedY; + public int lastRowToDisplay = 24, lastRowToDisplayMax = 24; + + // Alt Buffer + public final int[] altBuffer = new int[WIDTH * HEIGHT]; + public final ColorData[] altColors = new ColorData[WIDTH * HEIGHT]; + public final ColorData[] altColorsBackground = new ColorData[WIDTH * HEIGHT]; + public final byte[] altStyles = new byte[WIDTH * HEIGHT]; + public final boolean[] altTabs = new boolean[WIDTH]; + + // Render Data + public final transient Set renderers = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>())); + public transient boolean displayOnly; // Set on client to not send responses to status requests. + public transient boolean hasPendingBell; + public boolean continuationByte; + public int unicode; + public int bytesRead; + public int bytesToRead; + public boolean useG0 = true; + public int drawingModeG0; + public int drawingModeG1; + public int cursorMode; + public ModeState currentModeState = new ModeState(); + public PrivateModeState currentPrivateModeState = new PrivateModeState(); + public PrivateModeState savePrivateModeState = new PrivateModeState(); + + // Related Enums + public enum ColorMode { + @SerializedName("0") + SIXTEEN_COLOR, + @SerializedName("1") + TWO_FIFTY_SIX_COLOR, + @SerializedName("2") + TRUE_COLOR + } + + public static final class CursorMode { + public static final int DEFAULT = 0; // BLOCK + public static final int BLINK_BLOCK = 1; // BLINKING BLOCK + public static final int STEADY_BLOCK = 2; // STEADY BLOCK + public static final int BLINK_UNDERLINE = 3; // BLINKING UNDERLINE + public static final int STEADY_UNDERLINE = 4; // STEADY UNDERLINE + public static final int BLINKING_BAR_LINE = 5; // BLINKING BAR LINE + public static final int STEADY_BAR_LINE = 6; // STEADY BAR LINE + } + + public static final class DrawingMode { + public static final int ASCII = 0; // BLOCK + public static final int SPECIAL_GRAPHICS = 1; // BLINKING BLOCK + } + + @SuppressWarnings("unused") + public static final class Color { + static final int BLACK = 0; + static final int RED = 1; + static final int GREEN = 2; + static final int YELLOW = 3; + static final int BLUE = 4; + static final int MAGENTA = 5; + static final int CYAN = 6; + static final int WHITE = 7; + } + + public enum State { // Must be public for serialization. + NORMAL, // Reading characters normally. + ESCAPE, // Last character was ESC, figure out what kind next. + SHIFT_IN_CHARACTER_SET, // Shift in character set. + SHIFT_OUT_CHARACTER_SET, // Shift out character set. + HASH, // Escape sequence with # intermediate. + DCS, + OSC, + APC, + CONTROL_SEQUENCE, // Know what sequence we have, now parsing it. + } + + // Nested classes + public static class ColorData { + public int R; + public int G; + public int B; + public ColorMode Mode; + + @SuppressWarnings("unused") + public ColorData() { + R = 0; + G = 0; + B = 0; + ColorMode Mode = ColorMode.SIXTEEN_COLOR; + } + + public ColorData(final int r, final int g, final int b, final ColorMode mode) { + R = r; + G = g; + B = b; + Mode = mode; + } + + public int ToInt() { + return (((R & 0b11111111) << 16) | ((G & 0b11111111) << 8) | (B & 0b11111111)); + } + + public ColorData Copy() { + return new ColorData(R, G, B, Mode); + } + } + + // Instances + private final CSIManager csiManager = new CSIManager(this); + private final OSCManager oscManager = new OSCManager(this); + private final DCSManager dcsManager = new DCSManager(this); + private final APCManager apcManager = new APCManager(this); + + // Nested interfaces + public interface RendererView { + void render(final PoseStack stack, final Matrix4f projectionMatrix); + } + + public interface RendererModel { + AtomicInteger getDirtyMask(); + + void close(); + } + + // Generic Getters + public int getWidth() { + return WIDTH * CHAR_WIDTH; + } + + public int getHeight() { + return HEIGHT * CHAR_HEIGHT; + } + + @OnlyIn(Dist.CLIENT) + public RendererView getRenderer() { + final Renderer renderer = new Renderer(this); + renderers.add(renderer); + return renderer; + } + + public void incrementLastLineToDisplay() { + incrementLastLineToDisplay(false); + } + + public void incrementLastLineToDisplay(boolean scroll) { + if (scrollFirst != 0 || scrollLast != HEIGHT - 1) return; + boolean originallyEqual = lastRowToDisplayMax == lastRowToDisplay; + if (!scroll) { + lastRowToDisplayMax = Math.min(lastRowToDisplayMax + 1, (HEIGHT * SCROLL_BACK_COUNT)); + } else if (lastRowToDisplay == lastRowToDisplayMax) { + return; + } + + if (originallyEqual) { + lastRowToDisplay = lastRowToDisplayMax; + } + else { + lastRowToDisplay = Math.min(lastRowToDisplay + 1, lastRowToDisplayMax); + } + + int dirtyLinesMask = 0; + for (int i = 0; i <= 23; i++) { + dirtyLinesMask |= 1 << i; + } + final int finalDirtyLinesMask = dirtyLinesMask; + renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } + + public void decrementLastLineToDisplay() { + if (scrollFirst != 0 || scrollLast != HEIGHT - 1) return; + lastRowToDisplay = Math.max(lastRowToDisplay - 1, 24); + int dirtyLinesMask = 0; + for (int i = 0; i <= 23; i++) { + dirtyLinesMask |= 1 << i; + } + final int finalDirtyLinesMask = dirtyLinesMask; + renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } + + // Logic + + public Terminal() { + RIS.execute(this); + } + + // Terminal Management + public void clear() { + if (currentPrivateModeState.isAltBufferEnabled()) { + Arrays.fill(altBuffer, ' '); + Arrays.fill(altColors, DEFAULT_COLORS.Copy()); + ColorData c; + switch (currentBackgroundColorMode) { + case SIXTEEN_COLOR -> c = sixteenColor; + case TWO_FIFTY_SIX_COLOR -> c = twoFiftySixColor; + case TRUE_COLOR -> c = backgroundColor; + default -> c = DEFAULT_COLORS.Copy(); + } + Arrays.fill(altColorsBackground, c.Copy()); + Arrays.fill(altStyles, DEFAULT_STYLE); + } else { + Arrays.fill(buffer, ' '); + Arrays.fill(colors, DEFAULT_COLORS.Copy()); + ColorData c; + switch (currentBackgroundColorMode) { + case SIXTEEN_COLOR -> c = sixteenColor; + case TWO_FIFTY_SIX_COLOR -> c = twoFiftySixColor; + case TRUE_COLOR -> c = backgroundColor; + default -> c = DEFAULT_COLORS.Copy(); + } + Arrays.fill(colorsBackground, c.Copy()); + Arrays.fill(styles, DEFAULT_STYLE); + } + setCursorPos(0, 0); + renderers.forEach(model -> model.getDirtyMask().set(-1)); + } + + public void clearAlt() { + Arrays.fill(altBuffer, ' '); + Arrays.fill(altColors, DEFAULT_COLORS.Copy()); + ColorData c; + switch (currentBackgroundColorMode) { + case SIXTEEN_COLOR -> c = sixteenColor; + case TWO_FIFTY_SIX_COLOR -> c = twoFiftySixColor; + case TRUE_COLOR -> c = backgroundColor; + default -> c = DEFAULT_COLORS.Copy(); + } + Arrays.fill(altColorsBackground, c.Copy()); + Arrays.fill(altStyles, DEFAULT_STYLE); + } + + public void clearLine(final int y) { + clearLine(y, 0, WIDTH); + } + + public void clearLine(final int y, final int fromIndex, final int toIndex) { + currentForegroundColorMode = ColorMode.SIXTEEN_COLOR; + if (currentPrivateModeState.isAltBufferEnabled()) { + Arrays.fill(altBuffer, y * WIDTH + fromIndex, y * WIDTH + toIndex, ' '); + Arrays.fill(altColors, y * WIDTH + fromIndex, y * WIDTH + toIndex, DEFAULT_COLORS.Copy()); + ColorData c; + switch (currentBackgroundColorMode) { + case SIXTEEN_COLOR -> c = sixteenColor; + case TWO_FIFTY_SIX_COLOR -> c = twoFiftySixColor; + case TRUE_COLOR -> c = backgroundColor; + default -> c = DEFAULT_COLORS.Copy(); + } + Arrays.fill(altColorsBackground, y * WIDTH + fromIndex, y * WIDTH + toIndex, c.Copy()); + Arrays.fill(altStyles, y * WIDTH + fromIndex, y * WIDTH + toIndex, DEFAULT_STYLE); + } else { + int correctedY = (y + (lastRowToDisplayMax - HEIGHT)); + Arrays.fill(buffer, correctedY * WIDTH + fromIndex, correctedY * WIDTH + toIndex, ' '); + Arrays.fill(colors, correctedY * WIDTH + fromIndex, correctedY * WIDTH + toIndex, DEFAULT_COLORS.Copy()); + ColorData c; + switch (currentBackgroundColorMode) { + case SIXTEEN_COLOR -> c = sixteenColor; + case TWO_FIFTY_SIX_COLOR -> c = twoFiftySixColor; + case TRUE_COLOR -> c = backgroundColor; + default -> c = DEFAULT_COLORS.Copy(); + } + Arrays.fill(colorsBackground, correctedY * WIDTH + fromIndex, correctedY * WIDTH + toIndex, c.Copy()); + Arrays.fill(styles, correctedY * WIDTH + fromIndex, correctedY * WIDTH + toIndex, DEFAULT_STYLE); + } + renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(1 << y, (prev, next) -> prev | next)); + } + + public void setCursorPos(final int x, final int y) { + this.x = Math.max(0, Math.min(WIDTH - 1, x)); + this.y = Math.max(0, Math.min(HEIGHT - 1, y)); + } + + public void setClampedCursorPos(final int x, final int y) { + setCursorPos(x, Math.max(scrollFirst, Math.min(scrollLast, y))); + } + + public void setRelativeCursorPos(final int x, final int y) { + if (currentPrivateModeState.DECOM) { + setCursorPos(x, Math.min(scrollFirst + y, scrollLast)); + } else { + setCursorPos(x, y); + } + } + + @OnlyIn(Dist.CLIENT) + public void setDisplayOnly(final boolean value) { + displayOnly = value; + } + + @OnlyIn(Dist.CLIENT) + public void releaseRenderer(final RendererView renderer) { + if (renderer instanceof final RendererModel rendererModel) { + rendererModel.close(); + renderers.remove(rendererModel); + } + } + + @OnlyIn(Dist.CLIENT) + public void clientTick() { + if (hasPendingBell) { + hasPendingBell = false; + final Minecraft client = Minecraft.getInstance(); + client.execute(() -> client.getSoundManager().play(SimpleSoundInstance.forUI(NoteBlockInstrument.PLING.getSoundEvent(), 1))); + } + } + + public synchronized int readInput() { + if (input.isEmpty()) { + return -1; + } else { + return input.dequeueByte() & 0xFF; + } + } + + @Nullable + public synchronized ByteBuffer getInput() { + if (input.isEmpty()) { + return null; + } else { + if (!currentPrivateModeState.isAltBufferEnabled()) lastRowToDisplay = lastRowToDisplayMax; + int dirtyLinesMask = 0; + for (int i = 0; i <= 23; i++) { + dirtyLinesMask |= 1 << i; + } + final int finalDirtyLinesMask = dirtyLinesMask; + renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + final ByteBuffer buffer = ByteBuffer.allocate(input.size()); + while (!input.isEmpty()) { + buffer.put(input.dequeueByte()); + } + buffer.flip(); + return buffer; + } + } + + public synchronized void putInput(final String value) { + putInput(ByteBuffer.wrap(value.getBytes())); + } + + public synchronized void putInput(final ByteBuffer values) { + while (values.hasRemaining()) { + input.enqueue(values.get()); + } + } + + public synchronized void putOutput(final ByteBuffer values) { + while (values.hasRemaining()) { + putOutput(values.get()); + } + } + + public void putOutput(final byte value) { + final char ch = (char) value; + if (!continuationByte && (ch & (1 << 7)) != 0) { + continuationByte = true; + bytesToRead = 0; + bytesRead = 0; + unicode = 0; + if ((ch & (1 << 6)) != 0) { + bytesToRead++; + } else { + continuationByte = false; + return; + } + + if ((ch & (1 << 5)) != 0) { + bytesToRead++; + } else { + unicode = (ch & 0b11111) << 6; // 2 Byte Char + return; + } + + if ((ch & (1 << 4)) != 0) { + bytesToRead++; + } else { + unicode = (ch & 0b1111) << 12; // 3 Byte Char + return; + } + + unicode = (ch & 0b111) << 18; // 4 Byte Char + + return; + } else if (continuationByte) { + if ((ch & (1 << 7)) == 0) { + continuationByte = false; + bytesToRead = 0; + bytesRead = 0; + return; + } + + bytesRead++; + + unicode |= (ch & 0b111111) << ((bytesToRead - bytesRead) * 6); + + if (bytesToRead == bytesRead) { + bytesToRead = 0; + bytesRead = 0; + } else { + return; + } + } + switch (state) { + case NORMAL -> { + switch (value) { + case '\007' -> hasPendingBell = true; + case '\033' -> state = State.ESCAPE; + case '\016' -> useG0 = false; // SO + case '\017' -> useG0 = true; // SI + + case (byte) '\r' /* 015 */ -> setCursorPos(0, y); + case (byte) '\n' /* 012 */, '\013', '\014' -> { + if (currentModeState.LNM) { + NEL.execute(this); + } else { + IND.execute(this); + } + } + case (byte) '\t' /* 011 */ -> { + if (x < WIDTH) { + do { + x++; + } while (x < WIDTH && (currentPrivateModeState.isAltBufferEnabled() ? !altTabs[x] : !tabs[x])); + } + } + case (byte) '\b' /* 010 */ -> setCursorPos(Math.min(x, WIDTH - 1) - 1, y); + + default -> putChar((continuationByte) ? unicode : ch); + } + } + case ESCAPE -> { + if (ch == '[') { // Control Sequence Indicator + csiManager.reset(); + state = State.CONTROL_SEQUENCE; + } else if (ch == '(') { // SCS – Select Character Set + state = State.SHIFT_IN_CHARACTER_SET; + } else if (ch == ')') { // SCS – Select Character Set + state = State.SHIFT_OUT_CHARACTER_SET; + } else if (ch == '#') { // # Intermediate + state = State.HASH; + } else if (ch == 'P') { + dcsManager.reset(); + state = State.DCS; + } else if (ch == ']') { + oscManager.reset(); + state = State.OSC; + } else if (ch == '_') { + apcManager.reset(); + state = State.APC; + } else { + state = State.NORMAL; + switch (ch) { + case 'D' -> IND.execute(this); // IND – Index + case 'E' -> NEL.execute(this); // NEL – Next Line + case 'M' -> RI.execute(this); // RI – Reverse Index + case '7' -> DECSC.execute(this); // DECSC – Save Cursor (DEC public) + case '8' -> DECRC.execute(this); // DECRC – Restore Cursor (DEC public) + case 'H' -> HTS.execute(this); // HTS – Horizontal Tabulation Set + case 'c' -> RIS.execute(this); // RIS – Reset To Initial State + case '=' -> { + } // DECKPAM – Keypad Application Mode (DEC public) + case '>' -> { + } // DECKPNM – Keypad Numeric Mode (DEC public) + default -> System.out.println("Invalid escape: " + ch); + } + } + } + case CONTROL_SEQUENCE -> csiManager.handle(ch); + case SHIFT_IN_CHARACTER_SET, SHIFT_OUT_CHARACTER_SET -> { + state = State.NORMAL; + switch (ch) { + case 'A' -> { + } // United Kingdom Set + case 'B' -> drawingModeG0 = DrawingMode.ASCII; // ASCII Set + case '0' -> drawingModeG0 = DrawingMode.SPECIAL_GRAPHICS; // Special Graphics + case '1' -> { + } // Alternate Character ROM Standard Character Set + case '2' -> { + } // Alternate Character ROM Special Graphics + } + } + case HASH -> { + state = State.NORMAL; + switch (ch) { + case '3' -> { + } // Change this line to double-height top half (DECDHL) + case '4' -> { + } // Change this line to double-height bottom half (DECDHL) + case '5' -> { + } // Change this line to single-width single-height (DECSWL) + case '6' -> { + } // Change this line to double-width single-height (DECDWL) + case '8' -> { // Fill Screen with Es (DECALN) + if (currentPrivateModeState.isAltBufferEnabled()) { + Arrays.fill(altBuffer, 'E'); + } else { + Arrays.fill(buffer, (lastRowToDisplayMax - HEIGHT) * WIDTH, ((WIDTH - 1) + (HEIGHT - 1) * WIDTH) + 1, 'E'); + } + renderers.forEach(model -> model.getDirtyMask().set(-1)); + } + } + } + case DCS -> dcsManager.handle(ch); // Used for mapping Function keys and possibly other things + case OSC -> oscManager.handle(ch); + case APC -> apcManager.handle(ch); + } + } + + public synchronized void putInput(final char value) { + putInput((byte) value); + } + + public synchronized void putInput(final byte value) { + input.enqueue(value); + } + + public void putResponse(final String value) { + for (int i = 0; i < value.length(); i++) { + putResponse((byte) value.charAt(i)); + } + } + + public void putResponse(final byte value) { + if (!displayOnly) { + putInput(value); + } + } + + public void shiftUp(int count) { + if (currentPrivateModeState.isAltBufferEnabled()) { + shiftLines(scrollFirst + 1, scrollLast, -count); + } else { + if (lastRowToDisplay == HEIGHT * SCROLL_BACK_COUNT || scrollLast != Terminal.HEIGHT - 1 || scrollFirst != 0) { + shiftLines(scrollFirst != 0 ? (scrollFirst + (lastRowToDisplayMax - HEIGHT)) + 1 : 1, scrollLast != Terminal.HEIGHT - 1 ? scrollLast + (lastRowToDisplayMax - HEIGHT) : (HEIGHT * SCROLL_BACK_COUNT) - 1, -count); + } + } + } + + public void shiftDown(int count) { + if (currentPrivateModeState.isAltBufferEnabled()) { + shiftLines(scrollFirst, scrollLast - 1, count); + } else { + shiftLines(scrollFirst != 0 ? (scrollFirst + (lastRowToDisplayMax - HEIGHT)) : 0, scrollLast != Terminal.HEIGHT - 1 ? scrollLast + (lastRowToDisplayMax - HEIGHT) - 1 : ((HEIGHT * SCROLL_BACK_COUNT) - 1) - 1, count); + } + } + + public void shiftUpOne() { + shiftUp(1); + } + + public void shiftDownOne() { + shiftDown(1); + } + + public void shiftLines(final int firstLine, final int lastLine, final int count) { + if (count == 0) + return; + + final int srcIndex = firstLine * WIDTH; + final int charCount = (lastLine + 1) * WIDTH - srcIndex; + final int dstIndex = srcIndex + count * WIDTH; + if (currentPrivateModeState.isAltBufferEnabled()) { + System.arraycopy(altBuffer, srcIndex, altBuffer, dstIndex, charCount); + System.arraycopy(altColors, srcIndex, altColors, dstIndex, charCount); + System.arraycopy(altColorsBackground, srcIndex, altColorsBackground, dstIndex, charCount); + System.arraycopy(altStyles, srcIndex, altStyles, dstIndex, charCount); + + final int clearIndex = count > 0 ? srcIndex : (dstIndex + charCount); + final int clearCount = Math.abs(count * WIDTH); + Arrays.fill(altBuffer, clearIndex, clearIndex + clearCount, ' '); + // TODO Copy color and style from last line. + // TODO Copy color and style from last line. + Arrays.fill(altColors, clearIndex, clearIndex + clearCount, DEFAULT_COLORS.Copy()); + ColorData c; + switch (currentBackgroundColorMode) { + case SIXTEEN_COLOR -> c = sixteenColor; + case TWO_FIFTY_SIX_COLOR -> c = twoFiftySixColor; + case TRUE_COLOR -> c = backgroundColor; + default -> c = DEFAULT_COLORS.Copy(); + } + Arrays.fill(altColorsBackground, clearIndex, clearIndex + clearCount, c.Copy()); + Arrays.fill(altStyles, clearIndex, clearIndex + clearCount, DEFAULT_STYLE); + + int dirtyLinesMask = 0; + final int dirtyStart = Math.min(firstLine, firstLine + count); + final int dirtyEnd = Math.max(lastLine, lastLine + count); + for (int i = dirtyStart; i <= dirtyEnd; i++) { + dirtyLinesMask |= 1 << i; + } + final int finalDirtyLinesMask = dirtyLinesMask; + renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } else { + System.arraycopy(buffer, srcIndex, buffer, dstIndex, charCount); + System.arraycopy(colors, srcIndex, colors, dstIndex, charCount); + System.arraycopy(colorsBackground, srcIndex, colorsBackground, dstIndex, charCount); + System.arraycopy(styles, srcIndex, styles, dstIndex, charCount); + + final int clearIndex = count > 0 ? srcIndex : (dstIndex + charCount); + final int clearCount = Math.abs(count * WIDTH); + Arrays.fill(buffer, clearIndex, clearIndex + clearCount, ' '); + // TODO Copy color and style from last line. + // TODO Copy color and style from last line. + Arrays.fill(colors, clearIndex, clearIndex + clearCount, DEFAULT_COLORS.Copy()); + ColorData c; + switch (currentBackgroundColorMode) { + case SIXTEEN_COLOR -> c = sixteenColor; + case TWO_FIFTY_SIX_COLOR -> c = twoFiftySixColor; + case TRUE_COLOR -> c = backgroundColor; + default -> c = DEFAULT_COLORS.Copy(); + } + Arrays.fill(colorsBackground, clearIndex, clearIndex + clearCount, c.Copy()); + Arrays.fill(styles, clearIndex, clearIndex + clearCount, DEFAULT_STYLE); + + int dirtyLinesMask = 0; + final int dirtyStart = Math.min(firstLine, firstLine + count); + final int dirtyEnd = Math.max(lastLine, lastLine + count); + for (int i = dirtyStart; i <= dirtyEnd; i++) { + int globalI = lastRowToDisplayMax - (HEIGHT - i); + int localI = HEIGHT + (globalI - lastRowToDisplay); + dirtyLinesMask |= 1 << localI; + } + final int finalDirtyLinesMask = dirtyLinesMask; + renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } + } + + private void putChar(int ch) { + if (continuationByte) continuationByte = false; + if (Character.isISOControl(ch)) + return; + + int curMode = (useG0) ? drawingModeG0 : drawingModeG1; + + if (curMode == DrawingMode.SPECIAL_GRAPHICS) { + switch (ch) { + case 'l' -> ch = "┌".codePointAt(0); + case 'k' -> ch = "┐".codePointAt(0); + case 'm' -> ch = "└".codePointAt(0); + case 'j' -> ch = "┘".codePointAt(0); + case 'q' -> ch = "─".codePointAt(0); + case 'x' -> ch = "│".codePointAt(0); + case 'n' -> ch = "┼".codePointAt(0); + case '~' -> ch = "B".codePointAt(0); + case 'u' -> ch = "┤".codePointAt(0); + case 't' -> ch = "├".codePointAt(0); + case 'v' -> ch = "┴".codePointAt(0); + case 'w' -> ch = "┬".codePointAt(0); + } + } + + if (x >= WIDTH) { + if (currentPrivateModeState.DECAWM) { + NEL.execute(this); + } else { + setCursorPos(WIDTH - 1, y); + } + } + + setChar(x, y, ch); + x++; + } + + private void setChar(final int x, final int y, final int ch) { + if (currentPrivateModeState.isAltBufferEnabled()) { + final int index = x + y * WIDTH; + + altBuffer[index] = ch; + + switch (currentForegroundColorMode) { + case SIXTEEN_COLOR -> altColors[index] = sixteenColor.Copy(); + case TWO_FIFTY_SIX_COLOR -> altColors[index] = twoFiftySixColor.Copy(); + case TRUE_COLOR -> altColors[index] = foregroundColor.Copy(); + } + + switch (currentBackgroundColorMode) { + case SIXTEEN_COLOR -> altColorsBackground[index] = sixteenColor.Copy(); + case TWO_FIFTY_SIX_COLOR -> altColorsBackground[index] = twoFiftySixColor.Copy(); + case TRUE_COLOR -> altColorsBackground[index] = backgroundColor.Copy(); + } + + altStyles[index] = style; + renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(1 << (y), (prev, next) -> prev | next)); + } else { + int correctedY = (y + (lastRowToDisplayMax - HEIGHT)); + final int index = x + correctedY * WIDTH; + + buffer[index] = ch; + + switch (currentForegroundColorMode) { + case SIXTEEN_COLOR -> colors[index] = sixteenColor.Copy(); + case TWO_FIFTY_SIX_COLOR -> colors[index] = twoFiftySixColor.Copy(); + case TRUE_COLOR -> colors[index] = foregroundColor.Copy(); + } + + switch (currentBackgroundColorMode) { + case SIXTEEN_COLOR -> colorsBackground[index] = sixteenColor.Copy(); + case TWO_FIFTY_SIX_COLOR -> colorsBackground[index] = twoFiftySixColor.Copy(); + case TRUE_COLOR -> colorsBackground[index] = backgroundColor.Copy(); + } + + styles[index] = style; + int globalY = lastRowToDisplayMax - (HEIGHT - y); + int localY = HEIGHT + (globalY - lastRowToDisplay); + renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(1 << (localY), (prev, next) -> prev | next)); + } + } + + // Renderer + @OnlyIn(Dist.CLIENT) + public static final class Renderer implements RendererModel, RendererView { + public static final int[] COLORS = { + 0x555555, // Black + 0xEE3322, // Red + 0x33DD44, // Green + 0xFFCC11, // Yellow + 0x1188EE, // Blue + 0xDD33CC, // Magenta + 0x22CCDD, // Cyan + 0xEEEEEE, // White + }; + + public static final int[] DIM_COLORS = { + 0x010101, // Black + 0x772211, // Red + 0x116622, // Green + 0x886611, // Yellow + 0x115588, // Blue + 0x771177, // Magenta + 0x116677, // Cyan + 0x777777, // White + }; + + public static final int[] COLORS_256 = { + 0x010101, 0x772211, 0x116622, 0x886611, 0x115588, 0x771177, 0x116677, 0x777777, + 0x555555, 0xEE3322, 0x33DD44, 0xFFCC11, 0x1188EE, 0xDD33CC, 0x22CCDD, 0xEEEEEE, + 0x000000, 0x00005f, 0x000087, 0x0000af, 0x0000d7, 0x0000ff, 0x005f00, 0x005f5f, + 0x005f87, 0x005faf, 0x005fd7, 0x005fff, 0x008700, 0x00875f, 0x008787, 0x0087af, + 0x0087d7, 0x0087ff, 0x00af00, 0x00af5f, 0x00af87, 0x00afaf, 0x00afd7, 0x00afff, + 0x00d700, 0x00d75f, 0x00d787, 0x00d7af, 0x00d7d7, 0x00d7ff, 0x00ff00, 0x00ff5f, + 0x00ff87, 0x00ffaf, 0x00ffd7, 0x00ffff, 0x5f0000, 0x5f005f, 0x5f0087, 0x5f00af, + 0x5f00d7, 0x5f00ff, 0x5f5f00, 0x5f5f5f, 0x5f5f87, 0x5f5faf, 0x5f5fd7, 0x5f5fff, + 0x5f8700, 0x5f875f, 0x5f8787, 0x5f87af, 0x5f87d7, 0x5f87ff, 0x5faf00, 0x5faf5f, + 0x5faf87, 0x5fafaf, 0x5fafd7, 0x5fafff, 0x5fd700, 0x5fd75f, 0x5fd787, 0x5fd7af, + 0x5fd7d7, 0x5fd7ff, 0x5fff00, 0x5fff5f, 0x5fff87, 0x5fffaf, 0x5fffd7, 0x5fffff, + 0x870000, 0x87005f, 0x870087, 0x8700af, 0x8700d7, 0x8700ff, 0x875f00, 0x875f5f, + 0x875f87, 0x875faf, 0x875fd7, 0x875fff, 0x878700, 0x87875f, 0x878787, 0x8787af, + 0x8787d7, 0x8787ff, 0x87af00, 0x87af5f, 0x87af87, 0x87afaf, 0x87afd7, 0x87afff, + 0x87d700, 0x87d75f, 0x87d787, 0x87d7af, 0x87d7d7, 0x87d7ff, 0x87ff00, 0x87ff5f, + 0x87ff87, 0x87ffaf, 0x87ffd7, 0x87ffff, 0xaf0000, 0xaf005f, 0xaf0087, 0xaf00af, + 0xaf00d7, 0xaf00ff, 0xaf5f00, 0xaf5f5f, 0xaf5f87, 0xaf5faf, 0xaf5fd7, 0xaf5fff, + 0xaf8700, 0xaf875f, 0xaf8787, 0xaf87af, 0xaf87d7, 0xaf87ff, 0xafaf00, 0xafaf5f, + 0xafaf87, 0xafafaf, 0xafafd7, 0xafafff, 0xafd700, 0xafd75f, 0xafd787, 0xafd7af, + 0xafd7d7, 0xafd7ff, 0xafff00, 0xafff5f, 0xafff87, 0xafffaf, 0xafffd7, 0xafffff, + 0xd70000, 0xd7005f, 0xd70087, 0xd700af, 0xd700d7, 0xd700ff, 0xd75f00, 0xd75f5f, + 0xd75f87, 0xd75faf, 0xd75fd7, 0xd75fff, 0xd78700, 0xd7875f, 0xd78787, 0xd787af, + 0xd787d7, 0xd787ff, 0xdfaf00, 0xdfaf5f, 0xdfaf87, 0xdfafaf, 0xdfafdf, 0xdfafff, + 0xdfdf00, 0xdfdf5f, 0xdfdf87, 0xdfdfaf, 0xdfdfdf, 0xdfdfff, 0xdfff00, 0xdfff5f, + 0xdfff87, 0xdfffaf, 0xdfffdf, 0xdfffff, 0xff0000, 0xff005f, 0xff0087, 0xff00af, + 0xff00df, 0xff00ff, 0xff5f00, 0xff5f5f, 0xff5f87, 0xff5faf, 0xff5fdf, 0xff5fff, + 0xff8700, 0xff875f, 0xff8787, 0xff87af, 0xff87df, 0xff87ff, 0xffaf00, 0xffaf5f, + 0xffaf87, 0xffafaf, 0xffafdf, 0xffafff, 0xffdf00, 0xffdf5f, 0xffdf87, 0xffdfaf, + 0xffdfdf, 0xffdfff, 0xffff00, 0xffff5f, 0xffff87, 0xffffaf, 0xffffdf, 0xffffff, + 0x080808, 0x121212, 0x1c1c1c, 0x262626, 0x303030, 0x3a3a3a, 0x444444, 0x4e4e4e, + 0x585858, 0x626262, 0x6c6c6c, 0x767676, 0x808080, 0x8a8a8a, 0x949494, 0x9e9e9e, + 0xa8a8a8, 0xb2b2b2, 0xbcbcbc, 0xc6c6c6, 0xd0d0d0, 0xdadada, 0xe4e4e4, 0xeeeeee + }; + + /// //////////////////////////////////////////////////////////// + + public final Terminal terminal; + public final VertexBuffer[] lines = new VertexBuffer[HEIGHT]; + + public final AtomicInteger dirty = new AtomicInteger(-1); + + /// //////////////////////////////////////////////////////////// + + public Renderer(final Terminal terminal) { + this.terminal = terminal; + } + + /// //////////////////////////////////////////////////////////// + + @Override + public void render(final PoseStack stack, final Matrix4f projectionMatrix) { + if (terminal.currentPrivateModeState.APPLICATION_SYNC) return; + validateLineCache(); + renderBuffer(stack, projectionMatrix); + + boolean steady = switch (terminal.cursorMode) { + case CursorMode.STEADY_BLOCK, CursorMode.STEADY_UNDERLINE, CursorMode.STEADY_BAR_LINE -> true; + default -> false; + }; + + if (steady || (System.currentTimeMillis() + terminal.hashCode()) % 1000 > 500) { + renderCursor(stack); + } + } + + @Override + public AtomicInteger getDirtyMask() { + return dirty; + } + + @Override + public void close() { + for (int i = 0; i < lines.length; i++) { + final VertexBuffer line = lines[i]; + if (line != null) { + line.close(); + lines[i] = null; + } + } + } + + /// //////////////////////////////////////////////////////////// + + public int findLineIndex(VertexBuffer[] vba, VertexBuffer vb) { + int i = 0; + while (i < vba.length) { + if (vba[i] == vb) { + return i; + } + i++; + } + return -1; + } + + public void renderBuffer(final PoseStack stack, final Matrix4f projectionMatrix) { + final ShaderInstance shader = GameRenderer.getPositionColorTexShader(); + if (shader == null) { + return; + } + + RenderSystem.depthMask(false); + RenderSystem.setShaderTexture(0, FontHandling.getAtlas()); + + for (final VertexBuffer line : lines) { + if (!line.isInvalid()) { + try { + line.bind(); + line.drawWithShader(stack.last().pose(), projectionMatrix, shader); + VertexBuffer.unbind(); + } catch (Exception e) { + System.out.println("ERROR: " + e.getMessage()); + System.out.println(findLineIndex(lines, line)); + } + } + } + + RenderSystem.depthMask(true); + } + + @SuppressWarnings("resource") + public void validateLineCache() { + if (dirty.get() == 0) { + return; + } + + final int mask = dirty.getAndSet(0); + for (int row = 0; row < lines.length; row++) { + if ((mask & (1 << row)) == 0) { + continue; + } + BufferBuilder builder = Tesselator.getInstance().getBuilder(); + + final Matrix4f matrix = new Matrix4f().translate(0, row * CHAR_HEIGHT, 0); + + builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); + + renderBackground(matrix, builder, row); + renderForeground(matrix, builder, row); + + BufferBuilder.RenderedBuffer rb = builder.end(); + + if (lines[row] == null) { + lines[row] = new VertexBuffer(VertexBuffer.Usage.DYNAMIC); + } else if (lines[row] != null) { + lines[row].close(); + lines[row] = new VertexBuffer(VertexBuffer.Usage.DYNAMIC); + } + + if (!lines[row].isInvalid()) { + lines[row].bind(); + lines[row].upload(rb); + VertexBuffer.unbind(); + } + } + } + + public void renderBackground(final Matrix4f matrix, final BufferBuilder buffer, final int row) { + // State tracking for drawing background quads spanning multiple characters. + float backgroundStartX = -1; + int backgroundColor = 0; + + float tx = 0f; + boolean useAltBuffer = terminal.currentPrivateModeState.isAltBufferEnabled(); + for (int col = 0, index = useAltBuffer ? row * WIDTH : (row + (terminal.lastRowToDisplay - HEIGHT)) * WIDTH; col < WIDTH; col++, index++) { + final byte style = useAltBuffer ? terminal.altStyles[index] : terminal.styles[index]; + final boolean invertBackground = (style & STYLE_INVERT_MASK) != 0; + final ColorData color = !invertBackground ? useAltBuffer ? terminal.altColorsBackground[index] : terminal.colorsBackground[index] : useAltBuffer ? terminal.altColors[index] : terminal.colors[index]; + + if ((style & STYLE_HIDDEN_MASK) != 0) continue; + + final int[] palette = (style & STYLE_DIM_MASK) != 0 ? DIM_COLORS : COLORS; + int background = switch (color.Mode) { + case SIXTEEN_COLOR -> palette[!invertBackground ? color.G : color.R]; + case TWO_FIFTY_SIX_COLOR -> COLORS_256[!invertBackground ? color.G : color.R]; + case TRUE_COLOR -> color.ToInt(); + }; + + final boolean hadBackground = backgroundStartX >= 0; + final boolean hasBackground = background != palette[0]; + if (!hadBackground && hasBackground) { + backgroundStartX = tx; + backgroundColor = background; + } else if (hadBackground && (!hasBackground || backgroundColor != background)) { + renderBackground(matrix, buffer, backgroundStartX, tx, backgroundColor); + + if (hasBackground) { + backgroundStartX = tx; + backgroundColor = background; + } else { + backgroundStartX = -1; + } + } + + tx += CHAR_WIDTH; + } + + if (backgroundStartX >= 0) { + renderBackground(matrix, buffer, backgroundStartX, tx, backgroundColor); + } + } + + public void renderBackground(final Matrix4f matrix, final BufferBuilder buffer, final float x0, final float x1, final int color) { + final float r = ((color >> 16) & 0xFF) / 255f; + final float g = ((color >> 8) & 0xFF) / 255f; + final float b = (color & 0xFF) / 255f; + + buffer.vertex(matrix, x0, CHAR_HEIGHT, 0).color(r, g, b, 1).uv(0, 0).endVertex(); + buffer.vertex(matrix, x1, CHAR_HEIGHT, 0).color(r, g, b, 1).uv(0, 0).endVertex(); + buffer.vertex(matrix, x1, 0, 0).color(r, g, b, 1).uv(0, 0).endVertex(); + buffer.vertex(matrix, x0, 0, 0).color(r, g, b, 1).uv(0, 0).endVertex(); + } + + public void renderForeground(final Matrix4f matrix, final BufferBuilder buffer, final int row) { + float tx = 0f; + boolean useAltBuffer = terminal.currentPrivateModeState.isAltBufferEnabled(); + for (int col = 0, index = useAltBuffer ? row * WIDTH : (row + (terminal.lastRowToDisplay - HEIGHT)) * WIDTH; col < WIDTH; col++, index++) { + final byte style = useAltBuffer ? terminal.altStyles[index] : terminal.styles[index]; + final boolean invertBackground = (style & STYLE_INVERT_MASK) != 0; + final ColorData color = !invertBackground ? useAltBuffer ? terminal.altColors[index] : terminal.colors[index] : useAltBuffer ? terminal.altColorsBackground[index] : terminal.colorsBackground[index]; + + if ((style & STYLE_HIDDEN_MASK) != 0) continue; + + final int[] palette = (style & STYLE_DIM_MASK) != 0 ? DIM_COLORS : COLORS; + int foreground = switch (color.Mode) { + case SIXTEEN_COLOR -> palette[!invertBackground ? color.R : color.G]; + case TWO_FIFTY_SIX_COLOR -> COLORS_256[!invertBackground ? color.R : color.G]; + case TRUE_COLOR -> color.ToInt(); + }; + + final int character = (useAltBuffer) ? terminal.altBuffer[index] : terminal.buffer[index]; + + renderForeground(matrix, buffer, tx, character, foreground, style); + + tx += CHAR_WIDTH; + } + } + + public void renderForeground(final Matrix4f matrix, final BufferBuilder buffer, final float offset, final int character, final int color, final byte style) { + final float r = ((color >> 16) & 0xFF) / 255f; + final float g = ((color >> 8) & 0xFF) / 255f; + final float b = (color & 0xFF) / 255f; + + if (isPrintableCharacter(character)) { + Glyph glyph = FontHandling.getGlyph(character); + + buffer.vertex(matrix, offset, CHAR_HEIGHT, 0).color(r, g, b, 1).uv(glyph.uStart, glyph.vEnd).endVertex(); + buffer.vertex(matrix, offset + CHAR_WIDTH, CHAR_HEIGHT, 0).color(r, g, b, 1).uv(glyph.uEnd, glyph.vEnd).endVertex(); + buffer.vertex(matrix, offset + CHAR_WIDTH, 0, 0).color(r, g, b, 1).uv(glyph.uEnd, glyph.vStart).endVertex(); + buffer.vertex(matrix, offset, 0, 0).color(r, g, b, 1).uv(glyph.uStart, glyph.vStart).endVertex(); + } + + if ((style & STYLE_UNDERLINE_MASK) != 0) { + buffer.vertex(matrix, offset, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).uv(0, 0).endVertex(); + buffer.vertex(matrix, offset + CHAR_WIDTH, CHAR_HEIGHT - 3, 0).color(r, g, b, 1).uv(0, 0).endVertex(); + buffer.vertex(matrix, offset + CHAR_WIDTH, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).uv(0, 0).endVertex(); + buffer.vertex(matrix, offset, CHAR_HEIGHT - 2, 0).color(r, g, b, 1).uv(0, 0).endVertex(); + } + } + + public void renderCursor(final PoseStack stack) { + BufferUploader.reset(); + if (!terminal.currentPrivateModeState.DECTCEM) return; + int globalY = terminal.lastRowToDisplayMax - (HEIGHT - terminal.y); + int localY = HEIGHT + (globalY - terminal.lastRowToDisplay); + + boolean useAltBuffer = terminal.currentPrivateModeState.isAltBufferEnabled(); + + if (terminal.x < 0 || terminal.x >= WIDTH || ((!useAltBuffer && localY < 0) || terminal.y < 0) || ((!useAltBuffer && localY >= HEIGHT) || terminal.y >= HEIGHT) || (!useAltBuffer && globalY > terminal.lastRowToDisplay)) { + return; + } + + RenderSystem.depthMask(false); + RenderSystem.setShader(GameRenderer::getPositionColorShader); + + stack.pushPose(); + stack.translate(terminal.x * CHAR_WIDTH, (useAltBuffer ? terminal.y : localY) * CHAR_HEIGHT, 0); + + final Matrix4f matrix = stack.last().pose(); + final BufferBuilder buffer = Tesselator.getInstance().getBuilder(); + buffer.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR); + + final int foreground = COLORS[Color.WHITE]; + final float r = ((foreground >> 16) & 0xFF) / 255f; + final float g = ((foreground >> 8) & 0xFF) / 255f; + final float b = ((foreground) & 0xFF) / 255f; + + switch (terminal.cursorMode) { + case CursorMode.DEFAULT, CursorMode.BLINK_BLOCK, CursorMode.STEADY_BLOCK: // BLOCK + buffer.vertex(matrix, 0, CHAR_HEIGHT, 0).color(r, g, b, 1).endVertex(); + buffer.vertex(matrix, CHAR_WIDTH, CHAR_HEIGHT, 0).color(r, g, b, 1).endVertex(); + buffer.vertex(matrix, CHAR_WIDTH, 0, 0).color(r, g, b, 1).endVertex(); + buffer.vertex(matrix, 0, 0, 0).color(r, g, b, 1).endVertex(); + break; + case CursorMode.BLINK_UNDERLINE, CursorMode.STEADY_UNDERLINE: // UNDERLINE + buffer.vertex(matrix, 0, 1, 0).color(r, g, b, 1).endVertex(); + buffer.vertex(matrix, CHAR_WIDTH, 1, 0).color(r, g, b, 1).endVertex(); + buffer.vertex(matrix, CHAR_WIDTH, 0, 0).color(r, g, b, 1).endVertex(); + buffer.vertex(matrix, 0, 0, 0).color(r, g, b, 1).endVertex(); + break; + case CursorMode.BLINKING_BAR_LINE, CursorMode.STEADY_BAR_LINE: // VERTICAL BAR LINE + buffer.vertex(matrix, 0, CHAR_HEIGHT, 0).color(r, g, b, 1).endVertex(); + buffer.vertex(matrix, 1, CHAR_HEIGHT, 0).color(r, g, b, 1).endVertex(); + buffer.vertex(matrix, 1, 0, 0).color(r, g, b, 1).endVertex(); + buffer.vertex(matrix, 0, 0, 0).color(r, g, b, 1).endVertex(); + break; + } + + BufferBuilder.RenderedBuffer rb = buffer.end(); + BufferUploader.drawWithShader(rb); + + stack.popPose(); + + RenderSystem.depthMask(true); + } + + public static boolean isPrintableCharacter(final int ch) { + return ch == 0 || + (ch > ' ' && ch <= '~') || + ch >= 177; + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/DECRC.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/DECRC.java new file mode 100644 index 00000000..14abab51 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/DECRC.java @@ -0,0 +1,15 @@ +package li.cil.oc2.common.vm.terminal.escapes; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class DECRC { + public static void execute(Terminal terminal) { + if (terminal.currentPrivateModeState.isAltBufferEnabled()) { + terminal.x = terminal.altSavedX; + terminal.y = terminal.altSavedY; + } else { + terminal.x = terminal.savedX; + terminal.y = terminal.savedY; + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/DECSC.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/DECSC.java new file mode 100644 index 00000000..6c9bac3d --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/DECSC.java @@ -0,0 +1,15 @@ +package li.cil.oc2.common.vm.terminal.escapes; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class DECSC { + public static void execute(Terminal terminal) { + if (terminal.currentPrivateModeState.isAltBufferEnabled()) { + terminal.altSavedX = terminal.x; + terminal.altSavedY = terminal.y; + } else { + terminal.savedX = terminal.x; + terminal.savedY = terminal.y; + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/EscapeUtilities.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/EscapeUtilities.java new file mode 100644 index 00000000..5fdbe1cb --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/EscapeUtilities.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes; + +public class EscapeUtilities { + public static int parseArgument(final char ch, int currentValue) { + final int digit = ch - '0'; + if (currentValue < (Integer.MAX_VALUE - digit) / 10) { + currentValue = currentValue * 10 + digit; + } else { + currentValue = Integer.MAX_VALUE; + } + return currentValue; + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/HTS.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/HTS.java new file mode 100644 index 00000000..bf07b506 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/HTS.java @@ -0,0 +1,14 @@ +package li.cil.oc2.common.vm.terminal.escapes; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class HTS { + public static void execute(Terminal terminal) { + if (terminal.x >= 0 && terminal.x < Terminal.WIDTH) { + if(terminal.currentPrivateModeState.isAltBufferEnabled()) + terminal.altTabs[terminal.x] = true; + else + terminal.tabs[terminal.x] = true; + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/IND.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/IND.java new file mode 100644 index 00000000..ed549fe6 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/IND.java @@ -0,0 +1,14 @@ +package li.cil.oc2.common.vm.terminal.escapes; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class IND { + public static void execute(Terminal terminal) { + if (terminal.y >= terminal.scrollLast) { + terminal.shiftUpOne(); + if (!terminal.currentPrivateModeState.isAltBufferEnabled()) terminal.incrementLastLineToDisplay(); + } else { + terminal.setCursorPos(terminal.x, terminal.y + 1); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/NEL.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/NEL.java new file mode 100644 index 00000000..eb769a24 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/NEL.java @@ -0,0 +1,15 @@ +package li.cil.oc2.common.vm.terminal.escapes; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class NEL { + public static void execute(Terminal terminal) { + if (terminal.y >= terminal.scrollLast) { + terminal.shiftUpOne(); + if (!terminal.currentPrivateModeState.isAltBufferEnabled()) terminal.incrementLastLineToDisplay(); + terminal.setCursorPos(0, terminal.y); + } else { + terminal.setCursorPos(0, terminal.y + 1); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/RI.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/RI.java new file mode 100644 index 00000000..20dc1b80 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/RI.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class RI { + public static void execute(Terminal terminal) { + if (terminal.y <= terminal.scrollFirst) { + terminal.shiftDownOne(); + } else { + terminal.setCursorPos(0, terminal.y - 1); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/RIS.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/RIS.java new file mode 100644 index 00000000..e1ff942c --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/RIS.java @@ -0,0 +1,37 @@ +package li.cil.oc2.common.vm.terminal.escapes; + +import li.cil.oc2.common.vm.terminal.modes.ModeState; +import li.cil.oc2.common.vm.terminal.modes.PrivateModeState; +import li.cil.oc2.common.vm.terminal.Terminal; + +import java.util.Arrays; + +public class RIS { + public static void execute(Terminal terminal) { + terminal.currentForegroundColorMode = Terminal.ColorMode.SIXTEEN_COLOR; + terminal.currentBackgroundColorMode = Terminal.ColorMode.SIXTEEN_COLOR; + terminal.Use1006 = false; + terminal.sixteenColor = Terminal.DEFAULT_COLORS.Copy(); + terminal.backgroundColor = Terminal.DEFAULT_TRUE_COLOR_BACKGROUND.Copy(); + terminal.foregroundColor = Terminal.DEFAULT_TRUE_COLOR_FOREGROUND.Copy(); + terminal.twoFiftySixColor = Terminal.DEFAULT_256_COLORS.Copy(); + terminal.style = Terminal.DEFAULT_STYLE; + terminal.currentModeState = new ModeState(); + terminal.currentPrivateModeState = new PrivateModeState(); + terminal.lastRowToDisplay = 24; + terminal.lastRowToDisplayMax = 24; + terminal.drawingModeG0 = Terminal.DrawingMode.ASCII; + terminal.drawingModeG1 = Terminal.DrawingMode.ASCII; + terminal.useG0 = true; + terminal.clear(); + terminal.clearAlt(); + Arrays.fill(terminal.tabs, false); + Arrays.fill(terminal.altTabs, false); + for (int i = 1; i < Terminal.WIDTH; i++) { + if (i % Terminal.TAB_WIDTH == 0) { + terminal.tabs[i] = true; + terminal.altTabs[i] = true; + } + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/apc/APCManager.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/apc/APCManager.java new file mode 100644 index 00000000..cb234a6b --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/apc/APCManager.java @@ -0,0 +1,24 @@ +package li.cil.oc2.common.vm.terminal.escapes.apc; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class APCManager { + private final Terminal terminal; + private int lastChar = '\0'; + + public APCManager(Terminal terminal) { + this.terminal = terminal; + } + + public void handle(int ch) { + if ((lastChar == '\033' && ch == '\\')) { + terminal.state = Terminal.State.NORMAL; + } else { + lastChar = ch; + } + } + + public void reset() { + lastChar = '\0'; + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH1.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH1.java new file mode 100644 index 00000000..6b1a72b8 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH1.java @@ -0,0 +1,112 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CH1 extends CSISequenceHandler { // Combined Handler 1 (DECSTBM & XTRESTORE) + public CH1(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + if (state.questionMark) { + handleXTRESTORE(args[0]); + } + else if (argCount == 2) { + handleDECSTBM(args, argCount); + } + } + + private void handleXTRESTORE(int mode) { + switch (mode) { + case 1 -> terminal.currentPrivateModeState.DECCKM = terminal.savePrivateModeState.DECCKM; + case 2 -> terminal.currentPrivateModeState.DECANM = terminal.savePrivateModeState.DECANM; + case 3 -> terminal.currentPrivateModeState.DECCOLM = terminal.savePrivateModeState.DECCOLM; + case 4 -> terminal.currentPrivateModeState.DECSCLM = terminal.savePrivateModeState.DECSCLM; + case 5 -> terminal.currentPrivateModeState.DECSCNM = terminal.savePrivateModeState.DECSCNM; + case 6 -> terminal.currentPrivateModeState.DECOM = terminal.savePrivateModeState.DECOM; + case 7 -> terminal.currentPrivateModeState.DECAWM = terminal.savePrivateModeState.DECAWM; + case 8 -> terminal.currentPrivateModeState.DECARM = terminal.savePrivateModeState.DECARM; + case 9 -> terminal.currentPrivateModeState.X10MM = terminal.savePrivateModeState.X10MM; + case 10 -> terminal.currentPrivateModeState.TOOLBAR = terminal.savePrivateModeState.TOOLBAR; + case 12 -> terminal.currentPrivateModeState.START_BLINKING_CURSOR = terminal.savePrivateModeState.START_BLINKING_CURSOR; + case 13 -> terminal.currentPrivateModeState.START_BLINKING_CURSOR2 = terminal.savePrivateModeState.START_BLINKING_CURSOR2; + case 14 -> terminal.currentPrivateModeState.XORBLINK = terminal.savePrivateModeState.XORBLINK; + case 18 -> terminal.currentPrivateModeState.DECPFF = terminal.savePrivateModeState.DECPFF; + case 19 -> terminal.currentPrivateModeState.DECPEX = terminal.savePrivateModeState.DECPEX; + case 25 -> terminal.currentPrivateModeState.DECTCEM = terminal.savePrivateModeState.DECTCEM; + case 30 -> terminal.currentPrivateModeState.SHOW_SCROLL = terminal.savePrivateModeState.SHOW_SCROLL; + case 35 -> terminal.currentPrivateModeState.FONT_SHIFT = terminal.savePrivateModeState.FONT_SHIFT; + case 38 -> terminal.currentPrivateModeState.TEKTRONIX = terminal.savePrivateModeState.TEKTRONIX; + case 40 -> terminal.currentPrivateModeState.ENABLE_80_132 = terminal.savePrivateModeState.ENABLE_80_132; + case 41 -> terminal.currentPrivateModeState.MORE_FIX = terminal.savePrivateModeState.MORE_FIX; + case 42 -> terminal.currentPrivateModeState.DECNRCM = terminal.savePrivateModeState.DECNRCM; + case 43 -> terminal.currentPrivateModeState.DECGEPM = terminal.savePrivateModeState.DECGEPM; + case 44 -> terminal.currentPrivateModeState.MARG_BELL = terminal.savePrivateModeState.MARG_BELL; + case 45 -> terminal.currentPrivateModeState.XTREVWRAP = terminal.savePrivateModeState.XTREVWRAP; + case 46 -> terminal.currentPrivateModeState.XTLOGGING = terminal.savePrivateModeState.XTLOGGING; + case 47 -> terminal.currentPrivateModeState.ALT_BUFFER = terminal.savePrivateModeState.ALT_BUFFER; + case 66 -> terminal.currentPrivateModeState.DECNKM = terminal.savePrivateModeState.DECNKM; + case 67 -> terminal.currentPrivateModeState.DECBKM = terminal.savePrivateModeState.DECBKM; + case 69 -> terminal.currentPrivateModeState.DECLRMM = terminal.savePrivateModeState.DECLRMM; + case 80 -> terminal.currentPrivateModeState.DECSDM = terminal.savePrivateModeState.DECSDM; + case 96 -> terminal.currentPrivateModeState.DECNCSM = terminal.savePrivateModeState.DECNCSM; + case 1000 -> terminal.currentPrivateModeState.X11MM = terminal.savePrivateModeState.X11MM; + case 1001 -> terminal.currentPrivateModeState.HILITE_MOUSE = terminal.savePrivateModeState.HILITE_MOUSE; + case 1002 -> terminal.currentPrivateModeState.CELL_MOTION_MOUSE = terminal.savePrivateModeState.CELL_MOTION_MOUSE; + case 1003 -> terminal.currentPrivateModeState.ALL_MOTION_MOUSE_TRACKING = terminal.savePrivateModeState.ALL_MOTION_MOUSE_TRACKING; + case 1004 -> terminal.currentPrivateModeState.FOCUS_IN_FOCUS_OUT = terminal.savePrivateModeState.FOCUS_IN_FOCUS_OUT; + case 1005 -> terminal.currentPrivateModeState.UTF8_MOUSE = terminal.savePrivateModeState.UTF8_MOUSE; + case 1006 -> terminal.currentPrivateModeState.SGR_MOUSE = terminal.savePrivateModeState.SGR_MOUSE; + case 1007 -> terminal.currentPrivateModeState.ALTERNATE_SCROLL_MODE = terminal.savePrivateModeState.ALTERNATE_SCROLL_MODE; + case 1010 -> terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_OUTPUT = terminal.savePrivateModeState.SCROLL_BOTTOM_ON_OUTPUT; + case 1011 -> terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_KEY_PRESS = terminal.savePrivateModeState.SCROLL_BOTTOM_ON_KEY_PRESS; + case 1014 -> terminal.currentPrivateModeState.FAST_SCROLL = terminal.savePrivateModeState.FAST_SCROLL; + case 1015 -> terminal.currentPrivateModeState.URXVT_MOUSE = terminal.savePrivateModeState.URXVT_MOUSE; + case 1016 -> terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = terminal.savePrivateModeState.SGR_MOUSE_PIXEL; + case 1034 -> terminal.currentPrivateModeState.META_KEY = terminal.savePrivateModeState.META_KEY; + case 1035 -> terminal.currentPrivateModeState.SPECIAL_MODIFIERS = terminal.savePrivateModeState.SPECIAL_MODIFIERS; + case 1036 -> terminal.currentPrivateModeState.META_SENDS_ESCAPE = terminal.savePrivateModeState.META_SENDS_ESCAPE; + case 1037 -> terminal.currentPrivateModeState.DEL_EDIT_KEYPAD_DEL = terminal.savePrivateModeState.DEL_EDIT_KEYPAD_DEL; + case 1039 -> terminal.currentPrivateModeState.ALT_SENDS_ESC = terminal.savePrivateModeState.ALT_SENDS_ESC; + case 1040 -> terminal.currentPrivateModeState.KEEP_SELECTION = terminal.savePrivateModeState.KEEP_SELECTION; + case 1041 -> terminal.currentPrivateModeState.USE_CLIP = terminal.savePrivateModeState.USE_CLIP; + case 1042 -> terminal.currentPrivateModeState.ENABLE_URGENCY = terminal.savePrivateModeState.ENABLE_URGENCY; + case 1043 -> terminal.currentPrivateModeState.RAISE_ON_CTRL_G = terminal.savePrivateModeState.RAISE_ON_CTRL_G; + case 1044 -> terminal.currentPrivateModeState.KEEP_CLIP = terminal.savePrivateModeState.KEEP_CLIP; + case 1045 -> terminal.currentPrivateModeState.EXT_REV_WRAP = terminal.savePrivateModeState.EXT_REV_WRAP; + case 1046 -> terminal.currentPrivateModeState.ALLOW_ALT_BUFFER = terminal.savePrivateModeState.ALLOW_ALT_BUFFER; + case 1047 -> terminal.currentPrivateModeState.SWITCH_ALT_BUFFER = terminal.savePrivateModeState.SWITCH_ALT_BUFFER; + case 1048 -> terminal.currentPrivateModeState.SAVE_CURSOR = terminal.savePrivateModeState.SAVE_CURSOR; + case 1049 -> terminal.currentPrivateModeState.SAVE_CLEAR_AND_SWITCH = terminal.savePrivateModeState.SAVE_CLEAR_AND_SWITCH; + case 1050 -> terminal.currentPrivateModeState.SET_TERMINFO_FUNC_KEY_MODE = terminal.savePrivateModeState.SET_TERMINFO_FUNC_KEY_MODE; + case 1051 -> terminal.currentPrivateModeState.SET_SUN_KEY_MODE = terminal.savePrivateModeState.SET_SUN_KEY_MODE; + case 1052 -> terminal.currentPrivateModeState.SET_HP_K0EY_MODE = terminal.savePrivateModeState.SET_HP_K0EY_MODE; + case 1053 -> terminal.currentPrivateModeState.SET_SCO_KEY_MODE = terminal.savePrivateModeState.SET_SCO_KEY_MODE; + case 1060 -> terminal.currentPrivateModeState.SET_LEGACY_KEYBOARD = terminal.savePrivateModeState.SET_LEGACY_KEYBOARD; + case 1061 -> terminal.currentPrivateModeState.SET_VT220_KEYBOARD = terminal.savePrivateModeState.SET_VT220_KEYBOARD; + case 2001 -> terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_1 = terminal.savePrivateModeState.ENABLE_READLINE_MOUSE_1; + case 2002 -> terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_2 = terminal.savePrivateModeState.ENABLE_READLINE_MOUSE_2; + case 2003 -> terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_3 = terminal.savePrivateModeState.ENABLE_READLINE_MOUSE_3; + case 2004 -> terminal.currentPrivateModeState.SET_BRACKETED_PASTE = terminal.savePrivateModeState.SET_BRACKETED_PASTE; + case 2005 -> terminal.currentPrivateModeState.ENABLE_READLINE_CHAR_QUOTE = terminal.savePrivateModeState.ENABLE_READLINE_CHAR_QUOTE; + case 2006 -> terminal.currentPrivateModeState.ENABLE_READLINE_NEWLINE_PASTE = terminal.savePrivateModeState.ENABLE_READLINE_NEWLINE_PASTE; + } + } + + private void handleDECSTBM(int[] args, int argCount) { + final int first, last; + if (argCount == 2) { + first = args[0] - 1; + last = args[1] - 1; + } else { + first = 0; + last = Terminal.HEIGHT - 1; + } + if (first < 0 || last > Terminal.HEIGHT - 1 || last - first <= 0) { + return; + } + terminal.scrollFirst = first; // to index + terminal.scrollLast = last; // to index + terminal.setRelativeCursorPos(0, 0); // send cursor home + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH2.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH2.java new file mode 100644 index 00000000..983708e1 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH2.java @@ -0,0 +1,207 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; +import li.cil.oc2.common.vm.terminal.modes.ImplementedPrivateModes; + +public class CH2 extends CSISequenceHandler { // Combined Handler 2 (SM & DECSET) + public CH2(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + if (state.questionMark) { + handleDECSET(args, argCount); + } else { + handleSM(args, argCount); + } + } + + private void handleDECSET(int[] args, int argCount) { + for (int i = 0; i < argCount; i++) { + switch (args[i]) { + case 1 -> terminal.currentPrivateModeState.DECCKM = true; + case 2 -> terminal.currentPrivateModeState.DECANM = true; + case 3 -> terminal.currentPrivateModeState.DECCOLM = true; + case 4 -> terminal.currentPrivateModeState.DECSCLM = true; + case 5 -> terminal.currentPrivateModeState.DECSCNM = true; + case 6 -> { + terminal.currentPrivateModeState.DECOM = true; + terminal.setRelativeCursorPos(0, 0); + } + case 7 -> terminal.currentPrivateModeState.DECAWM = true; + case 8 -> terminal.currentPrivateModeState.DECARM = true; + case 9 -> { + terminal.currentPrivateModeState.X11MM = false; + terminal.currentPrivateModeState.CELL_MOTION_MOUSE = false; + terminal.currentPrivateModeState.ALL_MOTION_MOUSE_TRACKING = false; + terminal.currentPrivateModeState.X10MM = true; + } + case 10 -> terminal.currentPrivateModeState.TOOLBAR = true; + case 12 -> { + terminal.cursorMode = switch (terminal.cursorMode) { + case 2 -> 1; + case 4 -> 3; + case 6 -> 5; + default -> terminal.cursorMode; + }; + terminal.currentPrivateModeState.START_BLINKING_CURSOR = true; + } + case 13 -> terminal.currentPrivateModeState.START_BLINKING_CURSOR2 = true; + case 14 -> terminal.currentPrivateModeState.XORBLINK = true; + case 18 -> terminal.currentPrivateModeState.DECPFF = true; + case 19 -> terminal.currentPrivateModeState.DECPEX = true; + case 25 -> terminal.currentPrivateModeState.DECTCEM = true; + case 30 -> terminal.currentPrivateModeState.SHOW_SCROLL = true; + case 35 -> terminal.currentPrivateModeState.FONT_SHIFT = true; + case 38 -> terminal.currentPrivateModeState.TEKTRONIX = true; + case 40 -> terminal.currentPrivateModeState.ENABLE_80_132 = true; + case 41 -> terminal.currentPrivateModeState.MORE_FIX = true; + case 42 -> terminal.currentPrivateModeState.DECNRCM = true; + case 43 -> terminal.currentPrivateModeState.DECGEPM = true; + case 44 -> terminal.currentPrivateModeState.MARG_BELL = true; + case 45 -> terminal.currentPrivateModeState.XTREVWRAP = true; + case 46 -> terminal.currentPrivateModeState.XTLOGGING = true; + case 47 -> { + terminal.clearAlt(); + terminal.setCursorPos(0, 0); + terminal.currentPrivateModeState.ALT_BUFFER = true; + int dirtyLinesMask = 0; + for (int j = 0; j <= 23; j++) { + dirtyLinesMask |= 1 << j; + } + final int finalDirtyLinesMask = dirtyLinesMask; + terminal.renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } + case 66 -> terminal.currentPrivateModeState.DECNKM = true; + case 67 -> terminal.currentPrivateModeState.DECBKM = true; + case 69 -> terminal.currentPrivateModeState.DECLRMM = true; + case 80 -> terminal.currentPrivateModeState.DECSDM = true; + case 96 -> terminal.currentPrivateModeState.DECNCSM = true; + case 1000 -> { + terminal.currentPrivateModeState.CELL_MOTION_MOUSE = false; + terminal.currentPrivateModeState.ALL_MOTION_MOUSE_TRACKING = false; + terminal.currentPrivateModeState.X10MM = false; + terminal.currentPrivateModeState.X11MM = true; + } + case 1001 -> terminal.currentPrivateModeState.HILITE_MOUSE = true; + case 1002 -> { + terminal.currentPrivateModeState.ALL_MOTION_MOUSE_TRACKING = false; + terminal.currentPrivateModeState.X10MM = false; + terminal.currentPrivateModeState.X11MM = false; + terminal.currentPrivateModeState.CELL_MOTION_MOUSE = true; + } + case 1003 -> { + terminal.currentPrivateModeState.CELL_MOTION_MOUSE = false; + terminal.currentPrivateModeState.X10MM = false; + terminal.currentPrivateModeState.X11MM = false; + terminal.currentPrivateModeState.ALL_MOTION_MOUSE_TRACKING = true; + } + case 1004 -> terminal.currentPrivateModeState.FOCUS_IN_FOCUS_OUT = true; + case 1005 -> { + terminal.currentPrivateModeState.SGR_MOUSE = false; + terminal.currentPrivateModeState.URXVT_MOUSE = false; + terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = false; + terminal.currentPrivateModeState.UTF8_MOUSE = true; + } + case 1006 -> { + terminal.currentPrivateModeState.UTF8_MOUSE = false; + terminal.currentPrivateModeState.URXVT_MOUSE = false; + terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = false; + terminal.currentPrivateModeState.SGR_MOUSE = true; + } + case 1007 -> terminal.currentPrivateModeState.ALTERNATE_SCROLL_MODE = true; + case 1010 -> terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_OUTPUT = true; + case 1011 -> terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_KEY_PRESS = true; + case 1014 -> terminal.currentPrivateModeState.FAST_SCROLL = true; + case 1015 -> { + terminal.currentPrivateModeState.UTF8_MOUSE = false; + terminal.currentPrivateModeState.SGR_MOUSE = false; + terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = false; + terminal.currentPrivateModeState.URXVT_MOUSE = true; + } + case 1016 -> { + terminal.currentPrivateModeState.UTF8_MOUSE = false; + terminal.currentPrivateModeState.SGR_MOUSE = false; + terminal.currentPrivateModeState.URXVT_MOUSE = false; + terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = true; + } + case 1034 -> terminal.currentPrivateModeState.META_KEY = true; + case 1035 -> terminal.currentPrivateModeState.SPECIAL_MODIFIERS = true; + case 1036 -> terminal.currentPrivateModeState.META_SENDS_ESCAPE = true; + case 1037 -> terminal.currentPrivateModeState.DEL_EDIT_KEYPAD_DEL = true; + case 1039 -> terminal.currentPrivateModeState.ALT_SENDS_ESC = true; + case 1040 -> terminal.currentPrivateModeState.KEEP_SELECTION = true; + case 1041 -> terminal.currentPrivateModeState.USE_CLIP = true; + case 1042 -> terminal.currentPrivateModeState.ENABLE_URGENCY = true; + case 1043 -> terminal.currentPrivateModeState.RAISE_ON_CTRL_G = true; + case 1044 -> terminal.currentPrivateModeState.KEEP_CLIP = true; + case 1045 -> terminal.currentPrivateModeState.EXT_REV_WRAP = true; + case 1046 -> terminal.currentPrivateModeState.ALLOW_ALT_BUFFER = true; + case 1047 -> { + terminal.clearAlt(); + terminal.setCursorPos(0, 0); + terminal.currentPrivateModeState.SWITCH_ALT_BUFFER = true; + int dirtyLinesMask = 0; + for (int j = 0; j <= 23; j++) { + dirtyLinesMask |= 1 << j; + } + final int finalDirtyLinesMask = dirtyLinesMask; + terminal.renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } + case 1048 -> { + if (terminal.currentPrivateModeState.isAltBufferEnabled()) { + terminal.altSavedX = terminal.x; + terminal.altSavedY = terminal.y; + } else { + terminal.savedX = terminal.x; + terminal.savedY = terminal.y; + } + terminal.currentPrivateModeState.SAVE_CURSOR = true; + } + case 1049 -> { + if (terminal.currentPrivateModeState.isAltBufferEnabled()) { + terminal.altSavedX = terminal.x; + terminal.altSavedY = terminal.y; + } else { + terminal.savedX = terminal.x; + terminal.savedY = terminal.y; + } + terminal.clearAlt(); + terminal.setCursorPos(0, 0); + terminal.currentPrivateModeState.SAVE_CLEAR_AND_SWITCH = true; + int dirtyLinesMask = 0; + for (int j = 0; j <= 23; j++) { + dirtyLinesMask |= 1 << j; + } + final int finalDirtyLinesMask = dirtyLinesMask; + terminal.renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } + case 1050 -> terminal.currentPrivateModeState.SET_TERMINFO_FUNC_KEY_MODE = true; + case 1051 -> terminal.currentPrivateModeState.SET_SUN_KEY_MODE = true; + case 1052 -> terminal.currentPrivateModeState.SET_HP_K0EY_MODE = true; + case 1053 -> terminal.currentPrivateModeState.SET_SCO_KEY_MODE = true; + case 1060 -> terminal.currentPrivateModeState.SET_LEGACY_KEYBOARD = true; + case 1061 -> terminal.currentPrivateModeState.SET_VT220_KEYBOARD = true; + case 2001 -> terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_1 = true; + case 2002 -> terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_2 = true; + case 2003 -> terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_3 = true; + case 2004 -> terminal.currentPrivateModeState.SET_BRACKETED_PASTE = true; + case 2005 -> terminal.currentPrivateModeState.ENABLE_READLINE_CHAR_QUOTE = true; + case 2006 -> terminal.currentPrivateModeState.ENABLE_READLINE_NEWLINE_PASTE = true; + } + + ImplementedPrivateModes.instance.modeUsed(args[i], true); + } + } + + private void handleSM(int[] args, int argCount) { + for (int i = 0; i < argCount; i++) { + switch (args[i]) { + case 2 -> terminal.currentModeState.KAM = true; + case 4 -> terminal.currentModeState.IRM = true; + case 12 -> terminal.currentModeState.SRM = true; + case 20 -> terminal.currentModeState.LNM = true; + } + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH3.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH3.java new file mode 100644 index 00000000..0fab372e --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH3.java @@ -0,0 +1,156 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; +import li.cil.oc2.common.vm.terminal.modes.ImplementedPrivateModes; + +public class CH3 extends CSISequenceHandler { // Combined Handler 3 (RM & DECRST) + public CH3(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + if (state.questionMark) { + handleDECRST(args, argCount); + } + else if (argCount == 2) { + handleRM(args, argCount); + } + } + + private void handleDECRST(int[] args, int argCount) { + for (int i = 0; i < argCount; i++) { + switch (args[i]) { + case 1 -> terminal.currentPrivateModeState.DECCKM = false; + case 2 -> terminal.currentPrivateModeState.DECANM = false; + case 3 -> terminal.currentPrivateModeState.DECCOLM = false; + case 4 -> terminal.currentPrivateModeState.DECSCLM = false; + case 5 -> terminal.currentPrivateModeState.DECSCNM = false; + case 6 -> { + terminal.currentPrivateModeState.DECOM = false; + terminal.setRelativeCursorPos(0, 0); + terminal.clear(); + } + case 7 -> terminal.currentPrivateModeState.DECAWM = false; + case 8 -> terminal.currentPrivateModeState.DECARM = false; + case 9 -> terminal.currentPrivateModeState.X10MM = false; + case 10 -> terminal.currentPrivateModeState.TOOLBAR = false; + case 12 -> terminal.currentPrivateModeState.START_BLINKING_CURSOR = false; + case 13 -> terminal.currentPrivateModeState.START_BLINKING_CURSOR2 = false; + case 14 -> terminal.currentPrivateModeState.XORBLINK = false; + case 18 -> terminal.currentPrivateModeState.DECPFF = false; + case 19 -> terminal.currentPrivateModeState.DECPEX = false; + case 25 -> terminal.currentPrivateModeState.DECTCEM = false; + case 30 -> terminal.currentPrivateModeState.SHOW_SCROLL = false; + case 35 -> terminal.currentPrivateModeState.FONT_SHIFT = false; + case 38 -> terminal.currentPrivateModeState.TEKTRONIX = false; + case 40 -> terminal.currentPrivateModeState.ENABLE_80_132 = false; + case 41 -> terminal.currentPrivateModeState.MORE_FIX = false; + case 42 -> terminal.currentPrivateModeState.DECNRCM = false; + case 43 -> terminal.currentPrivateModeState.DECGEPM = false; + case 44 -> terminal.currentPrivateModeState.MARG_BELL = false; + case 45 -> terminal.currentPrivateModeState.XTREVWRAP = false; + case 46 -> terminal.currentPrivateModeState.XTLOGGING = false; + case 47 -> { + terminal.currentPrivateModeState.ALT_BUFFER = false; + int dirtyLinesMask = 0; + for (int j = 0; j <= 23; j++) { + dirtyLinesMask |= 1 << j; + } + final int finalDirtyLinesMask = dirtyLinesMask; + terminal.renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } + case 66 -> terminal.currentPrivateModeState.DECNKM = false; + case 67 -> terminal.currentPrivateModeState.DECBKM = false; + case 69 -> terminal.currentPrivateModeState.DECLRMM = false; + case 80 -> terminal.currentPrivateModeState.DECSDM = false; + case 96 -> terminal.currentPrivateModeState.DECNCSM = false; + case 1000 -> terminal.currentPrivateModeState.X11MM = false; + case 1001 -> terminal.currentPrivateModeState.HILITE_MOUSE = false; + case 1002 -> terminal.currentPrivateModeState.CELL_MOTION_MOUSE = false; + case 1003 -> terminal.currentPrivateModeState.ALL_MOTION_MOUSE_TRACKING = false; + case 1004 -> terminal.currentPrivateModeState.FOCUS_IN_FOCUS_OUT = false; + case 1005 -> terminal.currentPrivateModeState.UTF8_MOUSE = false; + case 1006 -> terminal.currentPrivateModeState.SGR_MOUSE = false; + case 1007 -> terminal.currentPrivateModeState.ALTERNATE_SCROLL_MODE = false; + case 1010 -> terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_OUTPUT = false; + case 1011 -> terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_KEY_PRESS = false; + case 1014 -> terminal.currentPrivateModeState.FAST_SCROLL = false; + case 1015 -> terminal.currentPrivateModeState.URXVT_MOUSE = false; + case 1016 -> terminal.currentPrivateModeState.SGR_MOUSE_PIXEL = false; + case 1034 -> terminal.currentPrivateModeState.META_KEY = false; + case 1035 -> terminal.currentPrivateModeState.SPECIAL_MODIFIERS = false; + case 1036 -> terminal.currentPrivateModeState.META_SENDS_ESCAPE = false; + case 1037 -> terminal.currentPrivateModeState.DEL_EDIT_KEYPAD_DEL = false; + case 1039 -> terminal.currentPrivateModeState.ALT_SENDS_ESC = false; + case 1040 -> terminal.currentPrivateModeState.KEEP_SELECTION = false; + case 1041 -> terminal.currentPrivateModeState.USE_CLIP = false; + case 1042 -> terminal.currentPrivateModeState.ENABLE_URGENCY = false; + case 1043 -> terminal.currentPrivateModeState.RAISE_ON_CTRL_G = false; + case 1044 -> terminal.currentPrivateModeState.KEEP_CLIP = false; + case 1045 -> terminal.currentPrivateModeState.EXT_REV_WRAP = false; + case 1046 -> terminal.currentPrivateModeState.ALLOW_ALT_BUFFER = false; + case 1047 -> { + terminal.currentPrivateModeState.SWITCH_ALT_BUFFER = false; + int dirtyLinesMask = 0; + for (int j = 0; j <= 23; j++) { + dirtyLinesMask |= 1 << j; + } + final int finalDirtyLinesMask = dirtyLinesMask; + terminal.renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } + case 1048 -> { + terminal.currentPrivateModeState.SAVE_CURSOR = false; + if (terminal.currentPrivateModeState.isAltBufferEnabled()) { + terminal.x = terminal.altSavedX; + terminal.y = terminal.altSavedY; + } else { + terminal.x = terminal.savedX; + terminal.y = terminal.savedY; + } + } + case 1049 -> { + terminal.currentPrivateModeState.SAVE_CLEAR_AND_SWITCH = false; + if (terminal.currentPrivateModeState.isAltBufferEnabled()) { + terminal.x = terminal.altSavedX; + terminal.y = terminal.altSavedY; + } else { + terminal.x = terminal.savedX; + terminal.y = terminal.savedY; + } + int dirtyLinesMask = 0; + for (int j = 0; j <= 23; j++) { + dirtyLinesMask |= 1 << j; + } + final int finalDirtyLinesMask = dirtyLinesMask; + terminal.renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(finalDirtyLinesMask, (left, right) -> left | right)); + } + case 1050 -> terminal.currentPrivateModeState.SET_TERMINFO_FUNC_KEY_MODE = false; + case 1051 -> terminal.currentPrivateModeState.SET_SUN_KEY_MODE = false; + case 1052 -> terminal.currentPrivateModeState.SET_HP_K0EY_MODE = false; + case 1053 -> terminal.currentPrivateModeState.SET_SCO_KEY_MODE = false; + case 1060 -> terminal.currentPrivateModeState.SET_LEGACY_KEYBOARD = false; + case 1061 -> terminal.currentPrivateModeState.SET_VT220_KEYBOARD = false; + case 2001 -> terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_1 = false; + case 2002 -> terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_2 = false; + case 2003 -> terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_3 = false; + case 2004 -> terminal.currentPrivateModeState.SET_BRACKETED_PASTE = false; + case 2005 -> terminal.currentPrivateModeState.ENABLE_READLINE_CHAR_QUOTE = false; + case 2006 -> terminal.currentPrivateModeState.ENABLE_READLINE_NEWLINE_PASTE = false; + case 2026 -> terminal.currentPrivateModeState.APPLICATION_SYNC = false; + } + + ImplementedPrivateModes.instance.modeUsed(args[i], false); + } + } + + private void handleRM(int[] args, int argCount) { + for (int i = 0; i < argCount; i++) { + switch (args[i]) { + case 2 -> terminal.currentModeState.KAM = false; + case 4 -> terminal.currentModeState.IRM = false; + case 12 -> terminal.currentModeState.SRM = false; + case 20 -> terminal.currentModeState.LNM = false; + } + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH4.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH4.java new file mode 100644 index 00000000..a89bd0c4 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH4.java @@ -0,0 +1,28 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CH4 extends CSISequenceHandler { // Combined Handler 4 (XTWINOPS, XTSMTITLE, DECSWBV, and DECRARA) + public CH4(final Terminal terminal) { + super(terminal); + } + + @Override + public void execute(final int[] args, final int argsCount, final CSIState state) { + if (state.greaterThan) { // XTSMTITLE + System.out.println("XTSMTITLE is not implemented"); + } else if (state.space) { // DECSWBV + System.out.println("DECSWBV is not implemented yet"); + } else if (state.dollarSign) { //DECRARA + System.out.println("DECRARA is not implemented"); + } else { // XTWINOPS + switch (args[0]) { + case 14 -> terminal.putResponse("\033[4;" + Terminal.HEIGHT + ";" + Terminal.WIDTH); //terminal.putResponse("\033[4;" + (Terminal.HEIGHT * Terminal.CHAR_HEIGHT) + ";" + (Terminal.WIDTH * Terminal.CHAR_WIDTH)); + case 15 -> terminal.putResponse("\033[5;" + (Terminal.HEIGHT * Terminal.CHAR_HEIGHT) + ";" + (Terminal.WIDTH * Terminal.CHAR_WIDTH)); + case 16 -> terminal.putResponse("\033[6;" + Terminal.CHAR_HEIGHT + ";" + Terminal.CHAR_WIDTH); + case 18 -> terminal.putResponse("\033[8;" + Terminal.HEIGHT + ";" + Terminal.WIDTH); + case 19 -> terminal.putResponse("\033[9;" + Terminal.HEIGHT + ";" + Terminal.WIDTH); + } + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH5.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH5.java new file mode 100644 index 00000000..4a6d39dc --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH5.java @@ -0,0 +1,30 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CH5 extends CSISequenceHandler { // Combined Handler 5 (XTSMPOINTER, DECSTR, DECSCL, and DECRARA) + public CH5(final Terminal terminal) { + super(terminal); + } + + @Override + public void execute(final int[] args, final int argsCount, final CSIState state) { + if (state.greaterThan) { // XTSMPOINTER + System.out.println("XTSMPOINTER not implemented"); + } else if (state.exclamation) { // DECSTR + System.out.println("DECSTR not implemented"); + } else if (state.quote) { // DECSCL + System.out.println("DECSCL not implemented"); + } else if (state.dollarSign) { // DECRQM + int mode = args[0]; + if (state.questionMark) { // DECSET/DECRST + terminal.putResponse("\033[?" + mode + ";" + (terminal.currentPrivateModeState.getMode(mode) ? 1 : 0) + "$y"); + } + else { // SM/RM + terminal.putResponse("\033[" + mode + ";" + (terminal.currentModeState.getMode(mode) ? 1 : 0) + "$y"); + } + } else { // XTPUSHSGR + System.out.println("XTPUSHSGR not implemented"); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH6.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH6.java new file mode 100644 index 00000000..0c33438c --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH6.java @@ -0,0 +1,104 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CH6 extends CSISequenceHandler { // Combined Handler 6 (XTSAVE, XTSHIFTESCAPE, DECSLRM, and SCOSC) + public CH6(final Terminal terminal) { + super(terminal); + } + + public void execute(final int[] args, final int argsCount, final CSIState state) { + if (state.questionMark) { // XTSAVE + handleXTSAVE(args[0]); + } + else if (state.greaterThan) { // XTSHIFTESCAPE + System.out.println("XTSHIFTESCAPE not implemented"); + } + else if (argsCount == 2) { // DECSLRM + System.out.println("DECSLRM not implemented"); + } + else if (argsCount == 0) { // SCOSC + if (!terminal.currentPrivateModeState.DECLRMM) { + terminal.savedX = terminal.x; + terminal.savedY = terminal.y; + } + } + } + + private void handleXTSAVE(final int mode) { + switch (mode) { + case 1 -> terminal.savePrivateModeState.DECCKM = terminal.currentPrivateModeState.DECCKM; + case 2 -> terminal.savePrivateModeState.DECANM = terminal.currentPrivateModeState.DECANM; + case 3 -> terminal.savePrivateModeState.DECCOLM = terminal.currentPrivateModeState.DECCOLM; + case 4 -> terminal.savePrivateModeState.DECSCLM = terminal.currentPrivateModeState.DECSCLM; + case 5 -> terminal.savePrivateModeState.DECSCNM = terminal.currentPrivateModeState.DECSCNM; + case 6 -> terminal.savePrivateModeState.DECOM = terminal.currentPrivateModeState.DECOM; + case 7 -> terminal.savePrivateModeState.DECAWM = terminal.currentPrivateModeState.DECAWM; + case 8 -> terminal.savePrivateModeState.DECARM = terminal.currentPrivateModeState.DECARM; + case 9 -> terminal.savePrivateModeState.X10MM = terminal.currentPrivateModeState.X10MM; + case 10 -> terminal.savePrivateModeState.TOOLBAR = terminal.currentPrivateModeState.TOOLBAR; + case 12 -> terminal.savePrivateModeState.START_BLINKING_CURSOR = terminal.currentPrivateModeState.START_BLINKING_CURSOR; + case 13 -> terminal.savePrivateModeState.START_BLINKING_CURSOR2 = terminal.currentPrivateModeState.START_BLINKING_CURSOR2; + case 14 -> terminal.savePrivateModeState.XORBLINK = terminal.currentPrivateModeState.XORBLINK; + case 18 -> terminal.savePrivateModeState.DECPFF = terminal.currentPrivateModeState.DECPFF; + case 19 -> terminal.savePrivateModeState.DECPEX = terminal.currentPrivateModeState.DECPEX; + case 25 -> terminal.savePrivateModeState.DECTCEM = terminal.currentPrivateModeState.DECTCEM; + case 30 -> terminal.savePrivateModeState.SHOW_SCROLL = terminal.currentPrivateModeState.SHOW_SCROLL; + case 35 -> terminal.savePrivateModeState.FONT_SHIFT = terminal.currentPrivateModeState.FONT_SHIFT; + case 38 -> terminal.savePrivateModeState.TEKTRONIX = terminal.currentPrivateModeState.TEKTRONIX; + case 40 -> terminal.savePrivateModeState.ENABLE_80_132 = terminal.currentPrivateModeState.ENABLE_80_132; + case 41 -> terminal.savePrivateModeState.MORE_FIX = terminal.currentPrivateModeState.MORE_FIX; + case 42 -> terminal.savePrivateModeState.DECNRCM = terminal.currentPrivateModeState.DECNRCM; + case 43 -> terminal.savePrivateModeState.DECGEPM = terminal.currentPrivateModeState.DECGEPM; + case 44 -> terminal.savePrivateModeState.MARG_BELL = terminal.currentPrivateModeState.MARG_BELL; + case 45 -> terminal.savePrivateModeState.XTREVWRAP = terminal.currentPrivateModeState.XTREVWRAP; + case 46 -> terminal.savePrivateModeState.XTLOGGING = terminal.currentPrivateModeState.XTLOGGING; + case 47 -> terminal.savePrivateModeState.ALT_BUFFER = terminal.currentPrivateModeState.ALT_BUFFER; + case 66 -> terminal.savePrivateModeState.DECNKM = terminal.currentPrivateModeState.DECNKM; + case 67 -> terminal.savePrivateModeState.DECBKM = terminal.currentPrivateModeState.DECBKM; + case 69 -> terminal.savePrivateModeState.DECLRMM = terminal.currentPrivateModeState.DECLRMM; + case 80 -> terminal.savePrivateModeState.DECSDM = terminal.currentPrivateModeState.DECSDM; + case 96 -> terminal.savePrivateModeState.DECNCSM = terminal.currentPrivateModeState.DECNCSM; + case 1000 -> terminal.savePrivateModeState.X11MM = terminal.currentPrivateModeState.X11MM; + case 1001 -> terminal.savePrivateModeState.HILITE_MOUSE = terminal.currentPrivateModeState.HILITE_MOUSE; + case 1002 -> terminal.savePrivateModeState.CELL_MOTION_MOUSE = terminal.currentPrivateModeState.CELL_MOTION_MOUSE; + case 1003 -> terminal.savePrivateModeState.ALL_MOTION_MOUSE_TRACKING = terminal.currentPrivateModeState.ALL_MOTION_MOUSE_TRACKING; + case 1004 -> terminal.savePrivateModeState.FOCUS_IN_FOCUS_OUT = terminal.currentPrivateModeState.FOCUS_IN_FOCUS_OUT; + case 1005 -> terminal.savePrivateModeState.UTF8_MOUSE = terminal.currentPrivateModeState.UTF8_MOUSE; + case 1006 -> terminal.savePrivateModeState.SGR_MOUSE = terminal.currentPrivateModeState.SGR_MOUSE; + case 1007 -> terminal.savePrivateModeState.ALTERNATE_SCROLL_MODE = terminal.currentPrivateModeState.ALTERNATE_SCROLL_MODE; + case 1010 -> terminal.savePrivateModeState.SCROLL_BOTTOM_ON_OUTPUT = terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_OUTPUT; + case 1011 -> terminal.savePrivateModeState.SCROLL_BOTTOM_ON_KEY_PRESS = terminal.currentPrivateModeState.SCROLL_BOTTOM_ON_KEY_PRESS; + case 1014 -> terminal.savePrivateModeState.FAST_SCROLL = terminal.currentPrivateModeState.FAST_SCROLL; + case 1015 -> terminal.savePrivateModeState.URXVT_MOUSE = terminal.currentPrivateModeState.URXVT_MOUSE; + case 1016 -> terminal.savePrivateModeState.SGR_MOUSE_PIXEL = terminal.currentPrivateModeState.SGR_MOUSE_PIXEL; + case 1034 -> terminal.savePrivateModeState.META_KEY = terminal.currentPrivateModeState.META_KEY; + case 1035 -> terminal.savePrivateModeState.SPECIAL_MODIFIERS = terminal.currentPrivateModeState.SPECIAL_MODIFIERS; + case 1036 -> terminal.savePrivateModeState.META_SENDS_ESCAPE = terminal.currentPrivateModeState.META_SENDS_ESCAPE; + case 1037 -> terminal.savePrivateModeState.DEL_EDIT_KEYPAD_DEL = terminal.currentPrivateModeState.DEL_EDIT_KEYPAD_DEL; + case 1039 -> terminal.savePrivateModeState.ALT_SENDS_ESC = terminal.currentPrivateModeState.ALT_SENDS_ESC; + case 1040 -> terminal.savePrivateModeState.KEEP_SELECTION = terminal.currentPrivateModeState.KEEP_SELECTION; + case 1041 -> terminal.savePrivateModeState.USE_CLIP = terminal.currentPrivateModeState.USE_CLIP; + case 1042 -> terminal.savePrivateModeState.ENABLE_URGENCY = terminal.currentPrivateModeState.ENABLE_URGENCY; + case 1043 -> terminal.savePrivateModeState.RAISE_ON_CTRL_G = terminal.currentPrivateModeState.RAISE_ON_CTRL_G; + case 1044 -> terminal.savePrivateModeState.KEEP_CLIP = terminal.currentPrivateModeState.KEEP_CLIP; + case 1045 -> terminal.savePrivateModeState.EXT_REV_WRAP = terminal.currentPrivateModeState.EXT_REV_WRAP; + case 1046 -> terminal.savePrivateModeState.ALLOW_ALT_BUFFER = terminal.currentPrivateModeState.ALLOW_ALT_BUFFER; + case 1047 -> terminal.savePrivateModeState.SWITCH_ALT_BUFFER = terminal.currentPrivateModeState.SWITCH_ALT_BUFFER; + case 1048 -> terminal.savePrivateModeState.SAVE_CURSOR = terminal.currentPrivateModeState.SAVE_CURSOR; + case 1049 -> terminal.savePrivateModeState.SAVE_CLEAR_AND_SWITCH = terminal.currentPrivateModeState.SAVE_CLEAR_AND_SWITCH; + case 1050 -> terminal.savePrivateModeState.SET_TERMINFO_FUNC_KEY_MODE = terminal.currentPrivateModeState.SET_TERMINFO_FUNC_KEY_MODE; + case 1051 -> terminal.savePrivateModeState.SET_SUN_KEY_MODE = terminal.currentPrivateModeState.SET_SUN_KEY_MODE; + case 1052 -> terminal.savePrivateModeState.SET_HP_K0EY_MODE = terminal.currentPrivateModeState.SET_HP_K0EY_MODE; + case 1053 -> terminal.savePrivateModeState.SET_SCO_KEY_MODE = terminal.currentPrivateModeState.SET_SCO_KEY_MODE; + case 1060 -> terminal.savePrivateModeState.SET_LEGACY_KEYBOARD = terminal.currentPrivateModeState.SET_LEGACY_KEYBOARD; + case 1061 -> terminal.savePrivateModeState.SET_VT220_KEYBOARD = terminal.currentPrivateModeState.SET_VT220_KEYBOARD; + case 2001 -> terminal.savePrivateModeState.ENABLE_READLINE_MOUSE_1 = terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_1; + case 2002 -> terminal.savePrivateModeState.ENABLE_READLINE_MOUSE_2 = terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_2; + case 2003 -> terminal.savePrivateModeState.ENABLE_READLINE_MOUSE_3 = terminal.currentPrivateModeState.ENABLE_READLINE_MOUSE_3; + case 2004 -> terminal.savePrivateModeState.SET_BRACKETED_PASTE = terminal.currentPrivateModeState.SET_BRACKETED_PASTE; + case 2005 -> terminal.savePrivateModeState.ENABLE_READLINE_CHAR_QUOTE = terminal.currentPrivateModeState.ENABLE_READLINE_CHAR_QUOTE; + case 2006 -> terminal.savePrivateModeState.ENABLE_READLINE_NEWLINE_PASTE = terminal.currentPrivateModeState.ENABLE_READLINE_NEWLINE_PASTE; + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH7.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH7.java new file mode 100644 index 00000000..85f70259 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH7.java @@ -0,0 +1,28 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CH7 extends CSISequenceHandler { // Combined Handler 7 (XTVERSION, DECLL, DECSCUSR, DECSCA, and XTPOPSGR) + public CH7(final Terminal terminal) { + super(terminal); + } + + public void execute(final int[] args, final int argsCount, final CSIState state) { + if (state.greaterThan) { // XTVERSION + System.out.println("XTVERSION not implemented"); + } else if (state.space) { // DECSCUSR + int cursorStyle = args[0]; + if (cursorStyle < 0 || cursorStyle > 6) { + terminal.cursorMode = Terminal.CursorMode.DEFAULT; + return; + } + terminal.cursorMode = cursorStyle; + } else if (state.quote) { // DECSCA + System.out.println("DECSCA not implemented"); + } else if (state.hash) { // XTPOPSGR + System.out.println("XTPOPSGR not implemented"); + } else { // DECLL + System.out.println("DECLL not implemented"); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH8.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH8.java new file mode 100644 index 00000000..b38aab5f --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH8.java @@ -0,0 +1,21 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CH8 extends CSISequenceHandler { // Combined Handler 8 (SU, XTTITLEPOS, and XTSMGRAPHICS) + public CH8(final Terminal terminal) { + super(terminal); + } + + public void execute(final int[] args, final int argsCount, final CSIState state) { + if (state.questionMark) { // XTSMGRAPHICS + System.out.println("XTSMGRAPHICS not implemented"); + } else if (state.hash) { // XTTITLEPOS + System.out.println("XTTITLEPOS not implemented"); + } else { // SU + for (int i = 0; i < args[0]; i++) { + terminal.shiftUpOne(); + } + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH9.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH9.java new file mode 100644 index 00000000..11cb2f07 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CH9.java @@ -0,0 +1,21 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CH9 extends CSISequenceHandler { // Combined Handler 9 (SD, XTHIMOUSE, and XTRMTITLE) + public CH9(final Terminal terminal) { + super(terminal); + } + + public void execute(final int[] args, final int argsCount, final CSIState state) { + if (state.greaterThan) { // XTRMTITLE + System.out.println("XTRMTITLE not implemented"); + } else if (argsCount == 5) { // XTHIMOUSE + System.out.println("XTHIMOUSE not implemented"); + } else { // SD + for (int i = 0; i < args[0]; i++) { + terminal.shiftDownOne(); + } + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CHA.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CHA.java new file mode 100644 index 00000000..d9802cb8 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CHA.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CHA extends CSISequenceHandler { + public CHA(final Terminal terminal) { + super(terminal); + } + + public void execute(final int[] args, final int argsCount, final CSIState state) { + terminal.setClampedCursorPos(args[0] - 1, terminal.y); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CSIManager.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CSIManager.java new file mode 100644 index 00000000..93423f52 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CSIManager.java @@ -0,0 +1,126 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; +import li.cil.oc2.common.vm.terminal.escapes.EscapeUtilities; + +import java.util.Arrays; +import java.util.HashMap; + +public class CSIManager { + private final int[] args = new int[10]; + private int argCount = 0; + private boolean questionMark = false; + private boolean greaterThan = false; + private boolean dollarSign = false; + private boolean hash = false; + private boolean quote = false; + private boolean singleQuote = false; + private boolean space = false; + private boolean exclamation = false; + + private final Terminal terminal; + private final HashMap sequences = new HashMap<>(); + + public CSIManager(Terminal terminal) { + this.terminal = terminal; + + sequences.put('A', new CUU(terminal)); + sequences.put('B', new CUD(terminal)); + sequences.put('C', new CUF(terminal)); + sequences.put('D', new CUB(terminal)); + sequences.put('H', new CUP(terminal)); + sequences.put('f', new HVP(terminal)); + sequences.put('m', new SGR(terminal)); + sequences.put('K', new EL(terminal)); + sequences.put('J', new ED(terminal)); + sequences.put('r', new CH1(terminal)); + sequences.put('g', new TBC(terminal)); + sequences.put('h', new CH2(terminal)); + sequences.put('l', new CH3(terminal)); + sequences.put('n', new DSR(terminal)); + sequences.put('c', new DA(terminal)); + sequences.put('d', new VPA(terminal)); + sequences.put('G', new CHA(terminal)); + sequences.put('t', new CH4(terminal)); + sequences.put('p', new CH5(terminal)); + sequences.put('s', new CH6(terminal)); + sequences.put('X', new ECH(terminal)); + sequences.put('q', new CH7(terminal)); + sequences.put('L', new IL(terminal)); + sequences.put('M', new DL(terminal)); + sequences.put('S', new CH8(terminal)); + sequences.put('T', new CH9(terminal)); + } + + public void handle(final char ch) { + if (ch >= '0' && ch <= '9') { + if (argCount < args.length) { + args[argCount] = EscapeUtilities.parseArgument(ch, args[argCount]); + } + } else { + switch (ch) { + case ' ' -> { + space = true; + return; + } + case '?' -> { + questionMark = true; + return; + } + case '>' -> { + greaterThan = true; + return; + } + case '$' -> { + dollarSign = true; + return; + } + case '#' -> { + hash = true; + return; + } + case '"' -> { + quote = true; + return; + } + case '\'' -> { + singleQuote = true; + return; + } + case '!' -> { + exclamation = true; + return; + } + case ';' -> { + argCount++; + return; // Keep going, we have another argument. + } + default -> argCount++; + } + + terminal.state = Terminal.State.NORMAL; + + CSISequenceHandler handler = sequences.get(ch); + CSIState state = new CSIState(questionMark, greaterThan, dollarSign, hash, quote, singleQuote, space, exclamation); + + if (handler != null) { + handler.execute(args, argCount, state); + } + else { + System.out.println("Control sequence: " + ch); + } + } + } + + public void reset() { + questionMark = false; + greaterThan = false; + dollarSign = false; + hash = false; + quote = false; + singleQuote = false; + space = false; + argCount = 0; + Arrays.fill(args, 0); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CSISequenceHandler.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CSISequenceHandler.java new file mode 100644 index 00000000..991e202d --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CSISequenceHandler.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public abstract class CSISequenceHandler { + protected Terminal terminal; + + public CSISequenceHandler(Terminal terminal) { + this.terminal = terminal; + } + + public abstract void execute(int[] args, int argsCount, CSIState state); +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CSIState.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CSIState.java new file mode 100644 index 00000000..0f1003ea --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CSIState.java @@ -0,0 +1,23 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +public class CSIState { + public boolean questionMark; + public boolean greaterThan; + public boolean dollarSign; + public boolean hash; + public boolean quote; + public boolean singleQuote; + public boolean space; + public boolean exclamation; + + public CSIState(boolean questionMark, boolean greaterThan, boolean dollarSign, boolean hash, boolean quote, boolean singleQuote, boolean space, boolean exclamation) { + this.questionMark = questionMark; + this.greaterThan = greaterThan; + this.dollarSign = dollarSign; + this.hash = hash; + this.quote = quote; + this.singleQuote = singleQuote; + this.space = space; + this.exclamation = exclamation; + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUB.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUB.java new file mode 100644 index 00000000..49305c81 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUB.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CUB extends CSISequenceHandler { + public CUB(Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argsCount, CSIState state) { + terminal.setClampedCursorPos(terminal.x - Math.max(1, args[0]), terminal.y); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUD.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUD.java new file mode 100644 index 00000000..e11e913f --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUD.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CUD extends CSISequenceHandler { + public CUD(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argsCount, CSIState state) { + terminal.setClampedCursorPos(terminal.x, terminal.y + Math.max(1, args[0])); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUF.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUF.java new file mode 100644 index 00000000..0de5fb7d --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUF.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CUF extends CSISequenceHandler { + public CUF(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argsCount, CSIState state) { + terminal.setClampedCursorPos(terminal.x + Math.max(1, args[0]), terminal.y); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUP.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUP.java new file mode 100644 index 00000000..f5a6a64f --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUP.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CUP extends CSISequenceHandler { + public CUP(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argsCount, CSIState state) { + terminal.setRelativeCursorPos(args[1] - 1, args[0] - 1); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUU.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUU.java new file mode 100644 index 00000000..9e96ea85 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/CUU.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class CUU extends CSISequenceHandler { + public CUU(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argsCount, CSIState state) { + terminal.setClampedCursorPos(terminal.x, terminal.y - Math.max(1, args[0])); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DA.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DA.java new file mode 100644 index 00000000..f9e4494d --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DA.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class DA extends CSISequenceHandler { + public DA(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + terminal.putResponse("\033[?1;0c"); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DL.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DL.java new file mode 100644 index 00000000..cf6805fa --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DL.java @@ -0,0 +1,27 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class DL extends CSISequenceHandler { + public DL(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + terminal.setCursorPos(0, terminal.y); + + int lines = Math.max(args[0], 1); + + for (int i = 0; i < lines; i++) { + terminal.clearLine(terminal.y + i); + } + + boolean useAltBuffer = terminal.currentPrivateModeState.isAltBufferEnabled(); + + if (useAltBuffer) { + terminal.shiftLines(terminal.y + lines, terminal.scrollLast, -lines); + } else { + terminal.shiftLines(terminal.y + lines, Terminal.HEIGHT * terminal.SCROLL_BACK_COUNT - 1, -lines); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DSR.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DSR.java new file mode 100644 index 00000000..741697d9 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/DSR.java @@ -0,0 +1,16 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class DSR extends CSISequenceHandler { + public DSR(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + switch (args[0]) { + case 5 -> terminal.putResponse("\033[0n"); // Report console status + case 6 -> terminal.putResponse(String.format("\033[?%d;%dR", terminal.y + 1, terminal.x + 1)); // Report cursor position + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/ECH.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/ECH.java new file mode 100644 index 00000000..b13d1a57 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/ECH.java @@ -0,0 +1,46 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +import java.util.Arrays; + +public class ECH extends CSISequenceHandler { + public ECH(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + int chars = args[0]; + if (terminal.currentPrivateModeState.isAltBufferEnabled()) { + int fromIndex = terminal.x + terminal.y * Terminal.WIDTH; + int toIndex = fromIndex + Math.max(Math.min(Math.max(chars, 1), Terminal.WIDTH - terminal.x), 1); + Arrays.fill(terminal.altBuffer, fromIndex, toIndex, '\0'); + Arrays.fill(terminal.altColors, fromIndex, toIndex, Terminal.DEFAULT_COLORS.Copy()); + Terminal.ColorData c; + switch (terminal.currentBackgroundColorMode) { + case SIXTEEN_COLOR -> c = terminal.sixteenColor; + case TWO_FIFTY_SIX_COLOR -> c = terminal.twoFiftySixColor; + case TRUE_COLOR -> c = terminal.backgroundColor; + default -> c = Terminal.DEFAULT_COLORS.Copy(); + } + Arrays.fill(terminal.altColorsBackground, fromIndex, toIndex, c.Copy()); + Arrays.fill(terminal.altStyles, fromIndex, toIndex, Terminal.DEFAULT_STYLE); + } else { + int fromIndex = terminal.x + (terminal.y + (terminal.lastRowToDisplayMax - Terminal.HEIGHT)) * Terminal.WIDTH; + int toIndex = fromIndex + Math.max(Math.min(Math.max(chars, 1), Terminal.WIDTH - terminal.x), 1); + Arrays.fill(terminal.buffer, fromIndex, toIndex, '\0'); + Arrays.fill(terminal.colors, fromIndex, toIndex, Terminal.DEFAULT_COLORS.Copy()); + Terminal.ColorData c; + switch (terminal.currentBackgroundColorMode) { + case SIXTEEN_COLOR -> c = terminal.sixteenColor; + case TWO_FIFTY_SIX_COLOR -> c = terminal.twoFiftySixColor; + case TRUE_COLOR -> c = terminal.backgroundColor; + default -> c = Terminal.DEFAULT_COLORS.Copy(); + } + Arrays.fill(terminal.colorsBackground, fromIndex, toIndex, c.Copy()); + Arrays.fill(terminal.styles, fromIndex, toIndex, Terminal.DEFAULT_STYLE); + } + + terminal.renderers.forEach(model -> model.getDirtyMask().accumulateAndGet(1 << terminal.y, (left, right) -> left | right)); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/ED.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/ED.java new file mode 100644 index 00000000..67554bae --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/ED.java @@ -0,0 +1,28 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class ED extends CSISequenceHandler { + public ED(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + switch (args[0]) { + case 0 -> { // From cursor to end of screen + terminal.clearLine(terminal.y, terminal.x, Terminal.WIDTH); + for (int iy = terminal.y + 1; iy < Terminal.HEIGHT; iy++) { + terminal.clearLine(iy); + } + } + case 1 -> { // From beginning of screen to cursor + for (int iy = 0; iy < terminal.y; iy++) { + terminal.clearLine(iy); + } + terminal.clearLine(terminal.y, 0, terminal.x + 1); + } + case 2 -> // Entire screen + terminal.clear(); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/EL.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/EL.java new file mode 100644 index 00000000..1a7b4047 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/EL.java @@ -0,0 +1,20 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class EL extends CSISequenceHandler { + public EL(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + switch (args[0]) { + case 0 -> // From cursor to end of line + terminal.clearLine(terminal.y, terminal.x, Terminal.WIDTH); + case 1 -> // From beginning of line to cursor + terminal.clearLine(terminal.y, 0, terminal.x + 1); + case 2 -> // Entire line containing cursor + terminal.clearLine(terminal.y); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/HVP.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/HVP.java new file mode 100644 index 00000000..2ba80364 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/HVP.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class HVP extends CSISequenceHandler { + public HVP(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argsCount, CSIState state) { + terminal.setRelativeCursorPos(args[1] - 1, args[0] - 1); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/IL.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/IL.java new file mode 100644 index 00000000..72dabba8 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/IL.java @@ -0,0 +1,20 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class IL extends CSISequenceHandler { + public IL(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + boolean useAltBuffer = terminal.currentPrivateModeState.isAltBufferEnabled(); + int lines = Math.max(args[0], 1); + if (useAltBuffer) { + terminal.shiftLines(terminal.y, terminal.scrollLast - lines, lines); + } + else { + terminal.shiftLines(terminal.y + terminal.lastRowToDisplayMax - Terminal.HEIGHT, Terminal.HEIGHT * terminal.SCROLL_BACK_COUNT - 2, lines); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/SGR.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/SGR.java new file mode 100644 index 00000000..afb60cc5 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/SGR.java @@ -0,0 +1,82 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class SGR extends CSISequenceHandler { + public SGR(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + for (int i = 0; i < argCount; i++) { + int v1 = args[i]; + if (v1 == 38 || v1 == 48) { + int v2 = args[++i]; + if (v1 == 38) { + if (v2 == 5) { + terminal.currentForegroundColorMode = Terminal.ColorMode.TWO_FIFTY_SIX_COLOR; + terminal.twoFiftySixColor.R = args[++i]; + } else if (v2 == 2) { + terminal.currentForegroundColorMode = Terminal.ColorMode.TRUE_COLOR; + terminal.foregroundColor = new Terminal.ColorData(args[++i], args[++i], args[++i], Terminal.ColorMode.TRUE_COLOR); + } + } else { + if (v2 == 5) { + terminal.currentBackgroundColorMode = Terminal.ColorMode.TWO_FIFTY_SIX_COLOR; + terminal.twoFiftySixColor.G = args[++i]; + } else if (v2 == 2) { + terminal.currentBackgroundColorMode = Terminal.ColorMode.TRUE_COLOR; + terminal.backgroundColor = new Terminal.ColorData(args[++i], args[++i], args[++i], Terminal.ColorMode.TRUE_COLOR); + } + } + return; + } + + selectStyle(terminal, v1); + } + } + + private static void selectStyle(Terminal terminal, int arg) { + switch (arg) { + case 0 -> { // Reset / Normal + terminal.sixteenColor = Terminal.DEFAULT_COLORS.Copy(); + terminal.style = Terminal.DEFAULT_STYLE; + terminal.currentForegroundColorMode = Terminal.ColorMode.SIXTEEN_COLOR; + terminal.currentBackgroundColorMode = Terminal.ColorMode.SIXTEEN_COLOR; + terminal.twoFiftySixColor = Terminal.DEFAULT_256_COLORS.Copy(); + terminal.foregroundColor = Terminal.DEFAULT_TRUE_COLOR_FOREGROUND.Copy(); + terminal.backgroundColor = Terminal.DEFAULT_TRUE_COLOR_BACKGROUND.Copy(); + } + case 1 -> // Bold or increased intensity + terminal.style |= Terminal.STYLE_BOLD_MASK; + case 2 -> // Faint or decreased intensity + terminal.style |= Terminal.STYLE_DIM_MASK; + case 4 -> // Underscore + terminal.style |= Terminal.STYLE_UNDERLINE_MASK; + case 5 -> // Blink + terminal.style |= Terminal.STYLE_BLINK_MASK; + case 7 -> // Negative (reverse) image + terminal.style |= Terminal.STYLE_INVERT_MASK; + case 8 -> // Conceal aka Hide + terminal.style |= Terminal.STYLE_HIDDEN_MASK; + case 22 -> // Normal color or intensity + terminal.style &= ~(Terminal.STYLE_BOLD_MASK | Terminal.STYLE_DIM_MASK); + case 24 -> // Underline off + terminal.style &= ~Terminal.STYLE_UNDERLINE_MASK; + case 25 -> // Blink off + terminal.style &= ~Terminal.STYLE_BLINK_MASK; + case 27 -> // Reverse/invert off + terminal.style &= ~Terminal.STYLE_INVERT_MASK; + case 28 -> // Reveal conceal off + terminal.style &= ~Terminal.STYLE_HIDDEN_MASK; + case 30, 31, 32, 33, 34, 35, 36, 37 -> { // Set foreground color + terminal.currentForegroundColorMode = Terminal.ColorMode.SIXTEEN_COLOR; + terminal.sixteenColor.R = arg - 30; + } + case 40, 41, 42, 43, 44, 45, 46, 47 -> { //–47 Set background color + terminal.currentBackgroundColorMode = Terminal.ColorMode.SIXTEEN_COLOR; + terminal.sixteenColor.G = arg - 40; + } + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/TBC.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/TBC.java new file mode 100644 index 00000000..250802ef --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/TBC.java @@ -0,0 +1,23 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +import java.util.Arrays; + +public class TBC extends CSISequenceHandler { + public TBC(final Terminal terminal) { + super(terminal); + } + + public void execute(int[] args, int argCount, CSIState state) { + switch (args[0]) { + case 0 -> { // Clear tab at current column + if (terminal.x >= 0 && terminal.x < Terminal.WIDTH) { + terminal.tabs[terminal.x] = false; + } + } + case 3 -> // Clear all tabs + Arrays.fill(terminal.tabs, false); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/VPA.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/VPA.java new file mode 100644 index 00000000..cd285934 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/csi/VPA.java @@ -0,0 +1,13 @@ +package li.cil.oc2.common.vm.terminal.escapes.csi; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class VPA extends CSISequenceHandler { + public VPA(final Terminal terminal) { + super(terminal); + } + + public void execute(final int[] args, final int argsCount, final CSIState state) { + terminal.setClampedCursorPos(terminal.x, args[0] - 1); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/dcs/DCSManager.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/dcs/DCSManager.java new file mode 100644 index 00000000..a40c7cdf --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/dcs/DCSManager.java @@ -0,0 +1,24 @@ +package li.cil.oc2.common.vm.terminal.escapes.dcs; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class DCSManager { + private final Terminal terminal; + private int lastChar = '\0'; + + public DCSManager(Terminal terminal) { + this.terminal = terminal; + } + + public void handle(int ch) { + if ((lastChar == '\033' && ch == '\\')) { + terminal.state = Terminal.State.NORMAL; + } else { + lastChar = ch; + } + } + + public void reset() { + lastChar = '\0'; + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/escapes/osc/OSCManager.java b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/osc/OSCManager.java new file mode 100644 index 00000000..bd44544e --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/escapes/osc/OSCManager.java @@ -0,0 +1,24 @@ +package li.cil.oc2.common.vm.terminal.escapes.osc; + +import li.cil.oc2.common.vm.terminal.Terminal; + +public class OSCManager { + private final Terminal terminal; + private int lastChar = '\0'; + + public OSCManager(Terminal terminal) { + this.terminal = terminal; + } + + public void handle(int ch) { + if ((lastChar == '\033' && ch == '\\') || ch == '\007') { + terminal.state = Terminal.State.NORMAL; + } else { + lastChar = ch; + } + } + + public void reset() { + lastChar = '\0'; + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/fonts/FontAtlas.java b/src/main/java/li/cil/oc2/common/vm/terminal/fonts/FontAtlas.java new file mode 100644 index 00000000..e0418a97 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/fonts/FontAtlas.java @@ -0,0 +1,127 @@ +package li.cil.oc2.common.vm.terminal.fonts; + +import com.mojang.blaze3d.platform.NativeImage; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; + +@OnlyIn(Dist.CLIENT) +public class FontAtlas { + private final static int PADDING = 2; // Padding between glyphs + + private final ResourceLocation resources; + private int atlasWidth; + private int atlasHeight; + public NativeImage atlasImage; // The current texture + private final DynamicTexture dynamicTexture; + private final List glyphs; + + private int currentX = 0; // X coordinate to place next glyph + private int currentY = 0; // Y coordinate to place next glyph + + public FontAtlas(int initialWidth, int initialHeight) { + this.atlasWidth = initialWidth; + this.atlasHeight = initialHeight; + this.atlasImage = new NativeImage(atlasWidth, atlasHeight, false); + this.dynamicTexture = new DynamicTexture(atlasImage); + this.resources = ResourceLocation.fromNamespaceAndPath("oc2r", "terminus_font_atlas"); + Minecraft.getInstance().getTextureManager().register(resources, dynamicTexture); + this.glyphs = new ArrayList<>(); + + for (int x = 0; x < atlasWidth; x++) { + for (int y = 0; y < atlasHeight; y++) { + this.atlasImage.setPixelRGBA(x, y, new Color(0, 0, 0, 0).getRGB()); + } + } + + BufferedImage f = new BufferedImage(16, 32, BufferedImage.TYPE_INT_ARGB); + + Graphics2D g = f.createGraphics(); + g.setColor(Color.WHITE); + g.draw(new Rectangle(0, 0, 16, 32)); + + g.dispose(); + + Glyph square = new Glyph(f, 16, 32, 0); + + addGlyph(square); + + glyphs.add(square); + } + + // Method to add a glyph to the atlas, resizing it if needed + public void addGlyph(Glyph glyph) { + if (currentX + glyph.image.getWidth() > atlasWidth) { + currentX = 0; + currentY += glyph.image.getHeight() + PADDING; + } + + // Check if there's enough space in the current atlas + if (currentY + glyph.image.getHeight() > atlasHeight) { + resizeAtlas(); // Resize the atlas if there isn't enough space + } + + // Copy the glyph into the atlas at the correct position + for (int y = 0; y < glyph.image.getHeight(); y++) { + for (int x = 0; x < glyph.image.getWidth(); x++) { + int color = glyph.image.getRGB(x, y); + atlasImage.setPixelRGBA(currentX + x, currentY + y, color); + } + } + + // Calculate the UV coordinates for this glyph + float uStart = (float) currentX * (1f / atlasWidth); + float vStart = (float) currentY * (1f / atlasHeight); + float uEnd = (float) (currentX + glyph.image.getWidth() + 1) * (1f / atlasWidth); + float vEnd = (float) (currentY + glyph.image.getHeight() + 1) * (1f / atlasHeight); + + glyph.setUV(uStart, vStart, uEnd, vEnd); + + glyphs.add(glyph); + + // Update the position for the next glyph + currentX += glyph.image.getWidth() + PADDING; + updateTexture(); + } + + private void resizeAtlas() { + System.out.println("resizing atlas at " + atlasWidth + "x" + atlasHeight); + int newWidth = atlasWidth * 2; + int newHeight = atlasHeight * 2; + + NativeImage newAtlasImage = new NativeImage(newWidth, newHeight, false); + + for (int y = 0; y < atlasHeight; y++) { + for (int x = 0; x < atlasWidth; x++) { + int color = atlasImage.getPixelRGBA(x, y); + newAtlasImage.setPixelRGBA(x, y, color); + } + } + + for (Glyph glyph : glyphs) { + glyph.setUV(glyph.uStart/2f, glyph.vStart/2f, glyph.uEnd/2f, glyph.vEnd/2f); + } + + this.atlasWidth = newWidth; + this.atlasHeight = newHeight; + this.atlasImage = newAtlasImage; + + this.dynamicTexture.setPixels(atlasImage); + updateTexture(); + } + + public ResourceLocation getTextureId() { + return this.resources; + } + + public void updateTexture() { + dynamicTexture.upload(); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/fonts/FontHandling.java b/src/main/java/li/cil/oc2/common/vm/terminal/fonts/FontHandling.java new file mode 100644 index 00000000..19ec7dd0 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/fonts/FontHandling.java @@ -0,0 +1,33 @@ +package li.cil.oc2.common.vm.terminal.fonts; + +import li.cil.oc2.common.Main; +import net.minecraft.resources.ResourceLocation; + +import java.awt.*; +import java.io.IOException; +import java.io.InputStream; + +public class FontHandling { + public static final Font TerminusFont = loadFont("/assets/oc2r/fonts/terminus.ttf", 32f); + public static final UnicodeFontRenderer unicodeFontRenderer = new UnicodeFontRenderer(TerminusFont); + + public static Glyph getGlyph(int character) { + return unicodeFontRenderer.getGlyph(character); + } + + public static ResourceLocation getAtlas() { + return unicodeFontRenderer.TerminusFontAtlas.getTextureId(); + } + + public static Font loadFont(String path, float size) { + try (InputStream is = Main.class.getResourceAsStream(path)) { + if (is == null) { + return new Font("Arial", Font.PLAIN, (int) size); + } + return Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(size); + } catch (FontFormatException | IOException e) { + e.printStackTrace(); + return new Font("Arial", Font.PLAIN, (int) size); // fallback + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/fonts/Glyph.java b/src/main/java/li/cil/oc2/common/vm/terminal/fonts/Glyph.java new file mode 100644 index 00000000..cf154987 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/fonts/Glyph.java @@ -0,0 +1,24 @@ +package li.cil.oc2.common.vm.terminal.fonts; + +import java.awt.image.BufferedImage; + +public class Glyph { + public final BufferedImage image; + public final int width, height; + public final int advance; + public float uStart = 0, vStart = 0, uEnd = 0, vEnd = 0; + + public Glyph(BufferedImage image, int width, int height, int advance) { + this.image = image; + this.width = width; + this.height = height; + this.advance = advance; + } + + public void setUV(float u, float v, float u2, float v2) { + uStart = u; + vStart = v; + uEnd = u2; + vEnd = v2; + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/fonts/UnicodeFontRenderer.java b/src/main/java/li/cil/oc2/common/vm/terminal/fonts/UnicodeFontRenderer.java new file mode 100644 index 00000000..7cef00c9 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/fonts/UnicodeFontRenderer.java @@ -0,0 +1,50 @@ +package li.cil.oc2.common.vm.terminal.fonts; + +import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.image.BufferedImage; +import java.util.HashMap; +import java.util.Map; + +public class UnicodeFontRenderer { + public final Font font; + public final FontAtlas TerminusFontAtlas = new FontAtlas(512, 512); + private final Map glyphCache = new HashMap<>(); + private final FontRenderContext frc = new FontRenderContext(null, false, false); + + public UnicodeFontRenderer(Font font) { + this.font = font; + + String initialSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!@#$%^&*()_+-=_.,:;<>?;':\"\\|`~[]{}1234567890△▽ "; + int[] characters = initialSet.codePoints().toArray(); + for (final int character : characters) { + getGlyph(character); + } + } + + public Glyph getGlyph(int character) { + return glyphCache.computeIfAbsent(character, this::rasterizeGlyph); + } + + private Glyph rasterizeGlyph(int character) { + GlyphVector gv = font.createGlyphVector(frc, Character.toChars(character)); + BufferedImage img = new BufferedImage(16, 32, BufferedImage.TYPE_INT_ARGB); // size can be dynamic + Graphics2D g = img.createGraphics(); + + g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + g.setFont(font); + g.setColor(Color.WHITE); + + FontMetrics metrics = g.getFontMetrics(); + int ascent = metrics.getAscent(); + + g.drawGlyphVector(gv, 0, ascent); + g.dispose(); + + Glyph glyph = new Glyph(img, 16, 32, (int) gv.getGlyphMetrics(0).getAdvance()); + + TerminusFontAtlas.addGlyph(glyph); + return glyph; + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/modes/ImplementedPrivateModes.java b/src/main/java/li/cil/oc2/common/vm/terminal/modes/ImplementedPrivateModes.java new file mode 100644 index 00000000..873b330b --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/modes/ImplementedPrivateModes.java @@ -0,0 +1,91 @@ +package li.cil.oc2.common.vm.terminal.modes; + +import java.util.HashMap; + +public class ImplementedPrivateModes { + public static HashMap modeStatus = new HashMap<>(); + + public static ImplementedPrivateModes instance = new ImplementedPrivateModes(); + + public ImplementedPrivateModes() { + modeStatus.put(1, true); // DECCKM; + modeStatus.put(2, false); // DECANM; + modeStatus.put(3, false); // DECCOLM; + modeStatus.put(4, true); // DECSCLM; + modeStatus.put(5, false); // DECSCNM; + modeStatus.put(6, true); // DECOM; + modeStatus.put(7, true); // DECAWM; + modeStatus.put(8, true); // DECARM; + modeStatus.put(9, false); // X10MM; + modeStatus.put(10, false); // TOOLBAR; + modeStatus.put(12, true); // START_BLINKING_CURSOR; + modeStatus.put(13, true); // START_BLINKING_CURSOR2; + modeStatus.put(14, false); // XORBLINK; + modeStatus.put(18, false); // DECPFF; + modeStatus.put(19, false); // DECPEX; + modeStatus.put(25, true); // DECTCEM; + modeStatus.put(30, false); // SHOW_SCROLL; + modeStatus.put(35, false); // FONT_SHIFT; + modeStatus.put(38, false); // TEKTRONIX; + modeStatus.put(40, false); // ENABLE_80_132; + modeStatus.put(41, false); // MORE_FIX; + modeStatus.put(42, false); // DECNRCM; + modeStatus.put(43, false); // DECGEPM; + modeStatus.put(44, false); // MARG_BELL; + modeStatus.put(45, false); // XTREVWRAP; + modeStatus.put(46, false); // XTLOGGING; + modeStatus.put(47, true); // ALT_BUFFER; + modeStatus.put(66, false); // DECNKM; + modeStatus.put(67, false); // DECBKM; + modeStatus.put(69, false); // DECLRMM; + modeStatus.put(80, false); // DECSDM; + modeStatus.put(96, false); // DECNCSM; + modeStatus.put(1000, true); // X11MM; + modeStatus.put(1001, false); // HILITE_MOUSE; + modeStatus.put(1002, true); // CELL_MOTION_MOUSE; -- PARTIAL SUPPORT: Treated as X11MM currently, no motion events are sent. This actually seems to match Window Terminal's level of implementation. + modeStatus.put(1003, false); // ALL_MOTION_MOUSE_TRACKING; + modeStatus.put(1004, true); // FOCUS_IN_FOCUS_OUT; + modeStatus.put(1005, true); // UTF8_MOUSE; + modeStatus.put(1006, true); // SGR_MOUSE; + modeStatus.put(1007, false); // ALTERNATE_SCROLL_MODE; + modeStatus.put(1010, false); // SCROLL_BOTTOM_ON_OUTPUT; + modeStatus.put(1011, false); // SCROLL_BOTTOM_ON_KEY_PRESS; + modeStatus.put(1014, false); // FAST_SCROLL; + modeStatus.put(1015, true); // URXVT_MOUSE; + modeStatus.put(1016, false); // SGR_MOUSE_PIXEL; + modeStatus.put(1034, false); // META_KEY; + modeStatus.put(1035, false); // SPECIAL_MODIFIERS; + modeStatus.put(1036, false); // META_SENDS_ESCAPE; + modeStatus.put(1037, false); // DEL_EDIT_KEYPAD_DEL; + modeStatus.put(1039, false); // ALT_SENDS_ESC; + modeStatus.put(1040, false); // KEEP_SELECTION; + modeStatus.put(1041, false); // USE_CLIP; + modeStatus.put(1042, false); // ENABLE_URGENCY; + modeStatus.put(1043, false); // RAISE_ON_CTRL_G; + modeStatus.put(1044, false); // KEEP_CLIP; + modeStatus.put(1045, false); // EXT_REV_WRAP; + modeStatus.put(1046, false); // ALLOW_ALT_BUFFER; + modeStatus.put(1047, true); // SWITCH_ALT_BUFFER; + modeStatus.put(1048, true); // SAVE_CURSOR; + modeStatus.put(1049, true); // SAVE_CLEAR_AND_SWITCH; + modeStatus.put(1050, false); // SET_TERMINFO_FUNC_KEY_MODE; + modeStatus.put(1051, false); // SET_SUN_KEY_MODE; + modeStatus.put(1052, false); // SET_HP_K0EY_MODE; + modeStatus.put(1053, false); // SET_SCO_KEY_MODE; + modeStatus.put(1060, false); // SET_LEGACY_KEYBOARD; + modeStatus.put(1061, false); // SET_VT220_KEYBOARD; + modeStatus.put(2001, false); // ENABLE_READLINE_MOUSE_1; + modeStatus.put(2002, false); // ENABLE_READLINE_MOUSE_2; + modeStatus.put(2003, false); // ENABLE_READLINE_MOUSE_3; + modeStatus.put(2004, true); // SET_BRACKETED_PASTE; + modeStatus.put(2005, false); // ENABLE_READLINE_CHAR_QUOTE; + modeStatus.put(2006, false); // ENABLE_READLINE_NEWLINE_PASTE; + modeStatus.put(2026, true); // APPLICATION_SYNC; + } + + public void modeUsed(int mode, boolean state) { + if (!modeStatus.get(mode)) { + System.out.println("Unimplemented Mode: " + mode + " was " + (state ? "set." : "reset.")); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/modes/Mode.java b/src/main/java/li/cil/oc2/common/vm/terminal/modes/Mode.java new file mode 100644 index 00000000..b82b84d4 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/modes/Mode.java @@ -0,0 +1,9 @@ +package li.cil.oc2.common.vm.terminal.modes; + +@SuppressWarnings("unused") +public final class Mode { + public static final int KAM = 2; + public static final int IRM = 4; + public static final int SRM = 12; + public static final int LNM = 20; +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/modes/ModeState.java b/src/main/java/li/cil/oc2/common/vm/terminal/modes/ModeState.java new file mode 100644 index 00000000..bd935fa2 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/modes/ModeState.java @@ -0,0 +1,21 @@ +package li.cil.oc2.common.vm.terminal.modes; + +import li.cil.ceres.api.Serialized; + +@Serialized +public class ModeState { + public boolean KAM = false; + public boolean IRM = false; + public boolean SRM = false; + public boolean LNM = false; + + public boolean getMode(int mode) { + return switch (mode) { + case 2 -> KAM; + case 4 -> IRM; + case 12 -> SRM; + case 20 -> LNM; + default -> throw new IndexOutOfBoundsException(); + }; + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/modes/MouseMode.java b/src/main/java/li/cil/oc2/common/vm/terminal/modes/MouseMode.java new file mode 100644 index 00000000..9807e0e1 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/modes/MouseMode.java @@ -0,0 +1,23 @@ +package li.cil.oc2.common.vm.terminal.modes; + +public class MouseMode { + public int PrimaryMode; + public int[] SecondaryModes; + + public MouseMode(int primaryMode, int[] secondaryModes) { + PrimaryMode = primaryMode; + SecondaryModes = secondaryModes; + } + + public boolean isSecondaryModeEnabled(int mode) { + for (int secondaryMode : SecondaryModes) { + if (secondaryMode == mode) return true; + } + + return false; + } + + public boolean isMouseDisabled() { + return PrimaryMode == 0; + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/modes/PrivateMode.java b/src/main/java/li/cil/oc2/common/vm/terminal/modes/PrivateMode.java new file mode 100644 index 00000000..8fc17414 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/modes/PrivateMode.java @@ -0,0 +1,78 @@ +package li.cil.oc2.common.vm.terminal.modes; + +@SuppressWarnings("unused") +public final class PrivateMode { + public static final int DECCKM = 1; // Cursor key + public static final int DECANM = 2; // ANSI/VT52 + public static final int DECCOLM = 3; // Column + public static final int DECSCLM = 4; // Scrolling + public static final int DECSCNM = 5; // Screen + public static final int DECOM = 6; // Origin + public static final int DECAWM = 7; // Auto wrap + public static final int DECARM = 8; // Auto-repeating + public static final int X10MM = 9; // X10 Mouse Cursor + public static final int TOOLBAR = 10; // Toolbar + public static final int START_BLINKING_CURSOR = 12; // SBC + public static final int START_BLINKING_CURSOR2 = 13; // SBC2 + public static final int XORBLINK = 14; // XOR of blinking cursor control sequence + public static final int DECPFF = 18; // Print Form Feed + public static final int DECPEX = 19; // Set print extent to full screen + public static final int DECTCEM = 25; // Show Cursor + public static final int SHOW_SCROLL = 30; // Show Scrollbar + public static final int FONT_SHIFT = 35; // Enable font-shifting + public static final int TEKTRONIX = 38; // Enable Tektronix + public static final int ENABLE_80_132 = 40; // Allow 80 -> 132 mode + public static final int MORE_FIX = 41; // More(1) fix + public static final int DECNRCM = 42; // Enable National Replacement Character sets + public static final int DECGEPM = 43; // Enable Graphic Print Color Mode + public static final int MARG_BELL = 44; // Enable margin bell + public static final int XTREVWRAP = 45; // Enable reverse wrap around + public static final int XTLOGGING = 46; // Enable logging + public static final int ALT_BUFFER = 47; // Use alternate screen buffer + public static final int DECNKM = 66; // Application keypad mode + public static final int DECBKM = 67; // Backarrow key sends backspace + public static final int DECLRMM = 69; // Enable left and right margin mode + public static final int DECSDM = 80; // Enable Sixel Display Mode + public static final int DECNCSM = 96; // Do not clear on DECCOLM set/reset + public static final int X11MM = 1000; // X11 Mouse Mode + public static final int HILITE_MOUSE = 1001; // Hilite Mouse Mode + public static final int CELL_MOTION_MOUSE = 1002; // Cell Motion Mouse Mode + public static final int ALL_MOTION_MOUSE_TRACKING = 1003; // All Motion Mouse Tracking Mode + public static final int FOCUS_IN_FOCUS_OUT = 1004; // Focus In/Out events + public static final int UTF8_MOUSE = 1005; // UTF-8 Mouse Mode + public static final int SGR_MOUSE = 1006; // SGR Mouse Mode + public static final int ALTERNATE_SCROLL_MODE = 1007; + public static final int SCROLL_BOTTOM_ON_OUTPUT = 1010; // Scroll to bottom on output + public static final int SCROLL_BOTTOM_ON_KEY_PRESS = 1011; // Scroll to bottom when key pressed + public static final int FAST_SCROLL = 1014; // Fast scroll + public static final int URXVT_MOUSE = 1015; + public static final int SGR_MOUSE_PIXEL = 1016; + public static final int META_KEY = 1034; // Interpret "meta" key (Zero Affect in our implementation as this would typically mess with the 8th bit of input in a 7bit setup, but we always send 8) + public static final int SPECIAL_MODIFIERS = 1035; // Enable special alt and numlock modifiers + public static final int META_SENDS_ESCAPE = 1036; // Meta sends ESC when pressed + public static final int DEL_EDIT_KEYPAD_DEL = 1037; // Send DEL from editing-keypad DEL key + public static final int ALT_SENDS_ESC = 1039; // Alt sends ESC when pressed + public static final int KEEP_SELECTION = 1040; // Keeps selection even if not highlighted + public static final int USE_CLIP = 1041; // Use Clipboard selection + public static final int ENABLE_URGENCY = 1042; // Bell will be urgent on CTRL-G + public static final int RAISE_ON_CTRL_G = 1043; // NO FUNCTION + public static final int KEEP_CLIP = 1044; // Keep most recent clipboard + public static final int EXT_REV_WRAP = 1045; // Extended reverse wrap mode + public static final int ALLOW_ALT_BUFFER = 1046; // Enable to and from alt buffer + public static final int SWITCH_ALT_BUFFER = 1047; // Switch to alt buffer + public static final int SAVE_CURSOR = 1048; // Save cursor as in DECSC + public static final int SAVE_CLEAR_AND_SWITCH = 1049; // Combines 1047 and 1048 + public static final int SET_TERMINFO_FUNC_KEY_MODE = 1050; // Set terminfo/termcap function-key mode + public static final int SET_SUN_KEY_MODE = 1051; // Set Sun key mode + public static final int SET_HP_K0EY_MODE = 1052; // Set HP function-key mode + public static final int SET_SCO_KEY_MODE = 1053; // Set SCO key mode + public static final int SET_LEGACY_KEYBOARD = 1060; // Emulate legacy keyboard + public static final int SET_VT220_KEYBOARD = 1061; // Emulate VT220 keyboard + public static final int ENABLE_READLINE_MOUSE_1 = 2001; // Readline mouse button-1 + public static final int ENABLE_READLINE_MOUSE_2 = 2002; // Readline mouse button-2 + public static final int ENABLE_READLINE_MOUSE_3 = 2003; // Readline mouse button-3 + public static final int SET_BRACKETED_PASTE = 2004; // Set bracketed paste mode + public static final int ENABLE_READLINE_CHAR_QUOTE = 2005; // Enable readline character quoting + public static final int ENABLE_READLINE_NEWLINE_PASTE = 2006; // Enable readline newline pasting + public static final int APPLICATION_SYNC = 2026; // Wait to render until application is ready +} diff --git a/src/main/java/li/cil/oc2/common/vm/terminal/modes/PrivateModeState.java b/src/main/java/li/cil/oc2/common/vm/terminal/modes/PrivateModeState.java new file mode 100644 index 00000000..d66bd0cb --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/terminal/modes/PrivateModeState.java @@ -0,0 +1,182 @@ +package li.cil.oc2.common.vm.terminal.modes; + +import li.cil.ceres.api.Serialized; + +import java.util.ArrayList; +import java.util.List; + +@Serialized +public class PrivateModeState { + public boolean DECCKM = false; + public boolean DECANM = false; + public boolean DECCOLM = false; + public boolean DECSCLM = false; + public boolean DECSCNM = false; + public boolean DECOM = false; + public boolean DECAWM = true; + public boolean DECARM = true; + public boolean X10MM = false; + public boolean TOOLBAR = false; + public boolean START_BLINKING_CURSOR = false; + public boolean START_BLINKING_CURSOR2 = false; + public boolean XORBLINK = false; + public boolean DECPFF = false; + public boolean DECPEX = false; + public boolean DECTCEM = true; + public boolean SHOW_SCROLL = false; + public boolean FONT_SHIFT = false; + public boolean TEKTRONIX = false; + public boolean ENABLE_80_132 = false; + public boolean MORE_FIX = false; + public boolean DECNRCM = false; + public boolean DECGEPM = false; + public boolean MARG_BELL = false; + public boolean XTREVWRAP = false; + public boolean XTLOGGING = false; + public boolean ALT_BUFFER = false; + public boolean DECNKM = false; + public boolean DECBKM = false; + public boolean DECLRMM = false; + public boolean DECSDM = false; + public boolean DECNCSM = false; + public boolean X11MM = false; + public boolean HILITE_MOUSE = false; + public boolean CELL_MOTION_MOUSE = false; + public boolean ALL_MOTION_MOUSE_TRACKING = false; + public boolean FOCUS_IN_FOCUS_OUT = false; + public boolean UTF8_MOUSE = false; + public boolean SGR_MOUSE = false; + public boolean ALTERNATE_SCROLL_MODE = false; + public boolean SCROLL_BOTTOM_ON_OUTPUT = false; + public boolean SCROLL_BOTTOM_ON_KEY_PRESS = false; + public boolean FAST_SCROLL = false; + public boolean URXVT_MOUSE = false; + public boolean SGR_MOUSE_PIXEL = false; + public boolean META_KEY = false; + public boolean SPECIAL_MODIFIERS = false; + public boolean META_SENDS_ESCAPE = false; + public boolean DEL_EDIT_KEYPAD_DEL = false; + public boolean ALT_SENDS_ESC = false; + public boolean KEEP_SELECTION = false; + public boolean USE_CLIP = false; + public boolean ENABLE_URGENCY = false; + public boolean RAISE_ON_CTRL_G = false; + public boolean KEEP_CLIP = false; + public boolean EXT_REV_WRAP = false; + public boolean ALLOW_ALT_BUFFER = false; + public boolean SWITCH_ALT_BUFFER = false; + public boolean SAVE_CURSOR = false; + public boolean SAVE_CLEAR_AND_SWITCH = false; + public boolean SET_TERMINFO_FUNC_KEY_MODE = false; + public boolean SET_SUN_KEY_MODE = false; + public boolean SET_HP_K0EY_MODE = false; + public boolean SET_SCO_KEY_MODE = false; + public boolean SET_LEGACY_KEYBOARD = false; + public boolean SET_VT220_KEYBOARD = false; + public boolean ENABLE_READLINE_MOUSE_1 = false; + public boolean ENABLE_READLINE_MOUSE_2 = false; + public boolean ENABLE_READLINE_MOUSE_3 = false; + public boolean SET_BRACKETED_PASTE = false; + public boolean ENABLE_READLINE_CHAR_QUOTE = false; + public boolean ENABLE_READLINE_NEWLINE_PASTE = false; + public boolean APPLICATION_SYNC = false; + + public boolean getMode(int mode) { + return switch (mode) { + case 1 -> DECCKM; + case 2 -> DECANM; + case 3 -> DECCOLM; + case 4 -> DECSCLM; + case 5 -> DECSCNM; + case 6 -> DECOM; + case 7 -> DECAWM; + case 8 -> DECARM; + case 9 -> X10MM; + case 10 -> TOOLBAR; + case 12 -> START_BLINKING_CURSOR; + case 13 -> START_BLINKING_CURSOR2; + case 14 -> XORBLINK; + case 18 -> DECPFF; + case 19 -> DECPEX; + case 25 -> DECTCEM; + case 30 -> SHOW_SCROLL; + case 35 -> FONT_SHIFT; + case 38 -> TEKTRONIX; + case 40 -> ENABLE_80_132; + case 41 -> MORE_FIX; + case 42 -> DECNRCM; + case 43 -> DECGEPM; + case 44 -> MARG_BELL; + case 45 -> XTREVWRAP; + case 46 -> XTLOGGING; + case 47 -> ALT_BUFFER; + case 66 -> DECNKM; + case 67 -> DECBKM; + case 69 -> DECLRMM; + case 80 -> DECSDM; + case 96 -> DECNCSM; + case 1000 -> X11MM; + case 1001 -> HILITE_MOUSE; + case 1002 -> CELL_MOTION_MOUSE; + case 1003 -> ALL_MOTION_MOUSE_TRACKING; + case 1004 -> FOCUS_IN_FOCUS_OUT; + case 1005 -> UTF8_MOUSE; + case 1006 -> SGR_MOUSE; + case 1007 -> ALTERNATE_SCROLL_MODE; + case 1010 -> SCROLL_BOTTOM_ON_OUTPUT; + case 1011 -> SCROLL_BOTTOM_ON_KEY_PRESS; + case 1014 -> FAST_SCROLL; + case 1015 -> URXVT_MOUSE; + case 1016 -> SGR_MOUSE_PIXEL; + case 1034 -> META_KEY; + case 1035 -> SPECIAL_MODIFIERS; + case 1036 -> META_SENDS_ESCAPE; + case 1037 -> DEL_EDIT_KEYPAD_DEL; + case 1039 -> ALT_SENDS_ESC; + case 1040 -> KEEP_SELECTION; + case 1041 -> USE_CLIP; + case 1042 -> ENABLE_URGENCY; + case 1043 -> RAISE_ON_CTRL_G; + case 1044 -> KEEP_CLIP; + case 1045 -> EXT_REV_WRAP; + case 1046 -> ALLOW_ALT_BUFFER; + case 1047 -> SWITCH_ALT_BUFFER; + case 1048 -> SAVE_CURSOR; + case 1049 -> SAVE_CLEAR_AND_SWITCH; + case 1050 -> SET_TERMINFO_FUNC_KEY_MODE; + case 1051 -> SET_SUN_KEY_MODE; + case 1052 -> SET_HP_K0EY_MODE; + case 1053 -> SET_SCO_KEY_MODE; + case 1060 -> SET_LEGACY_KEYBOARD; + case 1061 -> SET_VT220_KEYBOARD; + case 2001 -> ENABLE_READLINE_MOUSE_1; + case 2002 -> ENABLE_READLINE_MOUSE_2; + case 2003 -> ENABLE_READLINE_MOUSE_3; + case 2004 -> SET_BRACKETED_PASTE; + case 2005 -> ENABLE_READLINE_CHAR_QUOTE; + case 2006 -> ENABLE_READLINE_NEWLINE_PASTE; + case 2026 -> APPLICATION_SYNC; + default -> throw new IndexOutOfBoundsException(); + }; + } + + public MouseMode getMouseMode() { + int mode; + List secondaryModes = new ArrayList<>(); + if (X10MM) mode = 9; + else if (X11MM) mode = 1000; + else if (CELL_MOTION_MOUSE) mode = 1002; + else if (ALL_MOTION_MOUSE_TRACKING) mode = 1003; + else mode = 0; + if (UTF8_MOUSE) secondaryModes.add(1005); + if (SGR_MOUSE) secondaryModes.add(1006); + if (URXVT_MOUSE) secondaryModes.add(1015); + if (SGR_MOUSE_PIXEL) secondaryModes.add(1016); + + return new MouseMode(mode, secondaryModes.stream().mapToInt(Integer::intValue).toArray()); + } + + public boolean isAltBufferEnabled() { + return ALT_BUFFER || SWITCH_ALT_BUFFER || SAVE_CLEAR_AND_SWITCH; + } +} diff --git a/src/main/java/li/cil/oc2/data/ModBlockStateProvider.java b/src/main/java/li/cil/oc2/data/ModBlockStateProvider.java index 5a6399c5..3933d01c 100644 --- a/src/main/java/li/cil/oc2/data/ModBlockStateProvider.java +++ b/src/main/java/li/cil/oc2/data/ModBlockStateProvider.java @@ -16,21 +16,22 @@ import net.minecraftforge.client.model.generators.*; import net.minecraftforge.common.data.ExistingFileHelper; import net.minecraftforge.registries.RegistryObject; +@SuppressWarnings({"UnusedReturnValue", "SameParameterValue"}) public final class ModBlockStateProvider extends BlockStateProvider { - private static final ResourceLocation CABLE_MODEL = new ResourceLocation(API.MOD_ID, "block/cable_base"); - private static final ResourceLocation CABLE_LINK_MODEL = new ResourceLocation(API.MOD_ID, "block/cable_link"); - private static final ResourceLocation CABLE_PLUG_MODEL = new ResourceLocation(API.MOD_ID, "block/cable_plug"); - private static final ResourceLocation CABLE_STRAIGHT_MODEL = new ResourceLocation(API.MOD_ID, "block/cable_straight"); - private static final ResourceLocation CHARGER_MODEL = new ResourceLocation(API.MOD_ID, "block/charger"); - private static final ResourceLocation COMPUTER_MODEL = new ResourceLocation(API.MOD_ID, "block/computer"); - private static final ResourceLocation MONITOR_MODEL = new ResourceLocation(API.MOD_ID, "block/monitor"); - private static final ResourceLocation DISK_DRIVE_MODEL = new ResourceLocation(API.MOD_ID, "block/disk_drive"); - private static final ResourceLocation KEYBOARD_MODEL = new ResourceLocation(API.MOD_ID, "block/keyboard"); - private static final ResourceLocation NETWORK_CONNECTOR_MODEL = new ResourceLocation(API.MOD_ID, "block/network_connector"); - private static final ResourceLocation NETWORK_HUB_MODEL = new ResourceLocation(API.MOD_ID, "block/network_hub"); - private static final ResourceLocation PROJECTOR_MODEL = new ResourceLocation(API.MOD_ID, "block/projector"); - private static final ResourceLocation REDSTONE_INTERFACE_MODEL = new ResourceLocation(API.MOD_ID, "block/redstone_interface"); - //private static final ResourceLocation PCI_CARD_CAGE_MODEL = new ResourceLocation(API.MOD_ID, "block/pci_card_cage"); + private static final ResourceLocation CABLE_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/cable_base"); + private static final ResourceLocation CABLE_LINK_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/cable_link"); + private static final ResourceLocation CABLE_PLUG_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/cable_plug"); + private static final ResourceLocation CABLE_STRAIGHT_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/cable_straight"); + private static final ResourceLocation CHARGER_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/charger"); + private static final ResourceLocation COMPUTER_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/computer"); + private static final ResourceLocation MONITOR_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/monitor"); + private static final ResourceLocation DISK_DRIVE_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/disk_drive"); + private static final ResourceLocation KEYBOARD_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/keyboard"); + private static final ResourceLocation NETWORK_CONNECTOR_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/network_connector"); + private static final ResourceLocation NETWORK_HUB_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/network_hub"); + private static final ResourceLocation PROJECTOR_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/projector"); + private static final ResourceLocation REDSTONE_INTERFACE_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/redstone_interface"); + //private static final ResourceLocation PCI_CARD_CAGE_MODEL = ResourceLocation.fromNamespaceAndPath(API.MOD_ID, "block/pci_card_cage"); public ModBlockStateProvider(final PackOutput output, final ExistingFileHelper existingFileHelper) { diff --git a/src/main/java/li/cil/oc2/data/ModItemModelProvider.java b/src/main/java/li/cil/oc2/data/ModItemModelProvider.java index e4df3257..d06ba3ae 100644 --- a/src/main/java/li/cil/oc2/data/ModItemModelProvider.java +++ b/src/main/java/li/cil/oc2/data/ModItemModelProvider.java @@ -33,6 +33,7 @@ public final class ModItemModelProvider extends ItemModelProvider { simple(Items.CPU_TIER_2); simple(Items.CPU_TIER_3); simple(Items.CPU_TIER_4); + simple(Items.CPU_TIER_INF); simple(Items.SILICON); simple(Items.SILICON_BLEND); simple(Items.SILICON_WAFER); @@ -45,8 +46,6 @@ public final class ModItemModelProvider extends ItemModelProvider { .texture("layer1", "item/hard_drive_tint"); simple(Items.HARD_DRIVE_EXTRA_LARGE, "item/hard_drive_base") .texture("layer1", "item/hard_drive_tint"); - simple(Items.HARD_DRIVE_CUSTOM, "item/hard_drive_base") - .texture("layer1", "item/hard_drive_tint"); simple(Items.FLASH_MEMORY); simple(Items.FLASH_MEMORY_CUSTOM, "item/flash_memory"); simple(Items.FLOPPY, "item/floppy_base") @@ -77,8 +76,8 @@ public final class ModItemModelProvider extends ItemModelProvider { private ItemModelBuilder simple(final RegistryObject item, final String texturePath) { return singleTexture(item.getId().getPath(), - new ResourceLocation("item/generated"), + ResourceLocation.parse("item/generated"), "layer0", - new ResourceLocation(API.MOD_ID, texturePath)); + ResourceLocation.fromNamespaceAndPath(API.MOD_ID, texturePath)); } } diff --git a/src/main/java/li/cil/oc2/data/ModItemTagsProvider.java b/src/main/java/li/cil/oc2/data/ModItemTagsProvider.java index 63ad5fdf..9e055689 100644 --- a/src/main/java/li/cil/oc2/data/ModItemTagsProvider.java +++ b/src/main/java/li/cil/oc2/data/ModItemTagsProvider.java @@ -50,8 +50,7 @@ public final class ModItemTagsProvider extends ItemTagsProvider { Items.HARD_DRIVE_SMALL.get(), Items.HARD_DRIVE_MEDIUM.get(), Items.HARD_DRIVE_LARGE.get(), - Items.HARD_DRIVE_EXTRA_LARGE.get(), - Items.HARD_DRIVE_CUSTOM.get() + Items.HARD_DRIVE_EXTRA_LARGE.get() ); tag(DEVICES_FLASH_MEMORY).add( Items.FLASH_MEMORY.get(), @@ -88,11 +87,11 @@ public final class ModItemTagsProvider extends ItemTagsProvider { Items.HARD_DRIVE_MEDIUM.get(), Items.HARD_DRIVE_LARGE.get(), Items.HARD_DRIVE_EXTRA_LARGE.get(), - Items.HARD_DRIVE_CUSTOM.get(), Items.CPU_TIER_1.get(), Items.CPU_TIER_2.get(), Items.CPU_TIER_3.get(), Items.CPU_TIER_4.get(), + Items.CPU_TIER_INF.get(), Items.KEYBOARD.get(), Items.MEMORY_SMALL.get(), Items.MEMORY_MEDIUM.get(), @@ -108,7 +107,8 @@ public final class ModItemTagsProvider extends ItemTagsProvider { Items.CPU_TIER_1.get(), Items.CPU_TIER_2.get(), Items.CPU_TIER_3.get(), - Items.CPU_TIER_4.get() + Items.CPU_TIER_4.get(), + Items.CPU_TIER_INF.get() ); } } diff --git a/src/main/java/li/cil/oc2/data/ModRecipesProvider.java b/src/main/java/li/cil/oc2/data/ModRecipesProvider.java index 52aa4cd5..bb886728 100644 --- a/src/main/java/li/cil/oc2/data/ModRecipesProvider.java +++ b/src/main/java/li/cil/oc2/data/ModRecipesProvider.java @@ -280,13 +280,6 @@ public final class ModRecipesProvider extends RecipeProvider { .unlockedBy("has_robot", inventoryChange(Items.ROBOT.get())) .save(consumer); - WrenchRecipeBuilder - .wrenchRecipe(Items.HARD_DRIVE_CUSTOM.get()) - .requires(Items.HARD_DRIVE_LARGE.get()) - .unlockedBy("has_computer", inventoryChange(Items.COMPUTER.get())) - .unlockedBy("has_robot", inventoryChange(Items.ROBOT.get())) - .save(consumer); - ShapedRecipeBuilder .shaped(RecipeCategory.MISC, Items.FLASH_MEMORY.get()) .pattern("ITI") diff --git a/src/main/java/li/cil/oc2/data/WrenchRecipeBuilder.java b/src/main/java/li/cil/oc2/data/WrenchRecipeBuilder.java index ae052221..78f51c22 100644 --- a/src/main/java/li/cil/oc2/data/WrenchRecipeBuilder.java +++ b/src/main/java/li/cil/oc2/data/WrenchRecipeBuilder.java @@ -25,12 +25,12 @@ import javax.annotation.Nullable; import java.util.List; import java.util.function.Consumer; +@SuppressWarnings("unused") public final class WrenchRecipeBuilder { private final Item result; private final int count; private final List ingredients = Lists.newArrayList(); private final Advancement.Builder advancementBuilder = Advancement.Builder.advancement(); - private String group; public WrenchRecipeBuilder(final ItemLike result, final int count) { this.result = result.asItem(); @@ -81,7 +81,6 @@ public final class WrenchRecipeBuilder { } public WrenchRecipeBuilder setGroup(final String groupIn) { - this.group = groupIn; return this; } @@ -94,17 +93,17 @@ public final class WrenchRecipeBuilder { public void save(final Consumer consumerIn, final String save) { final ResourceLocation resourcelocation = ForgeRegistries.ITEMS.getKey(this.result); - if ((new ResourceLocation(save)).equals(resourcelocation)) { + if ((ResourceLocation.parse(save)).equals(resourcelocation)) { throw new IllegalStateException("Shapeless Recipe " + save + " should remove its 'save' argument"); } else { - this.save(consumerIn, new ResourceLocation(save)); + this.save(consumerIn, ResourceLocation.parse(save)); } } public void save(final Consumer consumerIn, final ResourceLocation id) { this.validate(id); - this.advancementBuilder.parent(new ResourceLocation("recipes/root")).addCriterion("has_the_recipe", RecipeUnlockedTrigger.unlocked(id)).rewards(AdvancementRewards.Builder.recipe(id)).requirements(RequirementsStrategy.OR); - consumerIn.accept(new WrenchRecipeBuilder.Result(id, this.result, this.count, "", this.ingredients, this.advancementBuilder, new ResourceLocation(id.getNamespace(), "recipes/misc/" + id.getPath()))); + this.advancementBuilder.parent(ResourceLocation.parse("recipes/root")).addCriterion("has_the_recipe", RecipeUnlockedTrigger.unlocked(id)).rewards(AdvancementRewards.Builder.recipe(id)).requirements(RequirementsStrategy.OR); + consumerIn.accept(new WrenchRecipeBuilder.Result(id, this.result, this.count, "", this.ingredients, this.advancementBuilder, ResourceLocation.fromNamespaceAndPath(id.getNamespace(), "recipes/misc/" + id.getPath()))); } private void validate(final ResourceLocation id) { diff --git a/src/main/resources/META-INF/mods.toml b/src/main/resources/META-INF/mods.toml index 7c66bce2..f03f5f05 100644 --- a/src/main/resources/META-INF/mods.toml +++ b/src/main/resources/META-INF/mods.toml @@ -17,7 +17,7 @@ This mod uses the Terminus Font under the Open Font License. The full license ca [[dependencies.oc2r]] modId = "forge" mandatory = true -versionRange = "[47.3.0,)" +versionRange = "[47.3.20,)" ordering = "NONE" side = "BOTH" [[dependencies.oc2r]] diff --git a/src/main/resources/assets/oc2r/fonts/license.txt b/src/main/resources/assets/oc2r/fonts/license.txt new file mode 100644 index 00000000..9022c11f --- /dev/null +++ b/src/main/resources/assets/oc2r/fonts/license.txt @@ -0,0 +1,92 @@ +Copyright (c) 2014, Ryan L McIntyre (https://ryanlmcintyre.com). + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/main/resources/assets/oc2r/fonts/terminus.ttf b/src/main/resources/assets/oc2r/fonts/terminus.ttf new file mode 100644 index 00000000..d8a4ea8a Binary files /dev/null and b/src/main/resources/assets/oc2r/fonts/terminus.ttf differ diff --git a/src/main/resources/assets/oc2r/models/block/cable_base.json b/src/main/resources/assets/oc2r/models/block/cable_base.json index 3a1c05c0..8e0ab97e 100644 --- a/src/main/resources/assets/oc2r/models/block/cable_base.json +++ b/src/main/resources/assets/oc2r/models/block/cable_base.json @@ -1 +1 @@ -{"parent":"block/block","loader": "oc2r:bus_cable","textures":{"atlas0":"oc2r:block/cable_base/cable_base_atlas0","particle":"#atlas0"},"elements":[{"from":[6,5,6],"to":[10,6,10],"faces":{"east":{"texture":"atlas0","uv":[0.0,8.0,2.0,8.5]},"west":{"texture":"atlas0","uv":[0.0,8.5,2.0,9.0]},"down":{"texture":"atlas0","uv":[0.0,9.0,2.0,11.0]},"north":{"texture":"atlas0","uv":[0.0,11.0,2.0,11.5]},"south":{"texture":"atlas0","uv":[0.0,11.5,2.0,12.0]}}},{"from":[6,6,10],"to":[10,10,11],"faces":{"east":{"texture":"atlas0","uv":[3.0,0.0,3.5,2.0]},"west":{"texture":"atlas0","uv":[3.5,0.0,4.0,2.0]},"up":{"texture":"atlas0","uv":[0.0,12.0,2.0,12.5]},"down":{"texture":"atlas0","uv":[0.0,12.5,2.0,13.0]},"south":{"texture":"atlas0","uv":[0.0,13.0,2.0,15.0]}}},{"from":[5,6,6],"to":[11,10,10],"faces":{"east":{"texture":"atlas0","uv":[2.0,13.0,4.0,15.0]},"west":{"texture":"atlas0","uv":[4.0,13.0,6.0,15.0]},"up":{"texture":"atlas0","uv":[0.0,0.0,3.0,2.0]},"down":{"texture":"atlas0","uv":[0.0,2.0,3.0,4.0]},"north":{"texture":"atlas0","uv":[0.0,4.0,3.0,6.0]},"south":{"texture":"atlas0","uv":[0.0,6.0,3.0,8.0]}}},{"from":[6,6,5],"to":[10,10,6],"faces":{"east":{"texture":"atlas0","uv":[4.0,0.0,4.5,2.0]},"west":{"texture":"atlas0","uv":[4.5,0.0,5.0,2.0]},"up":{"texture":"atlas0","uv":[0.0,15.0,2.0,15.5]},"down":{"texture":"atlas0","uv":[0.0,15.5,2.0,16.0]},"north":{"texture":"atlas0","uv":[6.0,13.0,8.0,15.0]}}},{"from":[6,10,6],"to":[10,11,10],"faces":{"east":{"texture":"atlas0","uv":[2.0,15.5,4.0,16.0]},"west":{"texture":"atlas0","uv":[4.0,15.5,6.0,16.0]},"up":{"texture":"atlas0","uv":[8.0,13.0,10.0,15.0]},"north":{"texture":"atlas0","uv":[6.0,15.5,8.0,16.0]},"south":{"texture":"atlas0","uv":[8.0,15.5,10.0,16.0]}}}]} +{"parent":"block/block","loader": "oc2r:bus_cable","render_type": "cutout","textures":{"atlas0":"oc2r:block/cable_base/cable_base_atlas0","particle":"#atlas0"},"elements":[{"from":[6,5,6],"to":[10,6,10],"faces":{"east":{"texture":"atlas0","uv":[0.0,8.0,2.0,8.5]},"west":{"texture":"atlas0","uv":[0.0,8.5,2.0,9.0]},"down":{"texture":"atlas0","uv":[0.0,9.0,2.0,11.0]},"north":{"texture":"atlas0","uv":[0.0,11.0,2.0,11.5]},"south":{"texture":"atlas0","uv":[0.0,11.5,2.0,12.0]}}},{"from":[6,6,10],"to":[10,10,11],"faces":{"east":{"texture":"atlas0","uv":[3.0,0.0,3.5,2.0]},"west":{"texture":"atlas0","uv":[3.5,0.0,4.0,2.0]},"up":{"texture":"atlas0","uv":[0.0,12.0,2.0,12.5]},"down":{"texture":"atlas0","uv":[0.0,12.5,2.0,13.0]},"south":{"texture":"atlas0","uv":[0.0,13.0,2.0,15.0]}}},{"from":[5,6,6],"to":[11,10,10],"faces":{"east":{"texture":"atlas0","uv":[2.0,13.0,4.0,15.0]},"west":{"texture":"atlas0","uv":[4.0,13.0,6.0,15.0]},"up":{"texture":"atlas0","uv":[0.0,0.0,3.0,2.0]},"down":{"texture":"atlas0","uv":[0.0,2.0,3.0,4.0]},"north":{"texture":"atlas0","uv":[0.0,4.0,3.0,6.0]},"south":{"texture":"atlas0","uv":[0.0,6.0,3.0,8.0]}}},{"from":[6,6,5],"to":[10,10,6],"faces":{"east":{"texture":"atlas0","uv":[4.0,0.0,4.5,2.0]},"west":{"texture":"atlas0","uv":[4.5,0.0,5.0,2.0]},"up":{"texture":"atlas0","uv":[0.0,15.0,2.0,15.5]},"down":{"texture":"atlas0","uv":[0.0,15.5,2.0,16.0]},"north":{"texture":"atlas0","uv":[6.0,13.0,8.0,15.0]}}},{"from":[6,10,6],"to":[10,11,10],"faces":{"east":{"texture":"atlas0","uv":[2.0,15.5,4.0,16.0]},"west":{"texture":"atlas0","uv":[4.0,15.5,6.0,16.0]},"up":{"texture":"atlas0","uv":[8.0,13.0,10.0,15.0]},"north":{"texture":"atlas0","uv":[6.0,15.5,8.0,16.0]},"south":{"texture":"atlas0","uv":[8.0,15.5,10.0,16.0]}}}]} diff --git a/src/main/resources/assets/oc2r/models/item/cpu_tier_inf.json b/src/main/resources/assets/oc2r/models/item/cpu_tier_inf.json new file mode 100644 index 00000000..9b4f8a15 --- /dev/null +++ b/src/main/resources/assets/oc2r/models/item/cpu_tier_inf.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "oc2r:item/cpu_tier_inf" + } +} diff --git a/src/main/resources/assets/oc2r/textures/gui/overlay/monitor_focused.png b/src/main/resources/assets/oc2r/textures/gui/overlay/monitor_focused.png new file mode 100644 index 00000000..e102e895 Binary files /dev/null and b/src/main/resources/assets/oc2r/textures/gui/overlay/monitor_focused.png differ diff --git a/src/main/resources/assets/oc2r/textures/item/cpu_tier_inf.png b/src/main/resources/assets/oc2r/textures/item/cpu_tier_inf.png new file mode 100644 index 00000000..c8071865 Binary files /dev/null and b/src/main/resources/assets/oc2r/textures/item/cpu_tier_inf.png differ diff --git a/src/main/resources/data/oc2r/item_tag_filters/oc2/hard_drive.json b/src/main/resources/data/oc2r/item_tag_filters/oc2r/hard_drive.json similarity index 100% rename from src/main/resources/data/oc2r/item_tag_filters/oc2/hard_drive.json rename to src/main/resources/data/oc2r/item_tag_filters/oc2r/hard_drive.json diff --git a/src/main/resources/data/oc2r/item_tag_filters/oc2/memory.json b/src/main/resources/data/oc2r/item_tag_filters/oc2r/memory.json similarity index 100% rename from src/main/resources/data/oc2r/item_tag_filters/oc2/memory.json rename to src/main/resources/data/oc2r/item_tag_filters/oc2r/memory.json diff --git a/src/main/resources/data/oc2r/tags/items/devices/cpu.json b/src/main/resources/data/oc2r/tags/items/devices/cpu.json index 5282a5fc..b7d00658 100644 --- a/src/main/resources/data/oc2r/tags/items/devices/cpu.json +++ b/src/main/resources/data/oc2r/tags/items/devices/cpu.json @@ -4,6 +4,7 @@ "oc2r:cpu_tier_1", "oc2r:cpu_tier_2", "oc2r:cpu_tier_3", - "oc2r:cpu_tier_4" + "oc2r:cpu_tier_4", + "oc2r:cpu_tier_inf" ] } diff --git a/src/main/scripts/bin/print256colors.sh b/src/main/scripts/bin/print256colors.sh new file mode 100644 index 00000000..99e3d8c9 --- /dev/null +++ b/src/main/scripts/bin/print256colors.sh @@ -0,0 +1,96 @@ +#!/bin/bash + +# Tom Hale, 2016. MIT Licence. +# Print out 256 colours, with each number printed in its corresponding colour +# See http://askubuntu.com/questions/821157/print-a-256-color-test-pattern-in-the-terminal/821163#821163 + +set -eu # Fail on errors or undeclared variables + +printable_colours=256 + +# Return a colour that contrasts with the given colour +# Bash only does integer division, so keep it integral +function contrast_colour { + local r g b luminance + colour="$1" + + if (( colour < 16 )); then # Initial 16 ANSI colours + (( colour == 0 )) && printf "15" || printf "0" + return + fi + + # Greyscale # rgb_R = rgb_G = rgb_B = (number - 232) * 10 + 8 + if (( colour > 231 )); then # Greyscale ramp + (( colour < 244 )) && printf "15" || printf "0" + return + fi + + # All other colours: + # 6x6x6 colour cube = 16 + 36*R + 6*G + B # Where RGB are [0..5] + # See http://stackoverflow.com/a/27165165/5353461 + + # r=$(( (colour-16) / 36 )) + g=$(( ((colour-16) % 36) / 6 )) + # b=$(( (colour-16) % 6 )) + + # If luminance is bright, print number in black, white otherwise. + # Green contributes 587/1000 to human perceived luminance - ITU R-REC-BT.601 + (( g > 2)) && printf "0" || printf "15" + return + + # Uncomment the below for more precise luminance calculations + + # # Calculate percieved brightness + # # See https://www.w3.org/TR/AERT#color-contrast + # # and http://www.itu.int/rec/R-REC-BT.601 + # # Luminance is in range 0..5000 as each value is 0..5 + # luminance=$(( (r * 299) + (g * 587) + (b * 114) )) + # (( $luminance > 2500 )) && printf "0" || printf "15" +} + +# Print a coloured block with the number of that colour +function print_colour { + local colour="$1" contrast + contrast=$(contrast_colour "$1") + printf "\e[48;5;%sm" "$colour" # Start block of colour + printf "\e[38;5;%sm%3d" "$contrast" "$colour" # In contrast, print number + printf "\e[0m " # Reset colour +} + +# Starting at $1, print a run of $2 colours +function print_run { + local i + for (( i = "$1"; i < "$1" + "$2" && i < printable_colours; i++ )) do + print_colour "$i" + done + printf " " +} + +# Print blocks of colours +function print_blocks { + local start="$1" i + local end="$2" # inclusive + local block_cols="$3" + local block_rows="$4" + local blocks_per_line="$5" + local block_length=$((block_cols * block_rows)) + + # Print sets of blocks + for (( i = start; i <= end; i += (blocks_per_line-1) * block_length )) do + printf "\n" # Space before each set of blocks + # For each block row + for (( row = 0; row < block_rows; row++ )) do + # Print block columns for all blocks on the line + for (( block = 0; block < blocks_per_line; block++ )) do + print_run $(( i + (block * block_length) )) "$block_cols" + done + (( i += block_cols )) # Prepare to print the next row + printf "\n" + done + done +} + +print_run 0 16 # The first 16 colours are spread over the whole spectrum +printf "\n" +print_blocks 16 231 6 6 3 # 6x6x6 colour cube between 16 and 231 inclusive +print_blocks 232 255 12 2 1 # Not 50, but 24 Shades of Grey diff --git a/src/main/scripts/bin/printtruecolor.sh b/src/main/scripts/bin/printtruecolor.sh new file mode 100644 index 00000000..554ab122 --- /dev/null +++ b/src/main/scripts/bin/printtruecolor.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# Based on: https://gist.github.com/XVilka/8346728 and https://unix.stackexchange.com/a/404415/395213 + +awk -v term_cols="20" -v term_lines="20" 'BEGIN{ + s="/\\"; + total_cols=term_cols*term_lines; + for (colnum = 0; colnum255) g = 510-g; + printf "\033[48;2;%d;%d;%dm", r,g,b; + printf "\033[38;2;%d;%d;%dm", 255-r,255-g,255-b; + printf "%s\033[0m", substr(s,colnum%2+1,1); + if (colnum%term_cols==term_cols) printf "\n"; + } + printf "\n"; +}' diff --git a/src/main/scripts/bin/printtruecolor2.sh b/src/main/scripts/bin/printtruecolor2.sh new file mode 100644 index 00000000..d170763e --- /dev/null +++ b/src/main/scripts/bin/printtruecolor2.sh @@ -0,0 +1,28 @@ +#!/bin/sh + +prompt() { + echo + read -p "Press any key to continue... " -n1 -s + clear +} + +clear +echo "XTERM True Color (24-bit RGB) Test" +echo "Rendering 20x20 background color gradient" +prompt + +# 20x20 character block gradient +# Horizontal: Red (0–255) +# Vertical: Blue (0–255) +for y in $(seq 0 19); do + for x in $(seq 0 19); do + r=$(( x * 255 / 19 )) + g=0 + b=$(( y * 255 / 19 )) + printf "\033[48;2;%d;%d;%dm \033[0m" "$r" "$g" "$b" + done + echo +done + +prompt +clear