terminal screen no worky

main
Walker Fowlkes 7 months ago
parent 44b600a835
commit b9be0549c9

@ -2,6 +2,7 @@ plugins {
id 'fabric-loom' version '1.6-SNAPSHOT'
id 'maven-publish'
id 'com.github.johnrengelman.shadow' version '8.1.1'
id 'org.jetbrains.kotlin.jvm' version '1.9.23'
}
version = project.mod_version
@ -17,6 +18,7 @@ repositories {
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories.
maven { url 'https://maven.dblsaiko.net' } //qcommon
}
loom {
@ -42,6 +44,8 @@ dependencies {
shadow(implementation(project(":J65el02")))
shadow(implementation(group: "net.dblsaiko.qcommon.croco", name: "croco", version: "2.1.3"))
}
processResources {

@ -1,13 +1,16 @@
package net.brokenmoon.redcontrol;
import net.brokenmoon.redcontrol.blocks.TerminalEntity;
import net.brokenmoon.redcontrol.screen.CpuScreen;
import net.brokenmoon.redcontrol.screen.MonitorScreen;
import net.brokenmoon.redcontrol.screen.TerminalScreen;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.text.Text;
import net.minecraft.util.math.BlockPos;
import java.util.Optional;
public class RedControlClient implements ClientModInitializer {
@Override
public void onInitializeClient() {
@ -15,16 +18,23 @@ public class RedControlClient implements ClientModInitializer {
ClientPlayNetworking.registerGlobalReceiver(
RedControlNetworking.CPUGUI_PACKET_ID, (client, handler, buf, responseSender) -> {
BlockPos blockPos = buf.readBlockPos();
client.execute(() -> {
client.setScreen(new CpuScreen(Text.literal("cpu"), blockPos));
});
client.execute(() -> client.setScreen(new CpuScreen(Text.literal("cpu"), blockPos)));
});
ClientPlayNetworking.registerGlobalReceiver(
RedControlNetworking.MONITOR_PACKET_ID, (client, handler, buf, responseSender) -> {
BlockPos blockPos = buf.readBlockPos();
client.execute(() -> {
client.setScreen(new MonitorScreen(Text.literal("monitor")));
});
ClientWorld cw = client.world;
if (cw != null) {
Optional<TerminalEntity> te = cw.getBlockEntity(blockPos,RedControl.TERMINAL_BLOCK_ENTITY);
if (te.isEmpty()) {
RedControl.LOGGER.warn("Server just sent us a Terminal packet, terminal is not at position given {}?",blockPos);
return;
}
client.execute(() -> client.setScreen(new TerminalScreen(te.get())));
} else {
RedControl.LOGGER.warn("Server just send us a packet... we dont have a world... HOW");
}
});
Shaders.INSTANCE.init();
}
}

@ -0,0 +1,93 @@
package net.brokenmoon.redcontrol
import net.brokenmoon.redcontrol.RedControl.modloc
import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener
import net.fabricmc.fabric.api.resource.ResourceManagerHelper
import net.minecraft.resource.ResourceManager
import net.minecraft.resource.ResourceReloader.Synchronizer
import net.minecraft.resource.ResourceType
import net.minecraft.util.Identifier
import net.minecraft.util.profiler.Profiler
import org.lwjgl.opengl.GL11
import org.lwjgl.opengl.GL30
import java.util.concurrent.CompletableFuture
import java.util.concurrent.Executor
import kotlin.jvm.optionals.getOrNull
object Shaders {
private var screen = 0
fun screen() = screen
fun init() {
ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(object : IdentifiableResourceReloadListener {
override fun reload(s: Synchronizer, rm: ResourceManager, profiler: Profiler, profiler1: Profiler, executor: Executor, executor1: Executor): CompletableFuture<Void> {
return CompletableFuture.runAsync({
if (screen != 0) GL30.glDeleteProgram(screen)
screen = loadShader(rm, "screen")
}, executor1).thenCompose { s.whenPrepared(null) }
}
override fun getFabricId(): Identifier = modloc("shaders")
})
}
private fun loadShader(rm: ResourceManager, id: String): Int {
val vshs = rm.getResource(modloc("shaders/$id.vert")).getOrNull()?.inputStream?.bufferedReader()?.readText()
val fshs = rm.getResource(modloc("shaders/$id.frag")).getOrNull()?.inputStream?.bufferedReader()?.readText()
val vsh = GL30.glCreateShader(GL30.GL_VERTEX_SHADER)
val fsh = GL30.glCreateShader(GL30.GL_FRAGMENT_SHADER)
val prog = GL30.glCreateProgram()
// No goto? I'll make my own.
run {
GL30.glShaderSource(vsh, vshs)
GL30.glShaderSource(fsh, fshs)
GL30.glCompileShader(vsh)
if (GL30.glGetShaderi(vsh, GL30.GL_COMPILE_STATUS) == GL11.GL_FALSE) {
// TODO use logger
val log = GL30.glGetShaderInfoLog(vsh, 32768)
println("Failed to compile vertex shader '$id'")
for (line in log.lineSequence()) println(line)
return@run
}
GL30.glCompileShader(fsh)
if (GL30.glGetShaderi(fsh, GL30.GL_COMPILE_STATUS) == GL11.GL_FALSE) {
// TODO use logger
val log = GL30.glGetShaderInfoLog(fsh, 32768)
println("Failed to compile fragment shader '$id'")
for (line in log.lineSequence()) println(line)
return@run
}
GL30.glAttachShader(prog, vsh)
GL30.glAttachShader(prog, fsh)
GL30.glLinkProgram(prog)
if (GL30.glGetProgrami(prog, GL30.GL_LINK_STATUS) == GL11.GL_FALSE) {
// TODO use logger
val log = GL30.glGetProgramInfoLog(prog, 32768)
println("Failed to link program '$id'")
for (line in log.lineSequence()) println(line)
return@run
}
GL30.glDeleteShader(vsh)
GL30.glDeleteShader(fsh)
return prog
}
GL30.glDeleteShader(vsh)
GL30.glDeleteShader(fsh)
GL30.glDeleteProgram(prog)
return 0
}
}

@ -1,31 +0,0 @@
package net.brokenmoon.redcontrol.screen;
import net.brokenmoon.redcontrol.RedControl;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
public class MonitorScreen extends Screen {
Identifier screenTexture = new Identifier("redcontrol", "gui/display.png");
public MonitorScreen(Text title) {
super(title);
}
@Override
protected void init() {
super.init();
RedControl.LOGGER.info("Opened Monitor Screen");
}
@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
super.render(context, mouseX, mouseY, delta);
context.drawTexture(screenTexture,0,0,0,0,350,230);
}
@Override
public boolean shouldPause() {
return false;
}
}

@ -0,0 +1,261 @@
package net.brokenmoon.redcontrol.screen
import com.mojang.blaze3d.platform.GlStateManager
import com.mojang.blaze3d.platform.TextureUtil
import com.mojang.blaze3d.systems.RenderSystem
import io.netty.buffer.Unpooled
import net.brokenmoon.redcontrol.RedControlNetworking
import net.brokenmoon.redcontrol.Shaders
import net.brokenmoon.redcontrol.blocks.TerminalEntity
import net.dblsaiko.qcommon.croco.Mat4
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gl.Framebuffer
import net.minecraft.client.gl.SimpleFramebuffer
import net.minecraft.client.gui.DrawContext
import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.render.VertexFormat.DrawMode
import net.minecraft.client.render.VertexFormats
import net.minecraft.network.PacketByteBuf
import net.minecraft.text.Text
import net.minecraft.util.math.Vec3d
import org.lwjgl.BufferUtils
import org.lwjgl.glfw.GLFW
import org.lwjgl.opengl.*
import org.lwjgl.opengl.GL11.GL_FLOAT
import org.lwjgl.opengl.GL11.GL_TRIANGLES
import kotlin.experimental.xor
import kotlin.math.round
private val buf = BufferUtils.createByteBuffer(16384)
private val vbo = GL30.glGenBuffers()
private val vao = GL30.glGenVertexArrays()
private val screenTex = createTexture()
private val charsetTex = createTexture()
class TerminalScreen(val te: TerminalEntity) : Screen(Text.translatable("block.redcontrol.terminal")) {
private var uMvp = 0
private var uCharset = 0
private var uScreen = 0
private var aXyz = 0
private var aUv = 0
private var fb: Framebuffer? = null
override fun tick() {
val minecraft = client ?: return
val dist = minecraft.player?.getCameraPosVec(1f)?.squaredDistanceTo(Vec3d.ofCenter(te.pos))
?: Double.POSITIVE_INFINITY
if (dist > 10 * 10) minecraft.setScreen(null)
}
override fun render(ctx: DrawContext, mouseX: Int, mouseY: Int, delta: Float) {
renderBackground(ctx,mouseX,mouseY,delta)
val matrices = ctx.matrices
val sh = Shaders.screen()
val fb = fb ?: return
val mc = client ?: return
fb.setTexFilter(if ((mc.window.scaleFactor.toInt() % 2) == 0) GL11.GL_NEAREST else GL11.GL_LINEAR)
fb.beginWrite(true)
val mat = Mat4.ortho(0.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f)
GL30.glUseProgram(sh)
GL30.glBindVertexArray(vao)
GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, vbo)
GL20.glEnableVertexAttribArray(aXyz)
GL20.glEnableVertexAttribArray(aUv)
RenderSystem.activeTexture(GL13.GL_TEXTURE0)
//RenderSystem.enableTexture() //TODO: figure out why this does not exists
RenderSystem.bindTexture(screenTex)
buf.clear()
val fbuf = buf.asFloatBuffer()
mat.intoBuffer(fbuf)
fbuf.flip()
GL30.glUniformMatrix4fv(uMvp, false, fbuf)
GL30.glUniform1i(uScreen, 0)
buf.clear()
buf.put(te.screen)
if (te.cm == 1 || (te.cm == 2 && (System.currentTimeMillis() / 500) % 2 == 0L)) {
val ci = te.cx + te.cy * 80
buf.put(ci, te.screen[ci] xor 0x80.toByte())
}
buf.rewind()
GlStateManager._texImage2D(GL11.GL_TEXTURE_2D, 0, GL30.GL_R16I, 80, 60, 0, GL30.GL_RED_INTEGER, GL11.GL_UNSIGNED_BYTE, buf.asIntBuffer())
RenderSystem.activeTexture(GL13.GL_TEXTURE2)
//RenderSystem.enableTexture() //TODO: figure out why this does not exists
RenderSystem.bindTexture(charsetTex)
GL30.glUniform1i(uCharset, 2)
buf.clear()
buf.put(te.charset)
buf.rewind()
GlStateManager._texImage2D(GL11.GL_TEXTURE_2D, 0, GL30.GL_R16I, 8, 256, 0, GL30.GL_RED_INTEGER, GL11.GL_UNSIGNED_BYTE, buf.asIntBuffer())
GL11.glDrawArrays(GL_TRIANGLES, 0, 6)
GL20.glDisableVertexAttribArray(aXyz)
GL20.glDisableVertexAttribArray(aUv)
GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, 0)
GL30.glBindVertexArray(0)
GL30.glUseProgram(0)
RenderSystem.bindTexture(0)
//RenderSystem.disableTexture() //TODO: figure out why this does not exists
RenderSystem.activeTexture(GL13.GL_TEXTURE0)
RenderSystem.bindTexture(0)
mc.framebuffer.beginWrite(true)
val swidth = 8 * 80 * 0.5
val sheight = 8 * 50 * 0.5
val x1 = round(width / 2.0 - swidth / 2.0)
val y1 = round(height / 2.0 - sheight / 2.0)
matrices.push()
matrices.translate(x1, y1, -2000.0) // why the -2000? not sure
val shader = mc.gameRenderer.blitScreenProgram
shader.addSampler("DiffuseSampler", fb.colorAttachment)
shader.modelViewMat?.set(matrices.peek().positionMatrix)
shader.projectionMat?.set(RenderSystem.getProjectionMatrix())
shader.bind()
val t = RenderSystem.renderThreadTesselator()
val buf = t.buffer
buf.begin(DrawMode.QUADS, VertexFormats.POSITION_TEXTURE_COLOR)
buf.vertex(0.0, 0.0, 0.0).texture(0f, 1f).color(255, 255, 255, 255).next()
buf.vertex(0.0, sheight, 0.0).texture(0f, 0f).color(255, 255, 255, 255).next()
buf.vertex(swidth, sheight, 0.0).texture(1f, 0f).color(255, 255, 255, 255).next()
buf.vertex(swidth, 0.0, 0.0).texture(1f, 1f).color(255, 255, 255, 255).next()
buf.end()
//BufferRenderer.postDraw(buf) //TODO: figure out why this is gone
shader.unbind()
matrices.pop()
}
override fun keyPressed(key: Int, scancode: Int, modifiers: Int): Boolean {
if (super.keyPressed(key, scancode, modifiers)) return true
val result: Byte? = when (key) {
GLFW.GLFW_KEY_BACKSPACE -> 0x08
GLFW.GLFW_KEY_ENTER -> 0x0D
GLFW.GLFW_KEY_HOME -> 0x80
GLFW.GLFW_KEY_END -> 0x81
GLFW.GLFW_KEY_UP -> 0x82
GLFW.GLFW_KEY_DOWN -> 0x83
GLFW.GLFW_KEY_LEFT -> 0x84
GLFW.GLFW_KEY_RIGHT -> 0x85
else -> null
}?.toByte()
if (result != null) pushKey(result)
return result != null
}
override fun charTyped(c: Char, modifiers: Int): Boolean {
if (super.charTyped(c, modifiers)) return true
val result: Byte? = when (c) {
in '\u0001'..'\u007F' -> c.code.toByte()
else -> null
}
if (result != null) pushKey(result)
return result != null
}
private fun pushKey(c: Byte) {
val buffer = PacketByteBuf(Unpooled.buffer())
buffer.writeBlockPos(te.pos)
buffer.writeByte(c.toInt())
ClientPlayNetworking.send(RedControlNetworking.KEY_PRESS, buffer)
}
override fun init() {
//client!!.keyboard.setRepeatEvents(true) //TODO: figure out why this does not exists
initDrawData()
initFb()
}
private fun initDrawData() {
val sh = Shaders.screen()
GL30.glUseProgram(sh)
GL30.glBindVertexArray(vao)
GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, vbo)
uMvp = GL30.glGetUniformLocation(sh, "mvp")
uCharset = GL30.glGetUniformLocation(sh, "charset")
uScreen = GL30.glGetUniformLocation(sh, "screen")
aXyz = GL30.glGetAttribLocation(sh, "xyz")
aUv = GL30.glGetAttribLocation(sh, "uv")
GL20.glVertexAttribPointer(aXyz, 3, GL_FLOAT, false, 20, 0)
GL20.glVertexAttribPointer(aUv, 2, GL_FLOAT, false, 20, 12)
buf.clear()
floatArrayOf(
0f, 0f, 0f, 0f, 0f,
1f, 1f, 0f, 1f, 1f,
1f, 0f, 0f, 1f, 0f,
0f, 0f, 0f, 0f, 0f,
0f, 1f, 0f, 0f, 1f,
1f, 1f, 0f, 1f, 1f
).forEach { buf.putFloat(it) }
buf.rewind()
GL30.glBufferData(GL30.GL_ARRAY_BUFFER, buf, GL15.GL_STATIC_DRAW)
GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, 0)
GL30.glBindVertexArray(0)
GL30.glUseProgram(0)
}
private fun initFb() {
fb?.delete()
val scale = 4
fb = SimpleFramebuffer(80 * 8 * scale, 50 * 8 * scale, false, MinecraftClient.IS_SYSTEM_MAC)
}
override fun removed() {
//client!!.keyboard.setRepeatEvents(false) //TODO: check if this is still okay. or if we need to change this
fb?.delete()
fb = null
}
override fun shouldPause() = false
}
private fun createTexture(): Int {
val tex = TextureUtil.generateTextureId()
RenderSystem.bindTexture(tex)
RenderSystem.texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST)
RenderSystem.texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST)
RenderSystem.texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_REPEAT)
RenderSystem.texParameter(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_REPEAT)
RenderSystem.bindTexture(0)
return tex
}

@ -2,10 +2,10 @@ package net.brokenmoon.redcontrol;
import net.brokenmoon.redcontrol.blockentities.CpuEntity;
import net.brokenmoon.redcontrol.blockentities.DriveEntity;
import net.brokenmoon.redcontrol.blockentities.MonitorEntity;
import net.brokenmoon.redcontrol.blocks.CpuBlock;
import net.brokenmoon.redcontrol.blocks.DriveBlock;
import net.brokenmoon.redcontrol.blocks.MonitorBlock;
import net.brokenmoon.redcontrol.blocks.TerminalBlock;
import net.brokenmoon.redcontrol.blocks.TerminalEntity;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.item.v1.FabricItemSettings;
@ -14,7 +14,6 @@ import net.fabricmc.fabric.api.object.builder.v1.block.FabricBlockSettings;
import net.fabricmc.fabric.api.object.builder.v1.block.entity.FabricBlockEntityTypeBuilder;
import net.fabricmc.fabric.api.resource.ResourceManagerHelper;
import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener;
import net.minecraft.block.Block;
import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
@ -23,7 +22,6 @@ import net.minecraft.registry.Registries;
import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceType;
import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import org.slf4j.Logger;
@ -42,13 +40,13 @@ public class RedControl implements ModInitializer {
//Blocks
public static final CpuBlock CPU = new CpuBlock(FabricBlockSettings.create().strength(4.0f));
public static final MonitorBlock MONITOR = new MonitorBlock(FabricBlockSettings.create().strength(4.0f));
public static final TerminalBlock TERMINAL = new TerminalBlock(FabricBlockSettings.create().strength(4.0f));
public static final DriveBlock DRIVE = new DriveBlock(FabricBlockSettings.create().strength(4.0f));
//Items
//Block Entities
public static final BlockEntityType<CpuEntity> CPU_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, modloc("cpu_block_entity"), FabricBlockEntityTypeBuilder.create(CpuEntity::new, CPU).build());
public static final BlockEntityType<MonitorEntity> MONITOR_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, modloc("monitor_block_entity"), FabricBlockEntityTypeBuilder.create(MonitorEntity::new, MONITOR).build());
public static final BlockEntityType<TerminalEntity> TERMINAL_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, modloc("monitor_block_entity"), FabricBlockEntityTypeBuilder.create(TerminalEntity::new, TERMINAL).build());
public static final BlockEntityType<DriveEntity> DRIVE_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, modloc("drive_block_entity"), FabricBlockEntityTypeBuilder.create(DriveEntity::new, DRIVE).build());
public static final Item SQUEAKY_HAMMER = new Item(new FabricItemSettings());
@ -69,55 +67,48 @@ public class RedControl implements ModInitializer {
public void reload(ResourceManager manager) {
images.clear(); //remove all previous images
for(Map.Entry<Identifier,Resource> entry : manager.findResources("image", path -> true).entrySet()) {
try(InputStream stream = entry.getValue().getInputStream();) {
try(InputStream stream = entry.getValue().getInputStream()) {
String[] split = entry.getKey().getPath().split("/");
String file = split[split.length-1];
LOGGER.info("Found image {}",file);
images.put(file,stream.readAllBytes());
} catch(Exception e) {
LOGGER.error("Error occurred while loading resource json {}", entry.getKey().toString(), e);
LOGGER.error("Error occurred while loading resource binary {}", entry.getKey().toString(), e);
}
}
}
});
LOGGER.info("Initializing RedControl!");
Registry.register(Registries.BLOCK, modloc("cpu"), CPU);
Registry.register(Registries.BLOCK, modloc("monitor"), MONITOR);
Registry.register(Registries.BLOCK, modloc("monitor"), TERMINAL);
Registry.register(Registries.BLOCK, modloc("disk_drive"), DRIVE);
Registry.register(Registries.ITEM, modloc("cpu"), new BlockItem(CPU, new FabricItemSettings()));
Registry.register(Registries.ITEM, modloc("monitor"), new BlockItem(MONITOR, new FabricItemSettings()));
Registry.register(Registries.ITEM, modloc("monitor"), new BlockItem(TERMINAL, new FabricItemSettings()));
Registry.register(Registries.ITEM, modloc("disk_drive"), new BlockItem(DRIVE, new FabricItemSettings()));
Registry.register(Registries.ITEM, modloc("squeaky_hammer"), SQUEAKY_HAMMER);
//Packets
ServerPlayNetworking.registerGlobalReceiver(RedControlNetworking.CPU_START, ((server, player, handler, buf, responseSender) -> {
server.execute(() -> {
ServerPlayNetworking.registerGlobalReceiver(RedControlNetworking.CPU_START, ((server, player, handler, buf, responseSender) -> server.execute(() -> {
BlockPos blockPos = buf.readBlockPos();
CpuEntity cpu = (CpuEntity) player.getWorld().getBlockEntity(blockPos);
cpu.start();
LOGGER.info("Starting cpu at {}",blockPos);
});
}));
})));
ServerPlayNetworking.registerGlobalReceiver(RedControlNetworking.CPU_STOP, ((server, player, handler, buf, responseSender) -> {
server.execute(() -> {
ServerPlayNetworking.registerGlobalReceiver(RedControlNetworking.CPU_STOP, ((server, player, handler, buf, responseSender) -> server.execute(() -> {
BlockPos blockPos = buf.readBlockPos();
CpuEntity cpu = (CpuEntity) player.getWorld().getBlockEntity(blockPos);
cpu.stop();
LOGGER.info("Stopping cpu at {}",blockPos);
});
}));
})));
ServerPlayNetworking.registerGlobalReceiver(RedControlNetworking.CPU_RESET, ((server, player, handler, buf, responseSender) -> {
server.execute(() -> {
ServerPlayNetworking.registerGlobalReceiver(RedControlNetworking.CPU_RESET, ((server, player, handler, buf, responseSender) -> server.execute(() -> {
BlockPos blockPos = buf.readBlockPos();
CpuEntity cpu = (CpuEntity) player.getWorld().getBlockEntity(blockPos);
cpu.reset();
LOGGER.info("Resetting cpu at {}", blockPos);
});
}));
})));
}
static Identifier modloc(String path) {return new Identifier("redcontrol",path);}

@ -2,10 +2,13 @@ package net.brokenmoon.redcontrol;
import net.minecraft.util.Identifier;
import static net.brokenmoon.redcontrol.RedControl.modloc;
public class RedControlNetworking {
public static final Identifier CPUGUI_PACKET_ID = new Identifier("redcontrol", "open_cpu_gui");
public static final Identifier MONITOR_PACKET_ID = new Identifier("redcontrol", "open_monitor");
public static final Identifier CPU_START = new Identifier("redcontrol", "start_cpu");
public static final Identifier CPU_STOP = new Identifier("redcontrol", "stop_cpu");
public static final Identifier CPU_RESET = new Identifier("redcontrol", "reset_cpu");
public static final Identifier CPUGUI_PACKET_ID = modloc("open_cpu_gui");
public static final Identifier MONITOR_PACKET_ID = modloc("open_monitor");
public static final Identifier CPU_START = modloc("start_cpu");
public static final Identifier CPU_STOP = modloc("stop_cpu");
public static final Identifier CPU_RESET = modloc("reset_cpu");
public static final Identifier KEY_PRESS = modloc("key_press");
}

@ -1,276 +0,0 @@
package net.brokenmoon.redcontrol.blockentities;
import net.brokenmoon.redcontrol.RedControl;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.listener.ClientPlayPacketListener;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
import net.minecraft.util.math.BlockPos;
import org.jetbrains.annotations.Nullable;
public class MonitorEntity extends Peripheral {
public static final int WIDTH = 80;
public static final int HEIGHT = 50;
private int accessRow;
private int cursorX;
private int cursorY;
private int cursorMode = 2; // (0: hidden, 1: solid, 2: blink)
private int keyBufferStart;
private int keyBufferPos;
private int blitMode; // (1: fill, 2: invert; 3: shift)
private int blitXStartOrFill;
private int blitYStart;
private int blitXOffset;
private int blitYOffset;
private int blitWidth;
private int blitHeight;
private byte[] keyBuffer = new byte[0x10];
private byte[][] windowData = new byte[HEIGHT][WIDTH];
public String[] getText(){
String[] l = new String[HEIGHT];
for(int y = 0; y < HEIGHT; y++) {
String temp = "";
for (int x = 0; x < WIDTH; x++) {
temp += (char) windowData[y][x];
}
l[y] = temp;
}
return l;
}
private boolean isDisplayDirty;
private boolean isCursorDirty;
public MonitorEntity(BlockPos pos, BlockState state) {
super(RedControl.MONITOR_BLOCK_ENTITY, pos, state, 1);
}
@Override
public void write(int address, int data) {
switch (address) {
case 0x00:
this.accessRow = data;
break;
case 0x01:
this.isCursorDirty = this.cursorX != data;
this.cursorX = data;
break;
case 0x02:
this.isCursorDirty = this.cursorY != data;
this.cursorY = data;
break;
case 0x03:
this.isCursorDirty = this.cursorMode != data;
this.cursorMode = data;
break;
case 0x04:
this.keyBufferStart = data & 0x0f;
break;
case 0x05:
this.keyBufferPos = data & 0x0f;
break;
case 0x06:
break;
case 0x07:
this.blitMode = data;
break;
case 0x08:
this.blitXStartOrFill = data;
break;
case 0x09:
this.blitYStart = data;
break;
case 0x0A:
this.blitXOffset = data;
break;
case 0x0B:
this.blitYOffset = data;
break;
case 0x0C:
this.blitWidth = data;
break;
case 0x0D:
this.blitHeight = data;
break;
default:
if (address >= 0x10 && address < 0x60) {
this.isDisplayDirty = true;
this.windowData[this.accessRow][address - 0x10] = (byte) data;
}
if (this.isDisplayDirty) {
this.isDisplayDirty = false;
this.update();
}
}
}
@Override
public int read(int address) {
switch (address) {
case 0x00:
return this.accessRow;
case 0x01:
return this.cursorX;
case 0x02:
return this.cursorY;
case 0x03:
return this.cursorMode;
case 0x04:
return this.keyBufferStart;
case 0x05:
return this.keyBufferPos;
case 0x06:
return this.keyBuffer[this.keyBufferStart] & 0xff;
case 0x07:
return this.blitMode;
case 0x08:
return this.blitXStartOrFill;
case 0x09:
return this.blitYStart;
case 0x0A:
return this.blitXOffset;
case 0x0B:
return this.blitYOffset;
case 0x0C:
return this.blitWidth;
case 0x0D:
return this.blitHeight;
default:
if (address >= 0x10 && address < 0x60) {
return this.windowData[this.accessRow][address - 0x10] & 0xff;
}
return 0;
}
}
@Override
public void update() {
int maxWidth = Math.min(WIDTH, this.blitWidth + this.blitXOffset);
int maxHeight = Math.min(HEIGHT, this.blitHeight + this.blitYOffset);
int row = this.blitYOffset;
int col;
this.isDisplayDirty |= this.blitMode != 0;
switch (this.blitMode) {
case 1: // fill
for (; row < maxHeight; row++) {
for (col = this.blitXOffset; col < maxWidth; col++) {
this.windowData[row][col] = (byte) this.blitXStartOrFill;
}
}
break;
case 2: // invert
for (; row < maxHeight; row++) {
for (col = this.blitXOffset; col < maxWidth; col++) {
this.windowData[row][col] ^= 0x80;
}
}
break;
case 3: // shift
int shiftX = this.blitXStartOrFill - this.blitXOffset;
int shiftY = this.blitYStart - this.blitYOffset;
for (; row < maxHeight; row++) {
int srcRow = row + shiftY;
if (srcRow >= 0 & srcRow < HEIGHT) {
for (col = this.blitXOffset; col < maxWidth; col++) {
int srcCol = col + shiftX;
if (srcCol >= 0 && srcCol < WIDTH) {
this.windowData[row][col] = this.windowData[srcRow][srcCol];
}
}
}
}
break;
}
this.blitMode = 0;
if (this.isCursorDirty) {
this.isCursorDirty = false;
this.updateCursor(this.cursorX, this.cursorY, this.cursorMode);
}
}
private void updateCursor(int cursorX, int cursorY, int cursorMode) {
}
/**
* Appends a key code to the key buffer.
*
* @param key The key code
*/
public void onKey(byte key) {
int nextPos = (this.keyBufferPos + 1) & 0x0f;
if (nextPos != this.keyBufferStart) {
this.keyBuffer[this.keyBufferPos] = key;
this.keyBufferPos = nextPos;
}
}
@Override
protected void writeNbt(NbtCompound nbt) {
nbt.putByteArray("keyBuffer", this.keyBuffer);
for(int i = 0; i < windowData.length; i++){
nbt.putByteArray("winData" + i, windowData[i]);
}
nbt.putInt("acessRow", accessRow);
nbt.putInt("cursorX", cursorX);
nbt.putInt("cursorY", cursorY);
nbt.putInt("cursorMode", cursorMode);
nbt.putInt("keyBufferStart", keyBufferStart);
nbt.putInt("keyBufferPos", keyBufferPos);
nbt.putInt("blitMode", blitMode);
nbt.putInt("blitXStartOrFill", blitXStartOrFill);
nbt.putInt("blitYStart", blitYStart);
nbt.putInt("blitXOffset", blitXOffset);
nbt.putInt("blitYOffset", blitYOffset);
nbt.putInt("blitWidth", blitWidth);
nbt.putInt("blitHeight", blitHeight);
super.writeNbt(nbt);
}
@Override
public void readNbt(NbtCompound nbt) {
this.keyBuffer = nbt.getByteArray("keyBuffer");
for(int i = 0; i < windowData.length; i++){
windowData[i] = nbt.getByteArray("winData" + i);
}
accessRow = nbt.getInt("accessRow");
cursorX = nbt.getInt("cursorX");
cursorY = nbt.getInt("cursorY");
cursorMode = nbt.getInt("cursorMode");
keyBufferStart = nbt.getInt("keyBufferStart");
keyBufferPos = nbt.getInt("keyBufferPos");
blitMode = nbt.getInt("blitMode");
blitXStartOrFill = nbt.getInt("blitXStartOrFill");
blitYStart = nbt.getInt("blitYStart");
blitXOffset = nbt.getInt("blitXOffset");
blitYOffset = nbt.getInt("blitYOffset");
blitWidth = nbt.getInt("blitWidth");
blitHeight = nbt.getInt("blitHeight");
super.readNbt(nbt);
}
@Nullable
@Override
public Packet<ClientPlayPacketListener> toUpdatePacket() {
return BlockEntityUpdateS2CPacket.create(this);
}
@Override
public NbtCompound toInitialChunkDataNbt() {
return createNbt();
}
}

@ -1,12 +1,9 @@
package net.brokenmoon.redcontrol.blocks;
import com.mojang.serialization.MapCodec;
import com.simon816.j65el02.Cpu;
import net.brokenmoon.redcontrol.RedControl;
import net.brokenmoon.redcontrol.RedControlNetworking;
import net.brokenmoon.redcontrol.blockentities.CpuEntity;
import net.brokenmoon.redcontrol.blockentities.MonitorEntity;
import net.brokenmoon.redcontrol.blockentities.Peripheral;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.block.*;
@ -42,7 +39,7 @@ public class CpuBlock extends NetworkCarrier {
@Override
public <T extends BlockEntity> BlockEntityTicker<T> getTicker(World world, BlockState state, BlockEntityType<T> type) {
return validateTicker(type, RedControl.CPU_BLOCK_ENTITY, (world1, pos, state1, be) -> CpuEntity.tick(world1, pos, state1, be));
return validateTicker(type, RedControl.CPU_BLOCK_ENTITY, CpuEntity::tick);
}
@Override

@ -3,7 +3,6 @@ package net.brokenmoon.redcontrol.blocks;
import com.mojang.serialization.MapCodec;
import net.brokenmoon.redcontrol.RedControl;
import net.brokenmoon.redcontrol.blockentities.DriveEntity;
import net.brokenmoon.redcontrol.blockentities.MonitorEntity;
import net.minecraft.block.BlockState;
import net.minecraft.block.BlockWithEntity;
import net.minecraft.block.entity.BlockEntity;

@ -1,60 +0,0 @@
package net.brokenmoon.redcontrol.blocks;
import com.mojang.serialization.MapCodec;
import net.brokenmoon.redcontrol.RedControl;
import net.brokenmoon.redcontrol.RedControlNetworking;
import net.brokenmoon.redcontrol.blockentities.MonitorEntity;
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs;
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking;
import net.minecraft.block.Block;
import net.minecraft.block.BlockEntityProvider;
import net.minecraft.block.BlockState;
import net.minecraft.block.BlockWithEntity;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;
public class MonitorBlock extends NetworkCarrier {
public MonitorBlock(Settings settings) {
super(settings);
}
@Override
protected MapCodec<? extends BlockWithEntity> getCodec() {
return null;
}
@Nullable
@Override
public BlockEntity createBlockEntity(BlockPos pos, BlockState state) {
return new MonitorEntity(pos, state);
}
@Override
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) {
if (!world.isClient) {
if (player.getStackInHand(hand).getItem() == RedControl.SQUEAKY_HAMMER) {
super.onUse(state,world,pos,player,hand,hit);
MonitorEntity monitor = (MonitorEntity) world.getBlockEntity(pos);
player.sendMessage(Text.literal(String.valueOf(monitor.getBus().hashCode())), false);
String[] text = monitor.getText();
for (String s : text) {
player.sendMessage(Text.literal(s), false);
}
}
PacketByteBuf byteBuf = PacketByteBufs.create();
byteBuf.writeBlockPos(pos);
ServerPlayNetworking.send((ServerPlayerEntity) player, RedControlNetworking.MONITOR_PACKET_ID,byteBuf);
}
return ActionResult.SUCCESS;
}
}

@ -0,0 +1,220 @@
package net.brokenmoon.redcontrol.blocks
import com.mojang.serialization.MapCodec
import net.brokenmoon.redcontrol.RedControl
import net.brokenmoon.redcontrol.RedControlNetworking
import net.brokenmoon.redcontrol.blockentities.Peripheral
import net.brokenmoon.redcontrol.util.unsigned
import net.fabricmc.fabric.api.networking.v1.PacketByteBufs
import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking
import net.minecraft.block.BlockState
import net.minecraft.block.BlockWithEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.nbt.NbtCompound
import net.minecraft.server.network.ServerPlayerEntity
import net.minecraft.util.ActionResult
import net.minecraft.util.ActionResult.FAIL
import net.minecraft.util.ActionResult.SUCCESS
import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos
import net.minecraft.world.World
import java.io.FileNotFoundException
import kotlin.experimental.xor
class TerminalBlock(settings: Settings) : NetworkCarrier(settings) {
@Suppress("OVERRIDE_DEPRECATION")
override fun onUse(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hit: BlockHitResult): ActionResult {
if (world.getBlockEntity(pos) !is TerminalEntity) return FAIL
if (!world.isClient) {
val bbuf = PacketByteBufs.create()
bbuf.writeBlockPos(pos)
ServerPlayNetworking.send(player as ServerPlayerEntity,RedControlNetworking.MONITOR_PACKET_ID,bbuf)
}
return SUCCESS
}
override fun getCodec(): MapCodec<out BlockWithEntity?>? {
return null
}
override fun createBlockEntity(pos: BlockPos, state: BlockState) = TerminalEntity(pos, state)
}
class TerminalEntity(pos: BlockPos, state: BlockState) : Peripheral(RedControl.TERMINAL_BLOCK_ENTITY, pos, state,1) {
val screen = ByteArray(80 * 50) { 0x20 }
val charset = RedControl.images["charset.bin"]?.clone()?: throw FileNotFoundException("expected a charset.bin in images datapack")
val kb = ByteArray(16)
var command: Byte = 0
var row = 0
var cx = 0
var cy = 0
var cm = 2
var kbs = 0
var kbp = 0
var bx1 = 0
var by1 = 0
var bx2 = 0
var by2 = 0
var bw = 0
var bh = 0
var char = 0
fun pushKey(byte: Byte): Boolean {
return if ((kbp + 1) % 16 != kbs) {
kb[kbp] = byte
kbp = (kbp + 1) % 16
true
} else false
}
fun getIndices(x1: Int, y1: Int, w: Int, h: Int): Sequence<Int> = sequence {
for (i in 0 until h) for (j in 0 until w) {
val x = j + x1
val y = i + y1
if (x in 0 until 80 && y in 0 until 60)
yield(x + 80 * y)
}
}
override fun read(address: Int): Int = readData(address.toByte()).toInt()
override fun update() {
val data = this
var error = false
when (data.command.unsigned) {
1 -> data.getIndices(data.bx2, data.by2, data.bw, data.bh).forEach { data.screen[it] = data.bx1.toByte() }
2 -> data.getIndices(data.bx2, data.by2, data.bw, data.bh).forEach { data.screen[it] = data.screen[it] xor 0x80.toByte() }
3 -> data.getIndices(data.bx2, data.by2, data.bw, data.bh).zip(data.getIndices(data.bx1, data.by1, data.bw, data.bh)).forEach { (dest, src) -> data.screen[dest] = data.screen[src] }
4 -> RedControl.images["charset.bin"]!!.copyInto(data.charset)
255 -> Unit
else -> error = true
}
if (data.command in 1..4) world?.updateListeners(pos, cachedState, cachedState, 3)
data.command = if (error) -1 else 0
}
override fun write(address: Int, data: Int) = storeData(address.toByte(),data.toByte())
private fun readData(at: Byte): Byte {
return when (val at = at.unsigned) {
0x00 -> row.toByte()
0x01 -> cx.toByte()
0x02 -> cy.toByte()
0x03 -> cm.toByte()
0x04 -> kbs.toByte()
0x05 -> kbp.toByte()
0x06 -> kb[kbs]
0x07 -> command
0x08 -> bx1.toByte()
0x09 -> by1.toByte()
0x0A -> bx2.toByte()
0x0B -> by2.toByte()
0x0C -> bw.toByte()
0x0D -> bh.toByte()
0x0E -> char.toByte()
in 0x10..0x5F -> screen[row * 80 + at - 0x10]
in 0x60..0x67 -> charset[char * 8 + at - 0x60]
else -> 0
}
}
private fun storeData(at: Byte, data: Byte) {
when (val at = at.unsigned) {
0x00 -> row = data.unsigned % 50
0x01 -> cx = data.unsigned % 80
0x02 -> cy = data.unsigned % 50
0x03 -> cm = data.unsigned % 3
0x04 -> kbs = data.unsigned % 16
0x05 -> kbp = data.unsigned % 16
0x06 -> kb[kbs] = data
0x07 -> command = data
0x08 -> bx1 = data.unsigned % 80
0x09 -> by1 = data.unsigned % 50
0x0A -> bx2 = data.unsigned % 80
0x0B -> by2 = data.unsigned % 50
0x0C -> bw = data.unsigned
0x0D -> bh = data.unsigned
0x0E -> char = data.unsigned
in 0x10..0x5F -> screen[row * 80 + at - 0x10] = data
in 0x60..0x67 -> charset[char * 8 + at - 0x60] = data
}
val needsClientUpdate = at.unsigned in setOf(0x01, 0x02, 0x03) + (0x10..0x67)
if (needsClientUpdate)
getWorld()?.updateListeners(getPos(), cachedState, cachedState, 3)
markDirty()
}
override fun toInitialChunkDataNbt(): NbtCompound {
val tag = super.toInitialChunkDataNbt()
// these are big, TODO: only send changed data
tag.putByteArray("screen", screen)
tag.putByteArray("charset", charset)
tag.putByte("cx", cx.toByte())
tag.putByte("cy", cy.toByte())
tag.putByte("cm", cm.toByte())
return tag
}
override fun writeNbt(tag: NbtCompound) {
super.writeNbt(tag)
tag.putByteArray("screen", screen)
tag.putByteArray("charset", charset)
tag.putByteArray("kb", kb)
tag.putByte("command", command)
tag.putByte("row", row.toByte())
tag.putByte("cx", cx.toByte())
tag.putByte("cy", cy.toByte())
tag.putByte("cm", cm.toByte())
tag.putByte("kbs", kbs.toByte())
tag.putByte("kbp", kbp.toByte())
tag.putByte("bx1", bx1.toByte())
tag.putByte("by1", by1.toByte())
tag.putByte("bx2", bx2.toByte())
tag.putByte("by2", by2.toByte())
tag.putByte("bw", bw.toByte())
tag.putByte("bh", bh.toByte())
tag.putByte("char", char.toByte())
}
override fun readNbt(tag: NbtCompound) {
super.readNbt(tag)
val world = getWorld()
tag.getByteArray("screen").copyInto(screen)
tag.getByteArray("charset").copyInto(charset)
cx = tag.getByte("cx").unsigned
cy = tag.getByte("cy").unsigned
cm = tag.getByte("cm").unsigned
if (world == null || !world.isClient) {
tag.getByteArray("screen").copyInto(screen)
tag.getByteArray("charset").copyInto(charset)
tag.getByteArray("kb").copyInto(kb)
command = tag.getByte("command")
row = tag.getByte("row").unsigned
kbs = tag.getByte("kbs").unsigned
kbp = tag.getByte("kbp").unsigned
bx1 = tag.getByte("bx1").unsigned
by1 = tag.getByte("by1").unsigned
bx2 = tag.getByte("bx2").unsigned
by2 = tag.getByte("by2").unsigned
bw = tag.getByte("bw").unsigned
bh = tag.getByte("bh").unsigned
char = tag.getByte("char").unsigned
}
}
}

@ -0,0 +1,24 @@
package net.brokenmoon.redcontrol.util
val Byte.unsigned: Int
get() = this.toInt() and 0xFF
val Short.unsigned: Int
get() = this.toInt() and 0xFFFF
val Int.unsigned: Long
get() = this.toLong() and 0xFFFFFFFF
infix fun Int.pmod(i: Int): Int = (this % i).let { if (it < 0) it + i else it }
infix fun Long.pmod(i: Int): Int = (this % i).let { if (it < 0) (it + i).toInt() else it.toInt() }
infix fun Long.pmod(l: Long): Long = (this % l).let { if (it < 0) it + l else it }
infix fun Byte.pmod(i: Int): Byte = (this % i).let { if (it < 0) (it + i).toByte() else it.toByte() }
infix fun Byte.shr(i: Int): Byte = (this.toInt() shr i).toByte()
infix fun Byte.ushr(i: Int): Byte = (this.unsigned ushr i).toByte()
infix fun Byte.shl(i: Int): Byte = (this.toInt() shl i).toByte()
infix fun Short.shr(i: Int): Short = (this.toInt() shr i).toShort()
infix fun Short.ushr(i: Int): Short = (this.unsigned ushr i).toShort()
infix fun Short.shl(i: Int): Short = (this.toInt() shl i).toShort()

@ -0,0 +1,64 @@
#version 330 core
#define SCREEN_WIDTH 80
#define SCREEN_HEIGHT 50
#define BGCOLOR vec3(0.09, 0.07, 0)
#define FGCOLOR vec3(0.78, 0.57, 0.01)
uniform usampler2D charset;
uniform usampler2D screen;
in vec2 f_uv;
out vec4 fragColor;
float get_pixel(in ivec2 px) {
// where is this character on the screen? (0,0) - (SCREEN_WIDTH,SCREEN_HEIGHT)
ivec2 char = px / 8;
// which pixel of this character is this? (0,0)-(8,8)
ivec2 chPixel = px % 8;
// which character is this? 0-255
int chIndex = int(texelFetch(screen, char, 0).x);
// the bitmap of the currently drawing line of the character
int lineData = int(texelFetch(charset, ivec2(chPixel.y, chIndex), 0).x);
return float((lineData >> (7 - chPixel.x)) & 1);
}
float get_pixel_with_fx(in vec2 screenPos) {
ivec2 px = ivec2(screenPos);
vec2 partial = fract(screenPos);
float strength = get_pixel(px);
float x = 0;
for (int dist = 1; dist < 6; dist++) {
float f = get_pixel(px - ivec2(dist, 0)) * 0.3;
if (f > 0) {
x = f * pow(0.5, dist + partial.x - 1);
break;
}
}
strength = min(1, strength + x);
if (px.y % 2 == 0) strength *= 0.9;
strength *= mix(0.25, 1, sin(partial.y * 3.141592654));
strength *= dot(vec3(0, 0, 1), normalize(vec3(px - 0.5 * vec2(SCREEN_WIDTH * 8, SCREEN_HEIGHT * 8), 300)));
return strength;
}
void main() {
vec2 screenPos = vec2(f_uv.x * SCREEN_WIDTH * 8, f_uv.y * SCREEN_HEIGHT * 8);
float strength = get_pixel_with_fx(screenPos);
vec3 color = mix(BGCOLOR, FGCOLOR, strength);
fragColor = vec4(color, 1);
}

@ -0,0 +1,13 @@
#version 330 core
in vec3 xyz;
in vec2 uv;
out vec2 f_uv;
uniform mat4 mvp;
void main() {
f_uv = uv;
gl_Position = mvp * vec4(xyz, 1);
}
Loading…
Cancel
Save