diff --git a/gradle.properties b/gradle.properties index 419f0d0..efad267 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,10 +5,10 @@ mod_version = 1.0.0 org.gradle.jvmargs = -Xmx1G # Versions -minecraft_version = 1.21.3 -yarn_mappings = 1.21.3+build.2 +minecraft_version = 1.21.4 +yarn_mappings = 1.21.4+build.2 loader_version = 0.16.9 -fabric_version = 0.110.0+1.21.3 +fabric_version = 0.112.0+1.21.4 -plasmid_version = 0.6.1+1.21.3 +plasmid_version = 0.6.2+1.21.4 wasmtime_version = 0.18.0 diff --git a/src/main/java/io/github/haykam821/consolebox/game/ConsoleBoxGame.java b/src/main/java/io/github/haykam821/consolebox/game/ConsoleBoxGame.java index 86bd2a6..b185fa2 100644 --- a/src/main/java/io/github/haykam821/consolebox/game/ConsoleBoxGame.java +++ b/src/main/java/io/github/haykam821/consolebox/game/ConsoleBoxGame.java @@ -11,12 +11,11 @@ import net.minecraft.entity.effect.StatusEffectInstance; import net.minecraft.entity.effect.StatusEffects; import net.minecraft.entity.passive.MuleEntity; -import net.minecraft.entity.player.PlayerPosition; import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.c2s.play.PlayerInputC2SPacket; +import net.minecraft.network.packet.c2s.play.PlayerLoadedC2SPacket; import net.minecraft.network.packet.s2c.play.GameStateChangeS2CPacket; -import net.minecraft.network.packet.s2c.play.PlayerPositionLookS2CPacket; -import net.minecraft.network.packet.s2c.play.PositionFlag; +import net.minecraft.network.packet.s2c.play.SetCameraEntityS2CPacket; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; @@ -24,6 +23,8 @@ import net.minecraft.util.math.Direction; import net.minecraft.util.math.Vec3d; import net.minecraft.world.GameMode; +import net.minecraft.world.dimension.DimensionType; +import net.minecraft.world.dimension.DimensionTypes; import xyz.nucleoid.fantasy.RuntimeWorldConfig; import xyz.nucleoid.fantasy.util.VoidChunkGenerator; import xyz.nucleoid.plasmid.api.game.*; @@ -39,27 +40,24 @@ import xyz.nucleoid.stimuli.event.player.PlayerDamageEvent; import xyz.nucleoid.stimuli.event.player.PlayerDeathEvent; -import java.util.Set; - public class ConsoleBoxGame implements GamePlayerEvents.Add, GameActivityEvents.Destroy, GameActivityEvents.Tick, GameActivityEvents.Enable, GamePlayerEvents.Remove, GamePlayerEvents.Accept, PlayerDamageEvent, PlayerDeathEvent, PlayerC2SPacketEvent { private final Thread thread; - private final GameSpace gameSpace; private final ServerWorld world; private final ConsoleBoxConfig config; - private final GameCanvas canvas; private final VirtualDisplay display; - + private final Entity cameraEntity; private final ServerPlayerEntity[] players = new ServerPlayerEntity[4]; private volatile boolean runs = true; private int playerCount = 0; - public ConsoleBoxGame(GameSpace gameSpace, ServerWorld world, ConsoleBoxConfig config, GameCanvas canvas, VirtualDisplay display) { + public ConsoleBoxGame(GameSpace gameSpace, ServerWorld world, ConsoleBoxConfig config, GameCanvas canvas, Entity cameraEntity, VirtualDisplay display) { this.gameSpace = gameSpace; this.world = world; this.config = config; + this.cameraEntity = cameraEntity; this.canvas = canvas; this.display = display; this.thread = new Thread(this::runThread); @@ -70,6 +68,7 @@ public static void setRules(GameActivity activity) { activity.deny(GameRuleType.BREAK_BLOCKS); activity.deny(GameRuleType.CRAFTING); activity.deny(GameRuleType.DISMOUNT_VEHICLE); + activity.deny(GameRuleType.STOP_SPECTATING_ENTITY); activity.deny(GameRuleType.FALL_DAMAGE); activity.deny(GameRuleType.FIRE_TICK); activity.deny(GameRuleType.FLUID_FLOW); @@ -92,6 +91,7 @@ public static GameOpenProcedure open(GameOpenContext context) ConsoleBoxConfig config = context.config(); RuntimeWorldConfig worldConfig = new RuntimeWorldConfig() + .setDimensionType(DimensionTypes.OVERWORLD_CAVES) .setGenerator(new VoidChunkGenerator(context.server())); @@ -103,8 +103,27 @@ public static GameOpenProcedure open(GameOpenContext context) .invisible() .build(); - ConsoleBoxGame phase = new ConsoleBoxGame(activity.getGameSpace(), world, config, canvas, display); - audioController.setOutput(phase); + var camera = EntityType.ITEM_DISPLAY.create(world, SpawnReason.LOAD); + assert camera != null; + camera.setInvisible(true); + camera.setPosition(canvas.getSpawnPos()); + camera.setYaw(canvas.getSpawnAngle()); + world.spawnEntity(camera); + + var leftAudio = EntityType.ITEM_DISPLAY.create(world, SpawnReason.LOAD); + assert leftAudio != null; + leftAudio.setInvisible(true); + leftAudio.setPosition(canvas.getSpawnPos().add(2, 0, 0)); + world.spawnEntity(leftAudio); + + var rightAudio = EntityType.ITEM_DISPLAY.create(world, SpawnReason.LOAD); + assert rightAudio != null; + rightAudio.setInvisible(true); + rightAudio.setPosition(canvas.getSpawnPos().add(-2, 0, 0)); + world.spawnEntity(rightAudio); + + ConsoleBoxGame phase = new ConsoleBoxGame(activity.getGameSpace(), world, config, canvas, camera, display); + audioController.setOutput(camera, leftAudio, rightAudio, activity.getGameSpace().getPlayers()::sendPacket); ConsoleBoxGame.setRules(activity); PlayerLimiter.addTo(activity, new PlayerLimiterConfig(phase.players.length)); @@ -130,6 +149,7 @@ public void onAddPlayer(ServerPlayerEntity player) { this.display.addPlayer(player); this.display.getCanvas().addPlayer(player); player.networkHandler.sendPacket(new GameStateChangeS2CPacket(GameStateChangeS2CPacket.GAME_MODE_CHANGED, GameMode.SPECTATOR.getId())); + player.networkHandler.sendPacket(new SetCameraEntityS2CPacket(this.cameraEntity)); } @Override @@ -161,6 +181,8 @@ public EventResult onPacket(ServerPlayerEntity player, Packet packet) { this.canvas.updateGamepad(id, input.forward(), input.left(), input.backward(), input.right(), isSneaking, isJumping); + } else if (packet instanceof PlayerLoadedC2SPacket) { + player.networkHandler.sendPacket(new SetCameraEntityS2CPacket(this.cameraEntity)); } return EventResult.PASS; @@ -168,13 +190,9 @@ public EventResult onPacket(ServerPlayerEntity player, Packet packet) { @Override public void onTick() { - for (var player : this.players) { - if (player != null) { - PlayerPosition pos = new PlayerPosition(Vec3d.ZERO, Vec3d.ZERO, 180, 0); - Set flags = Set.of(); - - player.networkHandler.sendPacket( - new PlayerPositionLookS2CPacket(0, pos, flags)); + for (var player : this.gameSpace.getPlayers()) { + if (player.getCameraEntity() != this.cameraEntity && this.cameraEntity.age > 2) { + player.setCameraEntity(this.cameraEntity); } } } @@ -213,9 +231,8 @@ public JoinAcceptorResult onAcceptPlayers(JoinAcceptor acceptor) { return acceptor.teleport(this.world, spawnPos).thenRunForEach(player -> { this.players[x] = player; this.playerCount++; - - this.spawnMount(spawnPos, this.players[x]); - this.initializePlayer(this.players[x], GameMode.ADVENTURE); + this.spawnMount(spawnPos.add(0, 10, 0), this.players[x]); + this.initializePlayer(this.players[x], GameMode.SPECTATOR); }); } } @@ -261,17 +278,18 @@ public void onRemovePlayer(ServerPlayerEntity player) { } // Utilities - private Entity spawnMount(Vec3d playerPos, ServerPlayerEntity player) { + private void spawnMount(Vec3d playerPos, ServerPlayerEntity player) { MuleEntity mount = EntityType.MULE.create(this.world, SpawnReason.JOCKEY); mount.calculateDimensions(); double y = playerPos.getY() - 1.25f; - mount.setPos(playerPos.getX(), y, playerPos.getZ()); + mount.setPos(playerPos.getX(), y, playerPos.getZ() + 2); mount.setYaw(this.canvas.getSpawnAngle()); mount.setAiDisabled(true); mount.setNoGravity(true); mount.setSilent(true); mount.setPersistent(); + mount.getAttributeInstance(EntityAttributes.SCALE).setBaseValue(0); // Prevent mount from being visible mount.addStatusEffect(this.createInfiniteStatusEffect(StatusEffects.INVISIBILITY)); @@ -283,7 +301,6 @@ private Entity spawnMount(Vec3d playerPos, ServerPlayerEntity player) { this.world.spawnEntity(mount); player.startRiding(mount, true); - return null; } private void initializePlayer(ServerPlayerEntity player, GameMode gameMode) { diff --git a/src/main/java/io/github/haykam821/consolebox/game/GameCanvas.java b/src/main/java/io/github/haykam821/consolebox/game/GameCanvas.java index 19bdb23..99ff2ea 100644 --- a/src/main/java/io/github/haykam821/consolebox/game/GameCanvas.java +++ b/src/main/java/io/github/haykam821/consolebox/game/GameCanvas.java @@ -6,6 +6,8 @@ import io.github.haykam821.consolebox.ConsoleBox; import io.github.haykam821.consolebox.game.audio.AudioChannel; import io.github.haykam821.consolebox.game.audio.AudioController; +import io.github.haykam821.consolebox.game.audio.ToneDuty; +import io.github.haykam821.consolebox.game.audio.TonePan; import io.github.haykam821.consolebox.game.palette.GamePalette; import io.github.haykam821.consolebox.game.render.FramebufferRendering; import io.github.kawamuray.wasmtime.Module; @@ -22,8 +24,6 @@ import org.slf4j.LoggerFactory; import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -33,26 +33,28 @@ public class GameCanvas { private static final Logger LOGGER = LoggerFactory.getLogger("GameCanvas"); - private static final CanvasImage BACKGROUND; + private static final CanvasImage DEFAULT_BACKGROUND = readImage("default_background"); + private static final CanvasImage DEFAULT_OVERLAY = readImage("default_overlay"); + private static final int BACKGROUND_SCALE = 2; - static { + private static CanvasImage readImage(String path) { CanvasImage temp; try { temp = CanvasImage.from(ImageIO.read( - Files.newInputStream(FabricLoader.getInstance().getModContainer(ConsoleBox.MOD_ID).get().findPath("background.png").get()))); + Files.newInputStream(FabricLoader.getInstance().getModContainer(ConsoleBox.MOD_ID).get().findPath("data/consolebox/background/" + path + ".png").get()))); } catch (Throwable e) { - temp = null; + temp = new CanvasImage(128, 128); e.printStackTrace(); } - BACKGROUND = temp; + return temp; } private static final int RENDER_SCALE = 1; private static final int MAP_SIZE = FilledMapItem.field_30907; private static final int SECTION_SIZE = MathHelper.ceil(HardwareConstants.SCREEN_WIDTH * RENDER_SCALE / (double) MAP_SIZE); - private static final int SECTION_HEIGHT = 3; - private static final int SECTION_WIDTH = 4; + private static final int SECTION_HEIGHT = 6; + private static final int SECTION_WIDTH = 8; private static final Consumer0 EMPTY_CALLBACK = () -> { }; @@ -88,8 +90,25 @@ public GameCanvas(ConsoleBoxConfig config, AudioController audioController) { this.palette = new GamePalette(this.memory); this.canvas = DrawableCanvas.create(SECTION_WIDTH, SECTION_HEIGHT); CanvasUtils.clear(this.canvas, CanvasColor.GRAY_HIGH); - if (BACKGROUND != null) { - CanvasUtils.draw(this.canvas, 0, 0, BACKGROUND); + if (DEFAULT_BACKGROUND != null) { + var background = DEFAULT_BACKGROUND; + var width = background.getWidth() * BACKGROUND_SCALE; + var height = background.getHeight() * BACKGROUND_SCALE; + var repeatsX = Math.ceilDiv(this.canvas.getWidth(), width); + var repeatsY = Math.ceilDiv(this.canvas.getHeight(), height); + + for (int x = 0; x < repeatsX; x++) { + for (int y = 0; y < repeatsY; y++) { + CanvasUtils.draw(this.canvas, x * width, y * height, width, height, background); + } + } + } + + if (DEFAULT_OVERLAY != null) { + var background = DEFAULT_OVERLAY; + var width = background.getWidth() * BACKGROUND_SCALE; + var height = background.getHeight() * BACKGROUND_SCALE; + CanvasUtils.draw(this.canvas, this.canvas.getWidth() / 2 - width / 2, this.canvas.getHeight() / 2 - height / 2, width, height, background); } var text = """ @@ -226,23 +245,23 @@ private void rect(int x, int y, int width, int height) { FramebufferRendering.drawRect(buffer, fillColor, strokeColor, x, y, width, height); } - private void drawText(String string, int x, int y) { + // This function needs to work on raw bytes, as Java strips invalid chars + private void drawText(byte[] string, int x, int y) { ByteBuffer buffer = this.memory.getFramebuffer(); int drawColors = this.memory.readDrawColors(); - FramebufferRendering.drawText(buffer, drawColors, string, x, y); } private void text(int string, int x, int y) { - this.drawText(this.memory.readString(string), x, y); + this.drawText(this.memory.readStringRaw(string), x, y); } private void textUtf8(int string, int length, int x, int y) { - this.drawText(this.memory.readUnterminatedString(string, length, StandardCharsets.UTF_8), x, y); + this.drawText(this.memory.readUnterminatedStringRaw8(string, length), x, y); } private void textUtf16(int string, int length, int x, int y) { - this.drawText(this.memory.readUnterminatedString(string, length, StandardCharsets.UTF_16LE), x, y); + this.drawText(this.memory.readUnterminatedStringRaw16LE(string, length), x, y); } private void tone(int frequency, int duration, int volume, int flags) { @@ -253,12 +272,30 @@ private void tone(int frequency, int duration, int volume, int flags) { default -> AudioChannel.NOISE; }; + var duty = switch ((flags >> 2) & 0b11) { + case 0 -> ToneDuty.MODE_12_5; + case 1 -> ToneDuty.MODE_25; + case 2 -> ToneDuty.MODE_50; + default -> ToneDuty.MODE_75; + }; + + var pan = switch ((flags >> 4) & 0b11) { + case 1 -> TonePan.LEFT; + case 2 -> TonePan.RIGHT; + default -> TonePan.CENTER; + }; + + var freq1 = frequency & 0xFFFF; var freq2 = (frequency >> 16) & 0xFFFF; var sustainTime = duration & 0xFF; - this.audioController.playSound(channel, freq1, sustainTime); + var volumeActual = volume & 0xFF; + var volumePeak = (volume >> 8) & 0xFF; + + + this.audioController.playSound(channel, duty, pan, freq1, freq2, sustainTime, volumeActual, volumePeak); // Intentionally empty as sound is unsupported } @@ -400,13 +437,13 @@ public void start() { } public BlockPos getDisplayPos() { - return new BlockPos(-SECTION_WIDTH, SECTION_HEIGHT, 0); + return new BlockPos(-SECTION_WIDTH, SECTION_HEIGHT + 100, 0); } public Vec3d getSpawnPos() { BlockPos displayPos = this.getDisplayPos(); - return new Vec3d(displayPos.getX() + SECTION_WIDTH * 0.5, displayPos.getY() - SECTION_HEIGHT * 0.5f, 1.1); + return new Vec3d(displayPos.getX() + SECTION_WIDTH * 0.5, displayPos.getY() - SECTION_HEIGHT * 0.5f + 1, 1.5); } public int getSpawnAngle() { diff --git a/src/main/java/io/github/haykam821/consolebox/game/GameMemory.java b/src/main/java/io/github/haykam821/consolebox/game/GameMemory.java index 35a68f2..7a09230 100644 --- a/src/main/java/io/github/haykam821/consolebox/game/GameMemory.java +++ b/src/main/java/io/github/haykam821/consolebox/game/GameMemory.java @@ -79,6 +79,9 @@ public boolean readSystemPreserveFramebuffer() { } public String readString(int start) { + return new String(readStringRaw(start), StandardCharsets.US_ASCII); + } + public byte[] readStringRaw(int start) { int length = 0; while (this.buffer.hasRemaining()) { @@ -87,14 +90,29 @@ public String readString(int start) { if (character == 0x00) { byte[] bytes = new byte[length]; this.buffer.get(start, bytes, 0, length); - - return new String(bytes, StandardCharsets.US_ASCII); + return bytes; } else { length += 1; } } - return ""; + return new byte[0]; + } + + public byte[] readUnterminatedStringRaw8(int start, int length) { + var bytes = new byte[length]; + for (int i = 0; i < length; i++) { + bytes[i] = this.buffer.get(start + i); + } + return bytes; + } + + public byte[] readUnterminatedStringRaw16LE(int start, int length) { + var bytes = new byte[length]; + for (int i = 0; i < length; i++) { + bytes[i] = this.buffer.get(start + i * 2); + } + return bytes; } public String readUnterminatedString(int start, int length, Charset charset) { diff --git a/src/main/java/io/github/haykam821/consolebox/game/audio/AudioController.java b/src/main/java/io/github/haykam821/consolebox/game/audio/AudioController.java index bf8722a..64ac390 100644 --- a/src/main/java/io/github/haykam821/consolebox/game/audio/AudioController.java +++ b/src/main/java/io/github/haykam821/consolebox/game/audio/AudioController.java @@ -1,7 +1,7 @@ package io.github.haykam821.consolebox.game.audio; public interface AudioController { - AudioController NOOP = (a, b, c) -> {}; + AudioController NOOP = (a, duty, pan, b, c, sustainTime, volumeActual, volumePeak) -> {}; - void playSound(AudioChannel channel, float freq1, int sustainTimeMs); + void playSound(AudioChannel channel, ToneDuty duty, TonePan pan, int freq1, int freq2, int sustainTime, int volumeActual, int volumePeak); } diff --git a/src/main/java/io/github/haykam821/consolebox/game/audio/BaseAudioController.java b/src/main/java/io/github/haykam821/consolebox/game/audio/BaseAudioController.java index 6ef7e24..ec33564 100644 --- a/src/main/java/io/github/haykam821/consolebox/game/audio/BaseAudioController.java +++ b/src/main/java/io/github/haykam821/consolebox/game/audio/BaseAudioController.java @@ -1,12 +1,45 @@ package io.github.haykam821.consolebox.game.audio; -import io.github.haykam821.consolebox.game.ConsoleBoxGame; +import net.minecraft.entity.Entity; +import net.minecraft.network.packet.Packet; +import net.minecraft.network.packet.s2c.play.PlaySoundFromEntityS2CPacket; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; + +import java.util.function.Consumer; public class BaseAudioController implements AudioController { + private Consumer> consumer = (x) -> {}; + private Entity center; + private Entity left; + private Entity right; + @Override - public void playSound(AudioChannel channel, float pitch, int sustainTimeMs) { + public void playSound(AudioChannel channel, ToneDuty duty, TonePan pan, int freq1, int freq2, int sustainTime, int volumeActual, int volumePeak) { + assert center != null; + assert left != null; + assert right != null; + var sound = switch (channel) { + case PULSE_1 -> SoundEvents.BLOCK_NOTE_BLOCK_FLUTE; + case PULSE_2 -> SoundEvents.BLOCK_NOTE_BLOCK_HARP; + case TRIANGLE -> SoundEvents.BLOCK_NOTE_BLOCK_BASS; + case NOISE -> SoundEvents.BLOCK_NOTE_BLOCK_SNARE; + }; + var pitch = freq1 / 500f; + + var volume = volumeActual / 100f; + + consumer.accept(new PlaySoundFromEntityS2CPacket(sound, SoundCategory.VOICE, switch (pan) { + case CENTER -> this.center; + case RIGHT -> this.right; + case LEFT -> this.left; + }, volume, pitch, 1)); } - public void setOutput(ConsoleBoxGame phase) { + public void setOutput(Entity center, Entity left, Entity right, Consumer> consumer) { + this.center = center; + this.left = left; + this.right = right; + this.consumer = consumer; } } diff --git a/src/main/java/io/github/haykam821/consolebox/game/audio/ToneDuty.java b/src/main/java/io/github/haykam821/consolebox/game/audio/ToneDuty.java new file mode 100644 index 0000000..a7ec749 --- /dev/null +++ b/src/main/java/io/github/haykam821/consolebox/game/audio/ToneDuty.java @@ -0,0 +1,8 @@ +package io.github.haykam821.consolebox.game.audio; + +public enum ToneDuty { + MODE_12_5, + MODE_25, + MODE_50, + MODE_75, +} diff --git a/src/main/java/io/github/haykam821/consolebox/game/audio/TonePan.java b/src/main/java/io/github/haykam821/consolebox/game/audio/TonePan.java new file mode 100644 index 0000000..86a2489 --- /dev/null +++ b/src/main/java/io/github/haykam821/consolebox/game/audio/TonePan.java @@ -0,0 +1,7 @@ +package io.github.haykam821.consolebox.game.audio; + +public enum TonePan { + CENTER, + LEFT, + RIGHT +} diff --git a/src/main/java/io/github/haykam821/consolebox/game/render/FramebufferRendering.java b/src/main/java/io/github/haykam821/consolebox/game/render/FramebufferRendering.java index 83edf81..e46cc89 100644 --- a/src/main/java/io/github/haykam821/consolebox/game/render/FramebufferRendering.java +++ b/src/main/java/io/github/haykam821/consolebox/game/render/FramebufferRendering.java @@ -283,11 +283,11 @@ public static void drawSprite(ByteBuffer buffer, int drawColors, ByteBuffer spri } } - public static void drawText(ByteBuffer buffer, int drawColors, String string, int x, int y) { + public static void drawText(ByteBuffer buffer, int drawColors, byte[] string, int x, int y) { int currentX = x; - for (int index = 0; index < string.length(); index++) { - char character = string.charAt(index); + for (int index = 0; index < string.length; index++) { + int character = Byte.toUnsignedInt(string[index]); if (character == '\0') { return; diff --git a/src/main/java/io/github/haykam821/consolebox/game/render/GameFont.java b/src/main/java/io/github/haykam821/consolebox/game/render/GameFont.java index 96cf237..d767b24 100644 --- a/src/main/java/io/github/haykam821/consolebox/game/render/GameFont.java +++ b/src/main/java/io/github/haykam821/consolebox/game/render/GameFont.java @@ -1,10 +1,12 @@ package io.github.haykam821.consolebox.game.render; +import net.minecraft.util.Util; + import java.nio.ByteBuffer; public final class GameFont { - protected static final int CHARACTER_WIDTH = 8; - protected static final int CHARACTER_HEIGHT = CHARACTER_WIDTH; + static final int CHARACTER_WIDTH = 8; + static final int CHARACTER_HEIGHT = CHARACTER_WIDTH; /** * The packed font spritesheet. @@ -13,7 +15,7 @@ public final class GameFont { * official WASM-4 runtimes, * which are licensed under the ISC license. */ - protected static final ByteBuffer FONT = ByteBuffer.wrap(new byte[] { + static final ByteBuffer FONT = ByteBuffer.wrap(new byte[] { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xC7, (byte) 0xC7, (byte) 0xC7, (byte) 0xCF, (byte) 0xCF, (byte) 0xFF, (byte) 0xCF, (byte) 0xFF, (byte) 0x93, (byte) 0x93, (byte) 0x93, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, diff --git a/src/main/resources/background.png b/src/main/resources/data/consolebox/background/nucleoid.png similarity index 100% rename from src/main/resources/background.png rename to src/main/resources/data/consolebox/background/nucleoid.png