diff --git a/module/Dronemode.lua b/module/Dronemode.lua index 67e08c7..f19f6d2 100644 --- a/module/Dronemode.lua +++ b/module/Dronemode.lua @@ -1,43 +1,34 @@ name = "Drone mode" description = "Its a drone mode, not freecam :D" author = "zebedelu" -version = 3.0 +version = 4.0 -- ========================================== -- 1. CONSTANTS AND STATE -- ========================================== --- Internal render resolution. Each ray becomes one screen tile. local W, H = 128, 64 local TILE_W, TILE_H = 15, 16 local MAX_RAY_STEPS = 60 --- Drone camera position and orientation. local camX, camY, camZ = 0, 64, 0 local centerX, centerY, centerZ = 0, 64, 0 local yaw, pitch = 0, 0 local camInitialized = false --- Real player position, cached outside RenderEvent. Flarial explicitly marks --- player API access from RenderEvent as unsafe. local playerX, playerY, playerZ = 0, 0, 0 local fpX, fpY, fpZ = 0, 0, 0 --- Render and scan state. local renderVisible = false local scanCompleted = false local raycastDirty = true --- Movement is expressed per second, so it no longer changes with framerate. local keys = {} local MOVE_SPEED = 8.0 local FAST_SPEED = 20.0 local SLOW_SPEED = 2.0 local ROTATE_SPEED = 3.9 --- The cache uses one flat integer key per voxel. Air is not stored at all. --- A procedural shell cursor eliminates millions of coordinate tables, while --- the flat cache eliminates nested hash tables at large radii. local worldCache = {} local scanIndex = 0 local scanRadius, scanFace = 0, 0 @@ -50,34 +41,29 @@ local worldMinX, worldMaxX = 0, 0 local worldMinY, worldMaxY = 0, 0 local worldMinZ, worldMaxZ = 0, 0 --- Rising-edge state for configurable keybinds. local uiKeyWasDown = false local rescanKeyWasDown = false local teleportKeyWasDown = false --- Main settings. local RADIUS = 30 local BLOCKS_PER_SECOND = 5000 local MAX_SCAN_BATCH = 2048 --- Raycasting is capped at 30 Hz. Rendering reuses the most recent run list, --- and a static completed scene does not raycast again until something changes. local RAYCAST_INTERVAL_MS = 1000 / 30 local lastRaycastTime = 0 --- Cached pixel colors and two-dimensionally merged draw runs. local pixelColors = {} local drawRuns = {} local drawRunCount = 0 local activeRunsA, activeRunsB = {}, {} --- Cache hot functions to avoid repeated global/table lookups. local m_floor = math.floor local m_abs = math.abs local m_cos = math.cos local m_sin = math.sin local m_min = math.min local m_max = math.max +local m_tan = math.tan local getTime = util.time local getBlock = world.getBlock local getPlayerPosition = player.position @@ -85,6 +71,11 @@ local notify = client.notify local getScreenName = client.getScreenName local getDeltaTime = ImGui.GetDeltaTime local getForegroundDrawList = ImGui.GetForegroundDrawList +local getDisplaySize = ImGui.GetDisplaySize + +-- ponytail: 1 = Low Quality, 2 = High Quality. Drives all branching. +local rendererMode = 2 +local OneRenderWarnShowed = false -- ========================================== -- 2. SETTINGS @@ -99,37 +90,22 @@ local OpenDroneUIKey = settings.addKeybind("Open Drone UI", "Open the drone UI w local RescanKey = settings.addKeybind("Rescan", "Rescan around the current camera position", "u") local TeleportToPlayerKey = settings.addKeybind("TP to player", "Move the camera to the player and restart the scan", "i") +settings.addHeader("Renderer Mode") +local LowQualityToggle = settings.addToggle("Low Quality - High Speed", "Uses pixelated raycasting for maximum FPS", false) +local HighQualityToggle = settings.addToggle("High Quality - Low Speed", "Uses smooth 3D polygons for better visuals", true) + -- ========================================== -- 3. KEY MAPPING -- ========================================== local keyMap = { - -- Letters: W, A, S, D (movement). - [87] = "w", [17] = "w", -- W (17 = LWJGL KEY_W) - [65] = "a", [30] = "a", -- A - [83] = "s", [31] = "s", -- S - [68] = "d", [32] = "d", -- D - - -- Other letters (fallback mappings). - [90] = "z", [44] = "z", -- Z - [67] = "c", [46] = "c", -- C - [88] = "x", [45] = "x", -- X - - -- Modifiers. - [32] = "space", -- ASCII space. This intentionally wins over LWJGL D. - [57] = "space", -- LWJGL space. - - [16] = "shift", [42] = "shift", -- Left Shift. - [54] = "shift", -- Right Shift. - [340] = "shift", [344] = "shift", -- Shift (GLFW) - - -- 17 is LWJGL W and cannot also be used for Ctrl. - [29] = "ctrl", -- Left Ctrl. - [157] = "ctrl", -- Right Ctrl. - [341] = "ctrl", [345] = "ctrl", -- Ctrl (GLFW) - [162] = "ctrl", [163] = "ctrl", -- Ctrl (Windows VK) - - -- Arrow keys: camera rotation. + [87] = "w", [17] = "w", [65] = "a", [30] = "a", + [83] = "s", [31] = "s", [68] = "d", [32] = "d", + [90] = "z", [44] = "z", [67] = "c", [46] = "c", + [88] = "x", [45] = "x", + [32] = "space", [57] = "space", + [16] = "shift", [42] = "shift", [54] = "shift", [340] = "shift", [344] = "shift", + [29] = "ctrl", [157] = "ctrl", [341] = "ctrl", [345] = "ctrl", [162] = "ctrl", [163] = "ctrl", [265] = "up", [38] = "up", [200] = "up", [264] = "down", [40] = "down", [208] = "down", [263] = "left", [37] = "left", [203] = "left", @@ -144,8 +120,6 @@ local blockColors = { ["minecraft:stone"] = {125, 125, 125}, ["minecraft:granite"] = {132, 98, 78}, ["minecraft:polished_granite"] = {140, 104, 82}, ["minecraft:diorite"] = {173, 173, 173}, ["minecraft:polished_diorite"] = {180, 180, 180}, ["minecraft:andesite"] = {126, 126, 131}, ["minecraft:polished_andesite"] = {135, 135, 140}, ["minecraft:deepslate"] = {68, 68, 73}, ["minecraft:cobbled_deepslate"] = {75, 75, 80}, ["minecraft:polished_deepslate"] = {82, 82, 87}, ["minecraft:calcite"] = {200, 200, 190}, ["minecraft:tuff"] = {100, 100, 95}, ["minecraft:dripstone_block"] = {155, 145, 130}, ["minecraft:grass_block"] = {90, 168, 55}, ["minecraft:dirt"] = {134, 96, 67}, ["minecraft:coarse_dirt"] = {125, 90, 62}, ["minecraft:podzol"] = {110, 100, 70}, ["minecraft:rooted_dirt"] = {120, 85, 58}, ["minecraft:mud"] = {75, 60, 45}, ["minecraft:mud_bricks"] = {100, 80, 60}, ["minecraft:packed_mud"] = {85, 68, 50}, ["minecraft:cobblestone"] = {122, 122, 122}, ["minecraft:oak_planks"] = {168, 132, 88}, ["minecraft:spruce_planks"] = {120, 90, 60}, ["minecraft:birch_planks"] = {205, 185, 145}, ["minecraft:jungle_planks"] = {155, 120, 65}, ["minecraft:acacia_planks"] = {175, 125, 70}, ["minecraft:dark_oak_planks"] = {100, 75, 50}, ["minecraft:mangrove_planks"] = {140, 100, 65}, ["minecraft:cherry_planks"] = {215, 175, 155}, ["minecraft:bamboo_planks"] = {195, 170, 110}, ["minecraft:bamboo_mosaic"] = {185, 160, 100}, ["minecraft:oak_log"] = {108, 82, 55}, ["minecraft:spruce_log"] = {85, 65, 45}, ["minecraft:birch_log"] = {175, 155, 125}, ["minecraft:jungle_log"] = {95, 70, 35}, ["minecraft:acacia_log"] = {100, 65, 30}, ["minecraft:dark_oak_log"] = {70, 52, 35}, ["minecraft:mangrove_log"] = {80, 55, 35}, ["minecraft:cherry_log"] = {150, 100, 80}, ["minecraft:stripped_oak_log"] = {165, 135, 95}, ["minecraft:stripped_spruce_log"] = {140, 110, 75}, ["minecraft:stripped_birch_log"] = {200, 180, 145}, ["minecraft:stripped_jungle_log"] = {160, 130, 80}, ["minecraft:stripped_acacia_log"] = {170, 135, 85}, ["minecraft:stripped_dark_oak_log"] = {115, 90, 65}, ["minecraft:stripped_mangrove_log"] = {145, 115, 80}, ["minecraft:stripped_cherry_log"] = {195, 155, 135}, ["minecraft:oak_wood"] = {108, 82, 55}, ["minecraft:spruce_wood"] = {85, 65, 45}, ["minecraft:birch_wood"] = {175, 155, 125}, ["minecraft:jungle_wood"] = {95, 70, 35}, ["minecraft:acacia_wood"] = {100, 65, 30}, ["minecraft:dark_oak_wood"] = {70, 52, 35}, ["minecraft:mangrove_wood"] = {80, 55, 35}, ["minecraft:cherry_wood"] = {150, 100, 80}, ["minecraft:stripped_oak_wood"] = {165, 135, 95}, ["minecraft:stripped_spruce_wood"] = {140, 110, 75}, ["minecraft:stripped_birch_wood"] = {200, 180, 145}, ["minecraft:stripped_jungle_wood"] = {160, 130, 80}, ["minecraft:stripped_acacia_wood"] = {170, 135, 85}, ["minecraft:stripped_dark_oak_wood"] = {115, 90, 65}, ["minecraft:stripped_mangrove_wood"] = {145, 115, 80}, ["minecraft:stripped_cherry_wood"] = {195, 155, 135}, ["minecraft:oak_leaves"] = {55, 140, 45}, ["minecraft:spruce_leaves"] = {40, 75, 35}, ["minecraft:birch_leaves"] = {65, 155, 50}, ["minecraft:jungle_leaves"] = {35, 120, 25}, ["minecraft:acacia_leaves"] = {75, 145, 35}, ["minecraft:dark_oak_leaves"] = {45, 95, 30}, ["minecraft:mangrove_leaves"] = {50, 115, 40}, ["minecraft:cherry_leaves"] = {235, 160, 185}, ["minecraft:azalea_leaves"] = {45, 130, 55}, ["minecraft:flowering_azalea_leaves"] = {180, 100, 160}, ["minecraft:sand"] = {219, 211, 160}, ["minecraft:red_sand"] = {193, 118, 62}, ["minecraft:sandstone"] = {215, 205, 155}, ["minecraft:red_sandstone"] = {185, 110, 55}, ["minecraft:cut_sandstone"] = {215, 205, 155}, ["minecraft:cut_red_sandstone"] = {185, 110, 55}, ["minecraft:chiseled_sandstone"] = {210, 200, 150}, ["minecraft:chiseled_red_sandstone"] = {180, 105, 50}, ["minecraft:smooth_sandstone"] = {220, 212, 165}, ["minecraft:smooth_red_sandstone"] = {195, 120, 65}, ["minecraft:gravel"] = {136, 126, 126}, ["minecraft:flint"] = {100, 100, 105}, ["minecraft:coal_ore"] = {115, 115, 115}, ["minecraft:deepslate_coal_ore"] = {65, 65, 70}, ["minecraft:iron_ore"] = {130, 125, 120}, ["minecraft:deepslate_iron_ore"] = {75, 72, 70}, ["minecraft:copper_ore"] = {135, 120, 100}, ["minecraft:deepslate_copper_ore"] = {80, 72, 62}, ["minecraft:gold_ore"] = {140, 130, 100}, ["minecraft:deepslate_gold_ore"] = {85, 78, 62}, ["minecraft:redstone_ore"] = {140, 110, 110}, ["minecraft:deepslate_redstone_ore"] = {85, 68, 68}, ["minecraft:emerald_ore"] = {120, 140, 115}, ["minecraft:deepslate_emerald_ore"] = {72, 85, 72}, ["minecraft:lapis_ore"] = {110, 115, 140}, ["minecraft:deepslate_lapis_ore"] = {68, 70, 88}, ["minecraft:diamond_ore"] = {125, 130, 140}, ["minecraft:deepslate_diamond_ore"] = {75, 78, 88}, ["minecraft:nether_gold_ore"] = {95, 60, 60}, ["minecraft:raw_iron_block"] = {180, 160, 150}, ["minecraft:raw_copper_block"] = {185, 135, 95}, ["minecraft:raw_gold_block"] = {195, 175, 85}, ["minecraft:coal_block"] = {25, 25, 25}, ["minecraft:iron_block"] = {220, 220, 220}, ["minecraft:gold_block"] = {250, 225, 80}, ["minecraft:copper_block"] = {185, 120, 70}, ["minecraft:exposed_copper"] = {170, 130, 100}, ["minecraft:weathered_copper"] = {110, 110, 105}, ["minecraft:oxidized_copper"] = {75, 110, 105}, ["minecraft:cut_copper"] = {185, 120, 70}, ["minecraft:exposed_cut_copper"] = {170, 130, 100}, ["minecraft:weathered_cut_copper"] = {110, 110, 105}, ["minecraft:oxidized_cut_copper"] = {75, 110, 105}, ["minecraft:chiseled_copper"] = {180, 115, 65}, ["minecraft:exposed_chiseled_copper"] = {165, 125, 95}, ["minecraft:weathered_chiseled_copper"] = {105, 105, 100}, ["minecraft:oxidized_chiseled_copper"] = {70, 105, 100}, ["minecraft:copper_door"] = {185, 120, 70}, ["minecraft:exposed_copper_door"] = {170, 130, 100}, ["minecraft:weathered_copper_door"] = {110, 110, 105}, ["minecraft:oxidized_copper_door"] = {75, 110, 105}, ["minecraft:copper_trapdoor"] = {185, 120, 70}, ["minecraft:exposed_copper_trapdoor"] = {170, 130, 100}, ["minecraft:weathered_copper_trapdoor"] = {110, 110, 105}, ["minecraft:oxidized_copper_trapdoor"] = {75, 110, 105}, ["minecraft:copper_grate"] = {180, 115, 65}, ["minecraft:exposed_copper_grate"] = {165, 125, 95}, ["minecraft:weathered_copper_grate"] = {105, 105, 100}, ["minecraft:oxidized_copper_grate"] = {70, 105, 100}, ["minecraft:copper_bulb"] = {185, 120, 70}, ["minecraft:exposed_copper_bulb"] = {170, 130, 100}, ["minecraft:weathered_copper_bulb"] = {110, 110, 105}, ["minecraft:oxidized_copper_bulb"] = {75, 110, 105}, ["minecraft:waxed_copper_block"] = {185, 120, 70}, ["minecraft:waxed_exposed_copper"] = {170, 130, 100}, ["minecraft:waxed_weathered_copper"] = {110, 110, 105}, ["minecraft:waxed_oxidized_copper"] = {75, 110, 105}, ["minecraft:waxed_cut_copper"] = {185, 120, 70}, ["minecraft:waxed_exposed_cut_copper"] = {170, 130, 100}, ["minecraft:waxed_weathered_cut_copper"] = {110, 110, 105}, ["minecraft:waxed_oxidized_cut_copper"] = {75, 110, 105}, ["minecraft:waxed_chiseled_copper"] = {180, 115, 65}, ["minecraft:waxed_exposed_chiseled_copper"] = {165, 125, 95}, ["minecraft:waxed_weathered_chiseled_copper"] = {105, 105, 100}, ["minecraft:waxed_oxidized_chiseled_copper"] = {70, 105, 100}, ["minecraft:waxed_copper_door"] = {185, 120, 70}, ["minecraft:waxed_exposed_copper_door"] = {170, 130, 100}, ["minecraft:waxed_weathered_copper_door"] = {110, 110, 105}, ["minecraft:waxed_oxidized_copper_door"] = {75, 110, 105}, ["minecraft:waxed_copper_trapdoor"] = {185, 120, 70}, ["minecraft:waxed_exposed_copper_trapdoor"] = {170, 130, 100}, ["minecraft:waxed_weathered_copper_trapdoor"] = {110, 110, 105}, ["minecraft:waxed_oxidized_copper_trapdoor"] = {75, 110, 105}, ["minecraft:waxed_copper_grate"] = {180, 115, 65}, ["minecraft:waxed_exposed_copper_grate"] = {165, 125, 95}, ["minecraft:waxed_weathered_copper_grate"] = {105, 105, 100}, ["minecraft:waxed_oxidized_copper_grate"] = {70, 105, 100}, ["minecraft:waxed_copper_bulb"] = {185, 120, 70}, ["minecraft:waxed_exposed_copper_bulb"] = {170, 130, 100}, ["minecraft:waxed_weathered_copper_bulb"] = {110, 110, 105}, ["minecraft:waxed_oxidized_copper_bulb"] = {75, 110, 105}, ["minecraft:diamond_block"] = {90, 220, 220}, ["minecraft:lapis_block"] = {35, 55, 150}, ["minecraft:emerald_block"] = {45, 180, 80}, ["minecraft:redstone_block"] = {180, 30, 30}, ["minecraft:netherite_block"] = {55, 50, 50}, ["minecraft:obsidian"] = {20, 18, 25}, ["minecraft:crying_obsidian"] = {60, 30, 70}, ["minecraft:glowstone"] = {220, 200, 120}, ["minecraft:redstone_lamp"] = {160, 130, 100}, ["minecraft:sea_lantern"] = {150, 220, 225}, ["minecraft:torch"] = {220, 180, 100}, ["minecraft:soul_torch"] = {80, 130, 200}, ["minecraft:lantern"] = {180, 160, 120}, ["minecraft:soul_lantern"] = {70, 110, 170}, ["minecraft:campfire"] = {160, 130, 100}, ["minecraft:soul_campfire"] = {60, 100, 160}, ["minecraft:white_wool"] = {230, 230, 230}, ["minecraft:orange_wool"] = {220, 130, 50}, ["minecraft:magenta_wool"] = {175, 75, 175}, ["minecraft:light_blue_wool"] = {135, 185, 220}, ["minecraft:yellow_wool"] = {230, 210, 75}, ["minecraft:lime_wool"] = {115, 185, 75}, ["minecraft:pink_wool"] = {220, 150, 165}, ["minecraft:gray_wool"] = {100, 100, 100}, ["minecraft:light_gray_wool"] = {160, 160, 160}, ["minecraft:cyan_wool"] = {75, 175, 175}, ["minecraft:purple_wool"] = {120, 60, 160}, ["minecraft:blue_wool"] = {60, 65, 160}, ["minecraft:brown_wool"] = {120, 85, 60}, ["minecraft:green_wool"] = {75, 120, 55}, ["minecraft:red_wool"] = {170, 50, 50}, ["minecraft:black_wool"] = {30, 30, 30}, ["minecraft:white_concrete"] = {215, 215, 215}, ["minecraft:orange_concrete"] = {210, 120, 45}, ["minecraft:magenta_concrete"] = {165, 65, 165}, ["minecraft:light_blue_concrete"] = {125, 175, 210}, ["minecraft:yellow_concrete"] = {220, 200, 65}, ["minecraft:lime_concrete"] = {105, 175, 65}, ["minecraft:pink_concrete"] = {210, 140, 155}, ["minecraft:gray_concrete"] = {90, 90, 90}, ["minecraft:light_gray_concrete"] = {150, 150, 150}, ["minecraft:cyan_concrete"] = {65, 165, 165}, ["minecraft:purple_concrete"] = {110, 50, 150}, ["minecraft:blue_concrete"] = {50, 55, 150}, ["minecraft:brown_concrete"] = {110, 75, 50}, ["minecraft:green_concrete"] = {65, 110, 45}, ["minecraft:red_concrete"] = {160, 40, 40}, ["minecraft:black_concrete"] = {20, 20, 20}, ["minecraft:white_concrete_powder"] = {215, 215, 215}, ["minecraft:orange_concrete_powder"] = {210, 120, 45}, ["minecraft:magenta_concrete_powder"] = {165, 65, 165}, ["minecraft:light_blue_concrete_powder"] = {125, 175, 210}, ["minecraft:yellow_concrete_powder"] = {220, 200, 65}, ["minecraft:lime_concrete_powder"] = {105, 175, 65}, ["minecraft:pink_concrete_powder"] = {210, 140, 155}, ["minecraft:gray_concrete_powder"] = {90, 90, 90}, ["minecraft:light_gray_concrete_powder"] = {150, 150, 150}, ["minecraft:cyan_concrete_powder"] = {65, 165, 165}, ["minecraft:purple_concrete_powder"] = {110, 50, 150}, ["minecraft:blue_concrete_powder"] = {50, 55, 150}, ["minecraft:brown_concrete_powder"] = {110, 75, 50}, ["minecraft:green_concrete_powder"] = {65, 110, 45}, ["minecraft:red_concrete_powder"] = {160, 40, 40}, ["minecraft:black_concrete_powder"] = {20, 20, 20}, ["minecraft:terracotta"] = {160, 110, 75}, ["minecraft:white_terracotta"] = {210, 205, 195}, ["minecraft:orange_terracotta"] = {185, 115, 65}, ["minecraft:magenta_terracotta"] = {150, 85, 120}, ["minecraft:light_blue_terracotta"] = {140, 155, 175}, ["minecraft:yellow_terracotta"] = {190, 165, 90}, ["minecraft:lime_terracotta"] = {130, 145, 85}, ["minecraft:pink_terracotta"] = {185, 125, 125}, ["minecraft:gray_terracotta"] = {105, 95, 90}, ["minecraft:light_gray_terracotta"] = {155, 145, 135}, ["minecraft:cyan_terracotta"] = {110, 135, 135}, ["minecraft:purple_terracotta"] = {130, 85, 125}, ["minecraft:blue_terracotta"] = {100, 90, 130}, ["minecraft:brown_terracotta"] = {130, 90, 65}, ["minecraft:green_terracotta"] = {105, 110, 80}, ["minecraft:red_terracotta"] = {150, 75, 60}, ["minecraft:black_terracotta"] = {55, 45, 40}, ["minecraft:white_glazed_terracotta"] = {220, 220, 215}, ["minecraft:orange_glazed_terracotta"] = {225, 140, 65}, ["minecraft:magenta_glazed_terracotta"] = {185, 90, 185}, ["minecraft:light_blue_glazed_terracotta"] = {150, 195, 230}, ["minecraft:yellow_glazed_terracotta"] = {235, 215, 85}, ["minecraft:lime_glazed_terracotta"] = {130, 195, 85}, ["minecraft:pink_glazed_terracotta"] = {225, 160, 175}, ["minecraft:gray_glazed_terracotta"] = {115, 115, 115}, ["minecraft:light_gray_glazed_terracotta"] = {175, 175, 175}, ["minecraft:cyan_glazed_terracotta"] = {90, 190, 190}, ["minecraft:purple_glazed_terracotta"] = {135, 70, 175}, ["minecraft:blue_glazed_terracotta"] = {75, 80, 175}, ["minecraft:brown_glazed_terracotta"] = {135, 95, 70}, ["minecraft:green_glazed_terracotta"] = {85, 135, 65}, ["minecraft:red_glazed_terracotta"] = {185, 60, 60}, ["minecraft:black_glazed_terracotta"] = {40, 40, 40}, ["minecraft:glass"] = {200, 220, 235}, ["minecraft:white_stained_glass"] = {215, 220, 225}, ["minecraft:orange_stained_glass"] = {225, 155, 95}, ["minecraft:magenta_stained_glass"] = {195, 120, 195}, ["minecraft:light_blue_stained_glass"] = {160, 200, 230}, ["minecraft:yellow_stained_glass"] = {230, 220, 130}, ["minecraft:lime_stained_glass"] = {145, 210, 130}, ["minecraft:pink_stained_glass"] = {230, 175, 190}, ["minecraft:gray_stained_glass"] = {130, 130, 135}, ["minecraft:light_gray_stained_glass"] = {185, 185, 190}, ["minecraft:cyan_stained_glass"] = {120, 200, 205}, ["minecraft:purple_stained_glass"] = {145, 100, 190}, ["minecraft:blue_stained_glass"] = {105, 115, 200}, ["minecraft:brown_stained_glass"] = {150, 115, 90}, ["minecraft:green_stained_glass"] = {110, 165, 100}, ["minecraft:red_stained_glass"] = {200, 85, 85}, ["minecraft:black_stained_glass"] = {55, 55, 60}, ["minecraft:glass_pane"] = {200, 220, 235}, ["minecraft:white_stained_glass_pane"] = {215, 220, 225}, ["minecraft:orange_stained_glass_pane"] = {225, 155, 95}, ["minecraft:magenta_stained_glass_pane"] = {195, 120, 195}, ["minecraft:light_blue_stained_glass_pane"] = {160, 200, 230}, ["minecraft:yellow_stained_glass_pane"] = {230, 220, 130}, ["minecraft:lime_stained_glass_pane"] = {145, 210, 130}, ["minecraft:pink_stained_glass_pane"] = {230, 175, 190}, ["minecraft:gray_stained_glass_pane"] = {130, 130, 135}, ["minecraft:light_gray_stained_glass_pane"] = {185, 185, 190}, ["minecraft:cyan_stained_glass_pane"] = {120, 200, 205}, ["minecraft:purple_stained_glass_pane"] = {145, 100, 190}, ["minecraft:blue_stained_glass_pane"] = {105, 115, 200}, ["minecraft:brown_stained_glass_pane"] = {150, 115, 90}, ["minecraft:green_stained_glass_pane"] = {110, 165, 100}, ["minecraft:red_stained_glass_pane"] = {200, 85, 85}, ["minecraft:black_stained_glass_pane"] = {55, 55, 60}, ["minecraft:prismarine"] = {80, 160, 150}, ["minecraft:prismarine_bricks"] = {70, 140, 135}, ["minecraft:dark_prismarine"] = {50, 95, 90}, ["minecraft:tube_coral_block"] = {130, 80, 150}, ["minecraft:brain_coral_block"] = {155, 100, 120}, ["minecraft:bubble_coral_block"] = {130, 150, 175}, ["minecraft:fire_coral_block"] = {200, 80, 55}, ["minecraft:horn_coral_block"] = {150, 130, 70}, ["minecraft:dead_tube_coral_block"] = {130, 125, 125}, ["minecraft:dead_brain_coral_block"] = {135, 125, 125}, ["minecraft:dead_bubble_coral_block"] = {130, 130, 130}, ["minecraft:dead_fire_coral_block"] = {135, 120, 115}, ["minecraft:dead_horn_coral_block"] = {130, 125, 115}, ["minecraft:netherrack"] = {100, 45, 45}, ["minecraft:nether_bricks"] = {60, 35, 40}, ["minecraft:red_nether_bricks"] = {100, 45, 35}, ["minecraft:cracked_nether_bricks"] = {60, 35, 40}, ["minecraft:chiseled_nether_bricks"] = {60, 35, 40}, ["minecraft:soul_sand"] = {80, 60, 45}, ["minecraft:soul_soil"] = {75, 60, 45}, ["minecraft:basalt"] = {70, 70, 80}, ["minecraft:polished_basalt"] = {75, 75, 85}, ["minecraft:blackstone"] = {40, 38, 42}, ["minecraft:polished_blackstone"] = {48, 45, 50}, ["minecraft:chiseled_polished_blackstone"] = {48, 45, 50}, ["minecraft:gilded_blackstone"] = {55, 50, 55}, ["minecraft:cracked_polished_blackstone_bricks"] = {48, 45, 50}, ["minecraft:polished_blackstone_bricks"] = {48, 45, 50}, ["minecraft:magma_block"] = {140, 60, 30}, ["minecraft:ancient_debris"] = {60, 55, 50}, ["minecraft:shroomlight"] = {215, 175, 75}, ["minecraft:crimson_nylium"] = {140, 40, 50}, ["minecraft:warped_nylium"] = {30, 110, 80}, ["minecraft:crimson_stem"] = {120, 35, 40}, ["minecraft:stripped_crimson_stem"] = {165, 110, 95}, ["minecraft:crimson_hyphae"] = {100, 30, 35}, ["minecraft:stripped_crimson_hyphae"] = {155, 100, 85}, ["minecraft:warped_stem"] = {40, 100, 75}, ["minecraft:stripped_warped_stem"] = {90, 145, 130}, ["minecraft:warped_hyphae"] = {35, 85, 65}, ["minecraft:stripped_warped_hyphae"] = {80, 135, 120}, ["minecraft:crimson_planks"] = {165, 75, 65}, ["minecraft:warped_planks"] = {60, 140, 115}, ["minecraft:crimson_slab"] = {165, 75, 65}, ["minecraft:warped_slab"] = {60, 140, 115}, ["minecraft:crimson_pressure_plate"] = {165, 75, 65}, ["minecraft:warped_pressure_plate"] = {60, 140, 115}, ["minecraft:crimson_fence"] = {165, 75, 65}, ["minecraft:warped_fence"] = {60, 140, 115}, ["minecraft:crimson_fence_gate"] = {165, 75, 65}, ["minecraft:warped_fence_gate"] = {60, 140, 115}, ["minecraft:crimson_door"] = {165, 75, 65}, ["minecraft:warped_door"] = {60, 140, 115}, ["minecraft:crimson_trapdoor"] = {165, 75, 65}, ["minecraft:warped_trapdoor"] = {60, 140, 115}, ["minecraft:crimson_sign"] = {165, 75, 65}, ["minecraft:warped_sign"] = {60, 140, 115}, ["minecraft:crimson_button"] = {165, 75, 65}, ["minecraft:warped_button"] = {60, 140, 115}, ["minecraft:nether_wart_block"] = {110, 30, 50}, ["minecraft:warped_wart_block"] = {25, 85, 70}, ["minecraft:lodestone"] = {60, 55, 50}, ["minecraft:respawn_anchor"] = {55, 50, 55}, ["minecraft:end_stone"] = {220, 215, 180}, ["minecraft:end_stone_bricks"] = {210, 205, 170}, ["minecraft:purpur_block"] = {150, 110, 170}, ["minecraft:purpur_pillar"] = {150, 110, 170}, ["minecraft:chiseled_purpur"] = {145, 105, 165}, ["minecraft:mycelium"] = {120, 150, 110}, ["minecraft:sculk_sensor"] = {20, 50, 60}, ["minecraft:sculk_catalyst"] = {30, 60, 70}, ["minecraft:sculk_shrieker"] = {25, 55, 65}, ["minecraft:sculk_vein"] = {20, 60, 60}, ["minecraft:calibrated_sculk_sensor"] = {20, 50, 60}, ["minecraft:ochre_froglight"] = {200, 160, 75}, ["minecraft:verdant_froglight"] = {130, 195, 90}, ["minecraft:pearlescent_froglight"] = {195, 150, 200}, ["minecraft:bamboo_block"] = {160, 140, 80}, ["minecraft:stripped_bamboo_block"] = {195, 170, 110}, ["minecraft:bamboo_mosaic_slab"] = {185, 160, 100}, ["minecraft:bamboo_mosaic_stairs"] = {185, 160, 100}, ["minecraft:sponge"] = {200, 180, 130}, ["minecraft:wet_sponge"] = {100, 120, 140}, ["minecraft:ice"] = {160, 210, 230}, ["minecraft:packed_ice"] = {150, 200, 220}, ["minecraft:blue_ice"] = {120, 160, 200}, ["minecraft:frosted_ice"] = {160, 210, 230}, ["minecraft:snow_block"] = {240, 240, 245}, ["minecraft:clay"] = {165, 165, 160}, ["minecraft:bone_block"] = {220, 215, 195}, ["minecraft:honeycomb_block"] = {225, 185, 70}, ["minecraft:slime_block"] = {120, 200, 90}, ["minecraft:hay_block"] = {210, 190, 80}, ["minecraft:melon"] = {140, 175, 60}, ["minecraft:pumpkin"] = {200, 130, 50}, ["minecraft:carved_pumpkin"] = {200, 130, 50}, ["minecraft:jack_o_lantern"] = {200, 130, 50}, ["minecraft:jukebox"] = {130, 95, 65}, ["minecraft:bookshelf"] = {150, 125, 85}, ["minecraft:chiseled_bookshelf"] = {145, 120, 80}, ["minecraft:enchanting_table"] = {130, 110, 145}, ["minecraft:brewing_stand"] = {180, 150, 120}, ["minecraft:cauldron"] = {50, 50, 50}, ["minecraft:water_cauldron"] = {50, 50, 50}, ["minecraft:lava_cauldron"] = {50, 50, 50}, ["minecraft:powder_snow_cauldron"] = {50, 50, 50}, ["minecraft:end_portal_frame"] = {50, 50, 55}, ["minecraft:spawner"] = {40, 40, 45}, ["minecraft:furnace"] = {130, 130, 130}, ["minecraft:blast_furnace"] = {110, 100, 100}, ["minecraft:smoker"] = {110, 110, 105}, ["minecraft:crafting_table"] = {155, 125, 85}, ["minecraft:anvil"] = {60, 60, 65}, ["minecraft:chipped_anvil"] = {60, 60, 65}, ["minecraft:damaged_anvil"] = {60, 60, 65}, ["minecraft:grindstone"] = {140, 130, 120}, ["minecraft:stonecutter"] = {135, 135, 135}, ["minecraft:smithing_table"] = {130, 100, 70}, ["minecraft:loom"] = {155, 125, 85}, ["minecraft:fletching_table"] = {155, 125, 85}, ["minecraft:cartography_table"] = {155, 125, 85}, ["minecraft:composter"] = {140, 120, 85}, ["minecraft:barrel"] = {145, 115, 80}, ["minecraft:chest"] = {150, 120, 80}, ["minecraft:trapped_chest"] = {150, 120, 80}, ["minecraft:ender_chest"] = {30, 30, 40}, ["minecraft:shulker_box"] = {140, 110, 150}, ["minecraft:white_shulker_box"] = {220, 220, 220}, ["minecraft:orange_shulker_box"] = {215, 125, 45}, ["minecraft:magenta_shulker_box"] = {170, 70, 170}, ["minecraft:light_blue_shulker_box"] = {130, 180, 215}, ["minecraft:yellow_shulker_box"] = {225, 205, 70}, ["minecraft:lime_shulker_box"] = {110, 180, 70}, ["minecraft:pink_shulker_box"] = {215, 145, 160}, ["minecraft:gray_shulker_box"] = {95, 95, 95}, ["minecraft:light_gray_shulker_box"] = {155, 155, 155}, ["minecraft:cyan_shulker_box"] = {70, 170, 170}, ["minecraft:purple_shulker_box"] = {115, 55, 155}, ["minecraft:blue_shulker_box"] = {55, 60, 155}, ["minecraft:brown_shulker_box"] = {115, 80, 55}, ["minecraft:green_shulker_box"] = {70, 115, 50}, ["minecraft:red_shulker_box"] = {165, 45, 45}, ["minecraft:black_shulker_box"] = {25, 25, 25}, ["minecraft:bedrock"] = {85, 85, 85}, ["minecraft:barrier"] = {220, 220, 220}, ["minecraft:command_block"] = {140, 80, 60}, ["minecraft:repeating_command_block"] = {60, 90, 140}, ["minecraft:chain_command_block"] = {50, 130, 70}, ["minecraft:structure_block"] = {100, 140, 180}, ["minecraft:jigsaw"] = {90, 130, 170}, ["minecraft:light"] = {255, 255, 255}, ["minecraft:structure_void"] = {50, 50, 50}, ["minecraft:end_gateway"] = {50, 50, 55}, ["minecraft:end_portal"] = {30, 30, 40}, ["minecraft:portal"] = {80, 30, 120}, ["minecraft:dragon_egg"] = {25, 20, 30}, ["minecraft:infested_stone"] = {125, 125, 125}, ["minecraft:infested_deepslate"] = {68, 68, 73}, ["minecraft:infested_cobblestone"] = {122, 122, 122}, ["minecraft:infested_stone_bricks"] = {135, 135, 130}, ["minecraft:infested_mossy_stone_bricks"] = {115, 135, 105}, ["minecraft:infested_cracked_stone_bricks"] = {135, 135, 130}, ["minecraft:infested_chiseled_stone_bricks"] = {135, 135, 130}, ["minecraft:stone_bricks"] = {135, 135, 130}, ["minecraft:mossy_stone_bricks"] = {115, 135, 105}, ["minecraft:cracked_stone_bricks"] = {135, 135, 130}, ["minecraft:chiseled_stone_bricks"] = {135, 135, 130}, ["minecraft:mossy_cobblestone"] = {115, 135, 105}, ["minecraft:infested_mud_bricks"] = {100, 80, 60}, ["minecraft:dandelion"] = {250, 220, 50}, ["minecraft:poppy"] = {200, 40, 40}, ["minecraft:blue_orchid"] = {50, 70, 180}, ["minecraft:allium"] = {170, 70, 170}, ["minecraft:azure_bluet"] = {220, 220, 230}, ["minecraft:red_tulip"] = {200, 50, 50}, ["minecraft:orange_tulip"] = {220, 130, 40}, ["minecraft:white_tulip"] = {230, 230, 235}, ["minecraft:pink_tulip"] = {230, 150, 170}, ["minecraft:oxeye_daisy"] = {230, 235, 210}, ["minecraft:cornflower"] = {60, 80, 200}, ["minecraft:lily_of_the_valley"] = {225, 230, 225}, ["minecraft:sunflower"] = {250, 210, 50}, ["minecraft:lilac"] = {170, 100, 180}, ["minecraft:peony"] = {210, 120, 150}, ["minecraft:rose_bush"] = {190, 45, 45}, ["minecraft:wither_rose"] = {40, 20, 40}, ["minecraft:dead_bush"] = {140, 120, 80}, ["minecraft:sugar_cane"] = {110, 150, 60}, ["minecraft:bamboo"] = {100, 145, 60}, ["minecraft:oak_sapling"] = {75, 135, 50}, ["minecraft:spruce_sapling"] = {50, 85, 40}, ["minecraft:birch_sapling"] = {85, 155, 65}, ["minecraft:jungle_sapling"] = {55, 115, 30}, ["minecraft:acacia_sapling"] = {85, 130, 40}, ["minecraft:dark_oak_sapling"] = {55, 85, 35}, ["minecraft:mangrove_propagule"] = {65, 110, 50}, ["minecraft:cherry_sapling"] = {210, 140, 170}, ["minecraft:spore_blossom"] = {140, 80, 160}, ["minecraft:flowering_azalea"] = {180, 100, 160}, ["minecraft:azalea"] = {45, 130, 55}, ["minecraft:water"] = {40, 80, 180}, ["minecraft:lava"] = {210, 100, 20}, ["minecraft:powder_snow"] = {230, 240, 250}, ["minecraft:fire"] = {230, 150, 50}, ["minecraft:soul_fire"] = {60, 120, 200}, ["minecraft:redstone_wire"] = {180, 30, 30}, ["minecraft:redstone_torch"] = {180, 50, 40}, ["minecraft:repeater"] = {130, 130, 130}, ["minecraft:comparator"] = {130, 130, 130}, ["minecraft:observer"] = {130, 130, 130}, ["minecraft:piston"] = {130, 130, 130}, ["minecraft:sticky_piston"] = {130, 130, 130}, ["minecraft:dispenser"] = {130, 130, 130}, ["minecraft:dropper"] = {130, 130, 130}, ["minecraft:note_block"] = {130, 95, 65}, ["minecraft:target"] = {210, 175, 155}, ["minecraft:lever"] = {100, 100, 100}, ["minecraft:button"] = {130, 130, 130}, ["minecraft:stone_button"] = {130, 130, 130}, ["minecraft:oak_button"] = {168, 132, 88}, ["minecraft:spruce_button"] = {120, 90, 60}, ["minecraft:birch_button"] = {205, 185, 145}, ["minecraft:jungle_button"] = {155, 120, 65}, ["minecraft:acacia_button"] = {175, 125, 70}, ["minecraft:dark_oak_button"] = {100, 75, 50}, ["minecraft:mangrove_button"] = {140, 100, 65}, ["minecraft:bamboo_button"] = {195, 170, 110}, ["minecraft:polished_blackstone_button"] = {48, 45, 50}, ["minecraft:pressure_plate"] = {130, 130, 130}, ["minecraft:stone_pressure_plate"] = {130, 130, 130}, ["minecraft:oak_pressure_plate"] = {168, 132, 88}, ["minecraft:spruce_pressure_plate"] = {120, 90, 60}, ["minecraft:birch_pressure_plate"] = {205, 185, 145}, ["minecraft:jungle_pressure_plate"] = {155, 120, 65}, ["minecraft:acacia_pressure_plate"] = {175, 125, 70}, ["minecraft:dark_oak_pressure_plate"] = {100, 75, 50}, ["minecraft:mangrove_pressure_plate"] = {140, 100, 65}, ["minecraft:bamboo_pressure_plate"] = {195, 170, 110}, ["minecraft:polished_blackstone_pressure_plate"] = {48, 45, 50}, ["minecraft:heavy_weighted_pressure_plate"] = {130, 130, 130}, ["minecraft:light_weighted_pressure_plate"] = {200, 180, 50}, ["minecraft:door"] = {130, 130, 130}, ["minecraft:iron_door"] = {160, 160, 160}, ["minecraft:oak_door"] = {168, 132, 88}, ["minecraft:spruce_door"] = {120, 90, 60}, ["minecraft:birch_door"] = {205, 185, 145}, ["minecraft:jungle_door"] = {155, 120, 65}, ["minecraft:acacia_door"] = {175, 125, 70}, ["minecraft:dark_oak_door"] = {100, 75, 50}, ["minecraft:mangrove_door"] = {140, 100, 65}, ["minecraft:bamboo_door"] = {195, 170, 110}, ["minecraft:trapdoor"] = {130, 130, 130}, ["minecraft:iron_trapdoor"] = {160, 160, 160}, ["minecraft:oak_trapdoor"] = {168, 132, 88}, ["minecraft:spruce_trapdoor"] = {120, 90, 60}, ["minecraft:birch_trapdoor"] = {205, 185, 145}, ["minecraft:jungle_trapdoor"] = {155, 120, 65}, ["minecraft:acacia_trapdoor"] = {175, 125, 70}, ["minecraft:dark_oak_trapdoor"] = {100, 75, 50}, ["minecraft:mangrove_trapdoor"] = {140, 100, 65}, ["minecraft:bamboo_trapdoor"] = {195, 170, 110}, ["minecraft:fence"] = {130, 130, 130}, ["minecraft:oak_fence"] = {168, 132, 88}, ["minecraft:spruce_fence"] = {120, 90, 60}, ["minecraft:birch_fence"] = {205, 185, 145}, ["minecraft:jungle_fence"] = {155, 120, 65}, ["minecraft:acacia_fence"] = {175, 125, 70}, ["minecraft:dark_oak_fence"] = {100, 75, 50}, ["minecraft:mangrove_fence"] = {140, 100, 65}, ["minecraft:bamboo_fence"] = {195, 170, 110}, ["minecraft:nether_brick_fence"] = {60, 35, 40}, ["minecraft:fence_gate"] = {130, 130, 130}, ["minecraft:oak_fence_gate"] = {168, 132, 88}, ["minecraft:spruce_fence_gate"] = {120, 90, 60}, ["minecraft:birch_fence_gate"] = {205, 185, 145}, ["minecraft:jungle_fence_gate"] = {155, 120, 65}, ["minecraft:acacia_fence_gate"] = {175, 125, 70}, ["minecraft:dark_oak_fence_gate"] = {100, 75, 50}, ["minecraft:mangrove_fence_gate"] = {140, 100, 65}, ["minecraft:bamboo_fence_gate"] = {195, 170, 110}, ["minecraft:wall_torch"] = {220, 180, 100}, ["minecraft:soul_wall_torch"] = {80, 130, 200}, ["minecraft:redstone_wall_torch"] = {180, 50, 40}, ["minecraft:sign"] = {130, 130, 130}, ["minecraft:oak_sign"] = {168, 132, 88}, ["minecraft:spruce_sign"] = {120, 90, 60}, ["minecraft:birch_sign"] = {205, 185, 145}, ["minecraft:jungle_sign"] = {155, 120, 65}, ["minecraft:acacia_sign"] = {175, 125, 70}, ["minecraft:dark_oak_sign"] = {100, 75, 50}, ["minecraft:mangrove_sign"] = {140, 100, 65}, ["minecraft:bamboo_sign"] = {195, 170, 110}, ["minecraft:wall_sign"] = {130, 130, 130}, ["minecraft:oak_wall_sign"] = {168, 132, 88}, ["minecraft:spruce_wall_sign"] = {120, 90, 60}, ["minecraft:birch_wall_sign"] = {205, 185, 145}, ["minecraft:jungle_wall_sign"] = {155, 120, 65}, ["minecraft:acacia_wall_sign"] = {175, 125, 70}, ["minecraft:dark_oak_wall_sign"] = {100, 75, 50}, ["minecraft:mangrove_wall_sign"] = {140, 100, 65}, ["minecraft:bamboo_wall_sign"] = {195, 170, 110}, ["minecraft:hanging_sign"] = {130, 130, 130}, ["minecraft:oak_hanging_sign"] = {168, 132, 88}, ["minecraft:spruce_hanging_sign"] = {120, 90, 60}, ["minecraft:birch_hanging_sign"] = {205, 185, 145}, ["minecraft:jungle_hanging_sign"] = {155, 120, 65}, ["minecraft:acacia_hanging_sign"] = {175, 125, 70}, ["minecraft:dark_oak_hanging_sign"] = {100, 75, 50}, ["minecraft:mangrove_hanging_sign"] = {140, 100, 65}, ["minecraft:bamboo_hanging_sign"] = {195, 170, 110}, ["minecraft:ladder"] = {160, 130, 85}, ["minecraft:scaffolding"] = {180, 170, 130}, ["minecraft:chain"] = {90, 90, 95}, ["minecraft:candle"] = {220, 210, 180}, ["minecraft:white_candle"] = {220, 220, 220}, ["minecraft:orange_candle"] = {220, 140, 60}, ["minecraft:magenta_candle"] = {180, 80, 180}, ["minecraft:light_blue_candle"] = {140, 190, 220}, ["minecraft:yellow_candle"] = {230, 215, 80}, ["minecraft:lime_candle"] = {120, 190, 80}, ["minecraft:pink_candle"] = {225, 155, 170}, ["minecraft:gray_candle"] = {110, 110, 110}, ["minecraft:light_gray_candle"] = {170, 170, 170}, ["minecraft:cyan_candle"] = {80, 180, 180}, ["minecraft:purple_candle"] = {130, 70, 170}, ["minecraft:blue_candle"] = {70, 75, 170}, ["minecraft:brown_candle"] = {130, 95, 70}, ["minecraft:green_candle"] = {80, 130, 60}, ["minecraft:red_candle"] = {180, 55, 55}, ["minecraft:black_candle"] = {40, 40, 40}, ["minecraft:rails"] = {130, 130, 130}, ["minecraft:powered_rail"] = {130, 130, 130}, ["minecraft:detector_rail"] = {130, 130, 130}, ["minecraft:activator_rail"] = {130, 130, 130}, ["minecraft:lime_candle_cake"] = {230, 215, 80}, ["minecraft:oak_slab"] = {168, 132, 88}, ["minecraft:spruce_slab"] = {120, 90, 60}, ["minecraft:birch_slab"] = {205, 185, 145}, ["minecraft:jungle_slab"] = {155, 120, 65}, ["minecraft:acacia_slab"] = {175, 125, 70}, ["minecraft:dark_oak_slab"] = {100, 75, 50}, ["minecraft:mangrove_slab"] = {140, 100, 65}, ["minecraft:bamboo_slab"] = {195, 170, 110}, ["minecraft:stone_slab"] = {125, 125, 125}, ["minecraft:smooth_stone_slab"] = {175, 175, 175}, ["minecraft:stone_brick_slab"] = {135, 135, 130}, ["minecraft:sandstone_slab"] = {215, 205, 155}, ["minecraft:purpur_slab"] = {150, 110, 170}, ["minecraft:quartz_slab"] = {230, 230, 225}, ["minecraft:red_sandstone_slab"] = {185, 110, 55}, ["minecraft:prismarine_slab"] = {80, 160, 150}, ["minecraft:prismarine_brick_slab"] = {70, 140, 135}, ["minecraft:dark_prismarine_slab"] = {50, 95, 90}, ["minecraft:granite_slab"] = {132, 98, 78}, ["minecraft:polished_granite_slab"] = {140, 104, 82}, ["minecraft:diorite_slab"] = {173, 173, 173}, ["minecraft:polished_diorite_slab"] = {180, 180, 180}, ["minecraft:andesite_slab"] = {126, 126, 131}, ["minecraft:polished_andesite_slab"] = {135, 135, 140}, ["minecraft:cobblestone_slab"] = {122, 122, 122}, ["minecraft:brick_slab"] = {150, 100, 80}, ["minecraft:mud_brick_slab"] = {100, 80, 60}, ["minecraft:cut_copper_slab"] = {185, 120, 70}, ["minecraft:exposed_cut_copper_slab"] = {170, 130, 100}, ["minecraft:weathered_cut_copper_slab"] = {110, 110, 105}, ["minecraft:oxidized_cut_copper_slab"] = {75, 110, 105}, ["minecraft:waxed_cut_copper_slab"] = {185, 120, 70}, ["minecraft:waxed_exposed_cut_copper_slab"] = {170, 130, 100}, ["minecraft:waxed_weathered_cut_copper_slab"] = {110, 110, 105}, ["minecraft:waxed_oxidized_cut_copper_slab"] = {75, 110, 105}, ["minecraft:tuff_slab"] = {100, 100, 95}, ["minecraft:polished_tuff_slab"] = {110, 110, 105}, ["minecraft:tuff_brick_slab"] = {105, 105, 100}, ["minecraft:polished_tuff_double_slab"] = {110, 110, 105}, ["minecraft:oak_stairs"] = {168, 132, 88}, ["minecraft:spruce_stairs"] = {120, 90, 60}, ["minecraft:birch_stairs"] = {205, 185, 145}, ["minecraft:jungle_stairs"] = {155, 120, 65}, ["minecraft:acacia_stairs"] = {175, 125, 70}, ["minecraft:dark_oak_stairs"] = {100, 75, 50}, ["minecraft:mangrove_stairs"] = {140, 100, 65}, ["minecraft:bamboo_stairs"] = {195, 170, 110}, ["minecraft:stone_stairs"] = {125, 125, 125}, ["minecraft:smooth_stone_stairs"] = {175, 175, 175}, ["minecraft:stone_brick_stairs"] = {135, 135, 130}, ["minecraft:sandstone_stairs"] = {215, 205, 155}, ["minecraft:purpur_stairs"] = {150, 110, 170}, ["minecraft:quartz_stairs"] = {230, 230, 225}, ["minecraft:red_sandstone_stairs"] = {185, 110, 55}, ["minecraft:prismarine_stairs"] = {80, 160, 150}, ["minecraft:prismarine_brick_stairs"] = {70, 140, 135}, ["minecraft:dark_prismarine_stairs"] = {50, 95, 90}, ["minecraft:granite_stairs"] = {132, 98, 78}, ["minecraft:polished_granite_stairs"] = {140, 104, 82}, ["minecraft:diorite_stairs"] = {173, 173, 173}, ["minecraft:polished_diorite_stairs"] = {180, 180, 180}, ["minecraft:andesite_stairs"] = {126, 126, 131}, ["minecraft:polished_andesite_stairs"] = {135, 135, 140}, ["minecraft:cobblestone_stairs"] = {122, 122, 122}, ["minecraft:brick_stairs"] = {150, 100, 80}, ["minecraft:mud_brick_stairs"] = {100, 80, 60}, ["minecraft:cut_copper_stairs"] = {185, 120, 70}, ["minecraft:exposed_cut_copper_stairs"] = {170, 130, 100}, ["minecraft:weathered_cut_copper_stairs"] = {110, 110, 105}, ["minecraft:oxidized_cut_copper_stairs"] = {75, 110, 105}, ["minecraft:waxed_cut_copper_stairs"] = {185, 120, 70}, ["minecraft:waxed_exposed_cut_copper_stairs"] = {170, 130, 100}, ["minecraft:waxed_weathered_cut_copper_stairs"] = {110, 110, 105}, ["minecraft:waxed_oxidized_cut_copper_stairs"] = {75, 110, 105}, ["minecraft:tuff_stairs"] = {100, 100, 95}, ["minecraft:polished_tuff_stairs"] = {110, 110, 105}, ["minecraft:tuff_brick_stairs"] = {105, 105, 100}, ["minecraft:wall"] = {125, 125, 125}, ["minecraft:cobblestone_wall"] = {122, 122, 122}, ["minecraft:mossy_cobblestone_wall"] = {115, 135, 105}, ["minecraft:stone_brick_wall"] = {135, 135, 130}, ["minecraft:mossy_stone_brick_wall"] = {115, 135, 105}, ["minecraft:granite_wall"] = {132, 98, 78}, ["minecraft:polished_granite_wall"] = {140, 104, 82}, ["minecraft:diorite_wall"] = {173, 173, 173}, ["minecraft:polished_diorite_wall"] = {180, 180, 180}, ["minecraft:andesite_wall"] = {126, 126, 131}, ["minecraft:polished_andesite_wall"] = {135, 135, 140}, ["minecraft:sandstone_wall"] = {215, 205, 155}, ["minecraft:red_sandstone_wall"] = {185, 110, 55}, ["minecraft:brick_wall"] = {150, 100, 80}, ["minecraft:prismarine_wall"] = {80, 160, 150}, ["minecraft:red_nether_brick_wall"] = {100, 45, 35}, ["minecraft:nether_brick_wall"] = {60, 35, 40}, ["minecraft:end_stone_brick_wall"] = {210, 205, 170}, ["minecraft:mud_brick_wall"] = {100, 80, 60}, ["minecraft:blackstone_wall"] = {40, 38, 42}, ["minecraft:polished_blackstone_wall"] = {48, 45, 50}, ["minecraft:polished_blackstone_brick_wall"] = {48, 45, 50}, ["minecraft:cobbled_deepslate_wall"] = {75, 75, 80}, ["minecraft:polished_deepslate_wall"] = {82, 82, 87}, ["minecraft:deepslate_brick_wall"] = {72, 72, 77}, ["minecraft:deepslate_tile_wall"] = {78, 78, 83}, ["minecraft:tuff_wall"] = {100, 100, 95}, ["minecraft:polished_tuff_wall"] = {110, 110, 105}, ["minecraft:tuff_brick_wall"] = {105, 105, 100}, ["minecraft:quartz_block"] = {230, 230, 225}, ["minecraft:chiseled_quartz_block"] = {230, 230, 225}, ["minecraft:quartz_pillar"] = {230, 230, 225}, ["minecraft:quartz_bricks"] = {230, 230, 225}, ["minecraft:smooth_quartz"] = {235, 235, 230}, ["minecraft:bricks"] = {150, 100, 80}, ["minecraft:chiseled_bricks"] = {150, 100, 80}, ["minecraft:deepslate_bricks"] = {72, 72, 77}, ["minecraft:cracked_deepslate_bricks"] = {72, 72, 77}, ["minecraft:deepslate_tiles"] = {78, 78, 83}, ["minecraft:cracked_deepslate_tiles"] = {78, 78, 83}, ["minecraft:chiseled_deepslate"] = {68, 68, 73}, ["minecraft:reinforced_deepslate"] = {50, 50, 55}, ["minecraft:polished_tuff"] = {110, 110, 105}, ["minecraft:chiseled_tuff"] = {110, 110, 105}, ["minecraft:tuff_bricks"] = {105, 105, 100}, ["minecraft:potted_dandelion"] = {130, 130, 130}, ["minecraft:potted_poppy"] = {130, 130, 130}, ["minecraft:potted_blue_orchid"] = {130, 130, 130}, ["minecraft:potted_allium"] = {130, 130, 130}, ["minecraft:potted_azure_bluet"] = {130, 130, 130}, ["minecraft:potted_red_tulip"] = {130, 130, 130}, ["minecraft:potted_orange_tulip"] = {130, 130, 130}, ["minecraft:potted_white_tulip"] = {130, 130, 130}, ["minecraft:potted_pink_tulip"] = {130, 130, 130}, ["minecraft:potted_oxeye_daisy"] = {130, 130, 130}, ["minecraft:potted_cornflower"] = {130, 130, 130}, ["minecraft:potted_lily_of_the_valley"] = {130, 130, 130}, ["minecraft:potted_wither_rose"] = {130, 130, 130}, ["minecraft:potted_oak_sapling"] = {130, 130, 130}, ["minecraft:potted_spruce_sapling"] = {130, 130, 130}, ["minecraft:potted_birch_sapling"] = {130, 130, 130}, ["minecraft:potted_jungle_sapling"] = {130, 130, 130}, ["minecraft:potted_acacia_sapling"] = {130, 130, 130}, ["minecraft:potted_dark_oak_sapling"] = {130, 130, 130}, ["minecraft:potted_mangrove_propagule"] = {130, 130, 130}, ["minecraft:potted_cherry_sapling"] = {130, 130, 130}, ["minecraft:potted_fern"] = {130, 130, 130}, ["minecraft:potted_dead_bush"] = {130, 130, 130}, ["minecraft:potted_cactus"] = {130, 130, 130}, ["minecraft:potted_bamboo"] = {130, 130, 130}, ["minecraft:potted_azalea"] = {130, 130, 130}, ["minecraft:potted_flowering_azalea"] = {130, 130, 130}, ["minecraft:potted_torchflower"] = {130, 130, 130}, ["minecraft:torchflower"] = {230, 210, 70}, ["minecraft:torchflower_crop"] = {60, 120, 40}, ["minecraft:potatoes"] = {60, 120, 40}, ["minecraft:carrots"] = {60, 120, 40}, ["minecraft:wheat"] = {140, 160, 50}, ["minecraft:beetroots"] = {60, 120, 40}, ["minecraft:melon_stem"] = {60, 120, 40}, ["minecraft:pumpkin_stem"] = {60, 120, 40}, ["minecraft:sweet_berry_bush"] = {60, 120, 40}, ["minecraft:cocoa"] = {140, 100, 50}, ["minecraft:kelp"] = {40, 100, 40}, ["minecraft:kelp_plant"] = {40, 100, 40}, ["minecraft:seagrass"] = {50, 130, 60}, ["minecraft:tall_seagrass"] = {50, 130, 60}, ["minecraft:fern"] = {50, 140, 50}, ["minecraft:large_fern"] = {50, 140, 50}, ["minecraft:vine"] = {50, 110, 40}, ["minecraft:lily_pad"] = {40, 120, 50}, ["minecraft:nether_sprouts"] = {50, 80, 60}, ["minecraft:crimson_fungus"] = {160, 40, 50}, ["minecraft:warped_fungus"] = {30, 110, 80}, ["minecraft:crimson_roots"] = {140, 40, 50}, ["minecraft:warped_roots"] = {30, 100, 75}, ["minecraft:weeping_vines"] = {100, 50, 60}, ["minecraft:weeping_vines_plant"] = {100, 50, 60}, ["minecraft:twisting_vines"] = {40, 120, 80}, ["minecraft:twisting_vines_plant"] = {40, 120, 80}, ["minecraft:dead_tube_coral"] = {130, 125, 125}, ["minecraft:dead_brain_coral"] = {135, 125, 125}, ["minecraft:dead_bubble_coral"] = {130, 130, 130}, ["minecraft:dead_fire_coral"] = {135, 120, 115}, ["minecraft:dead_horn_coral"] = {130, 125, 115}, ["minecraft:tube_coral"] = {130, 80, 150}, ["minecraft:brain_coral"] = {155, 100, 120}, ["minecraft:bubble_coral"] = {130, 150, 175}, ["minecraft:fire_coral"] = {200, 80, 55}, ["minecraft:horn_coral"] = {150, 130, 70}, ["minecraft:tube_coral_fan"] = {130, 80, 150}, ["minecraft:brain_coral_fan"] = {155, 100, 120}, ["minecraft:bubble_coral_fan"] = {130, 150, 175}, ["minecraft:fire_coral_fan"] = {200, 80, 55}, ["minecraft:horn_coral_fan"] = {150, 130, 70}, ["minecraft:dead_tube_coral_fan"] = {130, 125, 125}, ["minecraft:dead_brain_coral_fan"] = {135, 125, 125}, ["minecraft:dead_bubble_coral_fan"] = {130, 130, 130}, ["minecraft:dead_fire_coral_fan"] = {135, 120, 115}, ["minecraft:dead_horn_coral_fan"] = {130, 125, 115}, ["minecraft:cobweb"] = {200, 200, 200}, ["minecraft:snow"] = {240, 240, 245}, ["minecraft:tall_grass"] = {90, 150, 50}, ["minecraft:head"] = {130, 110, 90}, ["minecraft:skull"] = {130, 120, 110}, ["minecraft:player_head"] = {130, 110, 90}, ["minecraft:zombie_head"] = {100, 130, 90}, ["minecraft:creeper_head"] = {90, 140, 80}, ["minecraft:skeleton_skull"] = {160, 160, 150}, ["minecraft:wither_skeleton_skull"] = {50, 50, 55}, ["minecraft:piglin_head"] = {160, 120, 100}, ["minecraft:dragon_head"] = {80, 80, 90}, ["minecraft:bell"] = {180, 170, 140}, ["minecraft:lectern"] = {155, 125, 85}, ["minecraft:armorer_stand"] = {130, 130, 130}, ["minecraft:weaponsmith_stand"] = {130, 130, 130}, ["minecraft:toolsmith_stand"] = {130, 130, 130}, ["minecraft:butcher_stand"] = {130, 130, 130}, ["minecraft:leatherworker_stand"] = {130, 130, 130}, ["minecraft:decorated_pot"] = {180, 150, 100}, ["minecraft:suspicious_sand"] = {215, 200, 150}, ["minecraft:suspicious_gravel"] = {130, 120, 115}, ["minecraft:cake"] = {230, 210, 160}, ["minecraft:candle_cake"] = {230, 210, 160}, ["minecraft:white_candle_cake"] = {230, 210, 160}, ["minecraft:orange_candle_cake"] = {230, 210, 160}, ["minecraft:magenta_candle_cake"] = {230, 210, 160}, ["minecraft:light_blue_candle_cake"] = {230, 210, 160}, ["minecraft:yellow_candle_cake"] = {230, 210, 160}, ["minecraft:pink_candle_cake"] = {230, 210, 160}, ["minecraft:gray_candle_cake"] = {230, 210, 160}, ["minecraft:light_gray_candle_cake"] = {230, 210, 160}, ["minecraft:cyan_candle_cake"] = {230, 210, 160}, ["minecraft:purple_candle_cake"] = {230, 210, 160}, ["minecraft:blue_candle_cake"] = {230, 210, 160}, ["minecraft:brown_candle_cake"] = {230, 210, 160}, ["minecraft:green_candle_cake"] = {230, 210, 160}, ["minecraft:red_candle_cake"] = {230, 210, 160}, ["minecraft:black_candle_cake"] = {230, 210, 160}, ["minecraft:monster_egg"] = {125, 125, 125}, ["minecraft:stone_monster_egg"] = {125, 125, 125}, ["minecraft:cobblestone_monster_egg"] = {122, 122, 122}, ["minecraft:stone_brick_monster_egg"] = {135, 135, 130}, ["minecraft:mossy_stone_brick_monster_egg"] = {115, 135, 105}, ["minecraft:cracked_stone_brick_monster_egg"] = {135, 135, 130}, ["minecraft:chiseled_stone_brick_monster_egg"] = {135, 135, 130}, ["minecraft:deepslate_monster_egg"] = {68, 68, 73} } --- Interned RGBA tables let adjacent pixels compare colors by identity and let --- every cached voxel reference one shared, pre-shaded palette entry. local internedColors = {} local colorIds = {} local nextColorId = 0 @@ -180,88 +154,9 @@ local PLAYER_COLOR = internColor(255, 30, 30, 255) local UNKNOWN_COLOR = internColor(150, 50, 200, 255) local UNKNOWN_SHADES = {UNKNOWN_COLOR, UNKNOWN_COLOR, UNKNOWN_COLOR} --- Two one-dimensional ray axes replace 8,192 nested direction tables. local fovY = 0.8 local rayU, rayV = {}, {} -local function updateRayAxes() - local fovX = fovY * (W / H) - for px = 1, W do - rayU[px] = (((px - 0.5) / W) * 2 - 1) * fovX - end - for py = 1, H do - rayV[py] = (1 - ((py - 0.5) / H) * 2) * fovY - end - raycastDirty = true -end - -local function rebuildDrawRuns() - local runCount = 0 - local active, nextActive = activeRunsA, activeRunsB - - for key in pairs(active) do active[key] = nil end - for key in pairs(nextActive) do nextActive[key] = nil end - - for py = 1, H do - for key in pairs(nextActive) do nextActive[key] = nil end - local rowStart = (py - 1) * W - local startX = 0 - local color = pixelColors[rowStart + 1] - - for px = 2, W do - local nextColor = pixelColors[rowStart + px] - if nextColor ~= color then - local endX = px - 1 - local key = (colorIds[color] * (W + 1) + startX) * (W + 1) + endX - local run = active[key] - if run then - run.p2[2] = py * TILE_H - else - runCount = runCount + 1 - run = drawRuns[runCount] - if not run then - run = {p1 = {0, 0}, p2 = {0, 0}, color = color} - drawRuns[runCount] = run - end - run.p1[1], run.p1[2] = startX * TILE_W, (py - 1) * TILE_H - run.p2[1], run.p2[2] = endX * TILE_W, py * TILE_H - run.color = color - end - nextActive[key] = run - startX = px - 1 - color = nextColor - end - end - - local endX = W - local key = (colorIds[color] * (W + 1) + startX) * (W + 1) + endX - local run = active[key] - if run then - run.p2[2] = py * TILE_H - else - runCount = runCount + 1 - run = drawRuns[runCount] - if not run then - run = {p1 = {0, 0}, p2 = {0, 0}, color = color} - drawRuns[runCount] = run - end - run.p1[1], run.p1[2] = startX * TILE_W, (py - 1) * TILE_H - run.p2[1], run.p2[2] = endX * TILE_W, py * TILE_H - run.color = color - end - nextActive[key] = run - active, nextActive = nextActive, active - end - - drawRunCount = runCount -end - -for i = 1, W * H do - pixelColors[i] = SKY_COLOR -end -updateRayAxes() -rebuildDrawRuns() - -- ========================================== -- 5. SCANNING -- ========================================== @@ -293,9 +188,6 @@ local function resetCache(showNotification) end end --- Walk concentric cube shells without materializing a scan queue. The six face --- ranges are disjoint, so every voxel is produced exactly once and nearby data --- becomes visible first. local function nextScanPosition() if scanRadius == 0 then scanRadius, scanFace = 1, 1 @@ -328,15 +220,10 @@ local function nextScanPosition() scanRadius = scanRadius + 1 scanFace = 1 end - r = scanRadius - if scanFace <= 2 then - scanA, scanB = -r, -r - elseif scanFace <= 4 then - scanA, scanB = -r + 1, -r - else - scanA, scanB = -r + 1, -r + 1 - end + if scanFace <= 2 then scanA, scanB = -r, -r + elseif scanFace <= 4 then scanA, scanB = -r + 1, -r + else scanA, scanB = -r + 1, -r + 1 end end end @@ -363,16 +250,13 @@ local function updateScan(now) local wx, wy, wz = nextScanPosition() local blockName = getBlock(wx, wy, wz) if blockName and blockName ~= "minecraft:air" then - local cacheIndex = (wx - worldMinX) * PLANE + - (wy - worldMinY) * SIDE + - (wz - worldMinZ) + local cacheIndex = (wx - worldMinX) * PLANE + (wy - worldMinY) * SIDE + (wz - worldMinZ) worldCache[cacheIndex] = blockColors[blockName] or UNKNOWN_SHADES end - scanIndex = scanIndex + 1 end - raycastDirty = true + if rendererMode == 1 then raycastDirty = true end if scanIndex >= TOTAL_BLOCKS then scanCompleted = true notify("Scan complete!") @@ -380,19 +264,76 @@ local function updateScan(now) end -- ========================================== --- 6. RAYCASTING +-- 6. RENDERERS -- ========================================== +-- === RENDERER 1: LOW QUALITY === +local function updateRayAxes() + local fovX = fovY * (W / H) + for px = 1, W do rayU[px] = (((px - 0.5) / W) * 2 - 1) * fovX end + for py = 1, H do rayV[py] = (1 - ((py - 0.5) / H) * 2) * fovY end + raycastDirty = true +end + +local function rebuildDrawRuns() + local runCount = 0 + local active, nextActive = activeRunsA, activeRunsB + for key in pairs(active) do active[key] = nil end + for key in pairs(nextActive) do nextActive[key] = nil end + + for py = 1, H do + for key in pairs(nextActive) do nextActive[key] = nil end + local rowStart = (py - 1) * W + local startX = 0 + local color = pixelColors[rowStart + 1] + + for px = 2, W do + local nextColor = pixelColors[rowStart + px] + if nextColor ~= color then + local endX = px - 1 + local key = (colorIds[color] * (W + 1) + startX) * (W + 1) + endX + local run = active[key] + if run then + run.p2[2] = py * TILE_H + else + runCount = runCount + 1 + run = drawRuns[runCount] + if not run then run = {p1 = {0, 0}, p2 = {0, 0}, color = color}; drawRuns[runCount] = run end + run.p1[1], run.p1[2] = startX * TILE_W, (py - 1) * TILE_H + run.p2[1], run.p2[2] = endX * TILE_W, py * TILE_H + run.color = color + end + nextActive[key] = run + startX = px - 1 + color = nextColor + end + end + + local endX = W + local key = (colorIds[color] * (W + 1) + startX) * (W + 1) + endX + local run = active[key] + if run then + run.p2[2] = py * TILE_H + else + runCount = runCount + 1 + run = drawRuns[runCount] + if not run then run = {p1 = {0, 0}, p2 = {0, 0}, color = color}; drawRuns[runCount] = run end + run.p1[1], run.p1[2] = startX * TILE_W, (py - 1) * TILE_H + run.p2[1], run.p2[2] = endX * TILE_W, py * TILE_H + run.color = color + end + nextActive[key] = run + active, nextActive = nextActive, active + end + drawRunCount = runCount +end + local function raycastFrame() local cosY, sinY = m_cos(yaw), m_sin(yaw) local cosP, sinP = m_cos(pitch), m_sin(pitch) local camMapX, camMapY, camMapZ = m_floor(camX), m_floor(camY), m_floor(camZ) - local camInBounds = camMapX >= worldMinX and camMapX <= worldMaxX and - camMapY >= worldMinY and camMapY <= worldMaxY and - camMapZ >= worldMinZ and camMapZ <= worldMaxZ - local camCacheIndex = (camMapX - worldMinX) * PLANE + - (camMapY - worldMinY) * SIDE + - (camMapZ - worldMinZ) + local camInBounds = camMapX >= worldMinX and camMapX <= worldMaxX and camMapY >= worldMinY and camMapY <= worldMaxY and camMapZ >= worldMinZ and camMapZ <= worldMaxZ + local camCacheIndex = (camMapX - worldMinX) * PLANE + (camMapY - worldMinY) * SIDE + (camMapZ - worldMinZ) local camCellSolid = camInBounds and worldCache[camCacheIndex] ~= nil local pixelIndex = 0 @@ -411,24 +352,14 @@ local function raycastFrame() local deltaDistX = dirX == 0 and 1e30 or m_abs(1 / dirX) local deltaDistY = dirY == 0 and 1e30 or m_abs(1 / dirY) local deltaDistZ = dirZ == 0 and 1e30 or m_abs(1 / dirZ) - local stepX, stepY, stepZ - local sideDistX, sideDistY, sideDistZ + local stepX, stepY, stepZ, sideDistX, sideDistY, sideDistZ - if dirX < 0 then - stepX, sideDistX = -1, (camX - mapX) * deltaDistX - else - stepX, sideDistX = 1, (mapX + 1 - camX) * deltaDistX - end - if dirY < 0 then - stepY, sideDistY = -1, (camY - mapY) * deltaDistY - else - stepY, sideDistY = 1, (mapY + 1 - camY) * deltaDistY - end - if dirZ < 0 then - stepZ, sideDistZ = -1, (camZ - mapZ) * deltaDistZ - else - stepZ, sideDistZ = 1, (mapZ + 1 - camZ) * deltaDistZ - end + if dirX < 0 then stepX, sideDistX = -1, (camX - mapX) * deltaDistX + else stepX, sideDistX = 1, (mapX + 1 - camX) * deltaDistX end + if dirY < 0 then stepY, sideDistY = -1, (camY - mapY) * deltaDistY + else stepY, sideDistY = 1, (mapY + 1 - camY) * deltaDistY end + if dirZ < 0 then stepZ, sideDistZ = -1, (camZ - mapZ) * deltaDistZ + else stepZ, sideDistZ = 1, (mapZ + 1 - camZ) * deltaDistZ end local color = SKY_COLOR local previousSolid = camCellSolid @@ -437,44 +368,27 @@ local function raycastFrame() for _ = 1, MAX_RAY_STEPS do local side if sideDistX < sideDistY and sideDistX < sideDistZ then - sideDistX = sideDistX + deltaDistX - mapX = mapX + stepX - cacheIndex = cacheIndex + stepX * PLANE - side = 1 + sideDistX = sideDistX + deltaDistX; mapX = mapX + stepX; cacheIndex = cacheIndex + stepX * PLANE; side = 1 elseif sideDistY < sideDistZ then - sideDistY = sideDistY + deltaDistY - mapY = mapY + stepY - cacheIndex = cacheIndex + stepY * SIDE - side = 2 + sideDistY = sideDistY + deltaDistY; mapY = mapY + stepY; cacheIndex = cacheIndex + stepY * SIDE; side = 2 else - sideDistZ = sideDistZ + deltaDistZ - mapZ = mapZ + stepZ - cacheIndex = cacheIndex + stepZ - side = 3 + sideDistZ = sideDistZ + deltaDistZ; mapZ = mapZ + stepZ; cacheIndex = cacheIndex + stepZ; side = 3 end if mapX == fpX and mapZ == fpZ and (mapY == fpY or mapY == fpY + 1) then - color = PLAYER_COLOR - break + color = PLAYER_COLOR; break end - local inBounds = mapX >= worldMinX and mapX <= worldMaxX and - mapY >= worldMinY and mapY <= worldMaxY and - mapZ >= worldMinZ and mapZ <= worldMaxZ - + local inBounds = mapX >= worldMinX and mapX <= worldMaxX and mapY >= worldMinY and mapY <= worldMaxY and mapZ >= worldMinZ and mapZ <= worldMaxZ if inBounds then enteredBounds = true local block = worldCache[cacheIndex] if block and not previousSolid then - color = block[side] - break + color = block[side]; break end previousSolid = block ~= nil - elseif enteredBounds then - break - else - previousSolid = false - end + elseif enteredBounds then break + else previousSolid = false end end pixelIndex = pixelIndex + 1 @@ -483,46 +397,163 @@ local function raycastFrame() end end +for i = 1, W * H do pixelColors[i] = SKY_COLOR end +updateRayAxes() +rebuildDrawRuns() + + +-- === RENDERER 2: HIGH QUALITY === +local FACES = { + { 1, 0, 0, {1,0,0}, {1,0,1}, {1,1,1}, {1,1,0}, 1 }, + {-1, 0, 0, {0,0,1}, {0,0,0}, {0,1,0}, {0,1,1}, 1 }, + { 0, 1, 0, {0,1,0}, {1,1,0}, {1,1,1}, {0,1,1}, 2 }, + { 0,-1, 0, {0,0,1}, {1,0,1}, {1,0,0}, {0,0,0}, 2 }, + { 0, 0, 1, {1,0,1}, {0,0,1}, {0,1,1}, {1,1,1}, 3 }, + { 0, 0,-1, {0,0,0}, {1,0,0}, {1,1,0}, {0,1,0}, 3 } +} + +local function isSolid(x, y, z) + if x < 0 or x >= SIDE or y < 0 or y >= SIDE or z < 0 or z >= SIDE then return false end + local idx = x * PLANE + y * SIDE + z + return worldCache[idx] ~= nil +end + +local function renderHologram() + local drawList = getForegroundDrawList() + local displaySize = getDisplaySize() + local screenW, screenH = displaySize.x, displaySize.y + + local fovX = fovY * (W / H) + local fsX = screenW * 0.5 / fovX + local fsY = screenH * 0.5 / fovY + + drawList:AddRectFilled({0, 0}, {screenW, screenH}, SKY_COLOR, 0, 0) + + local faceCount = 0 + local renderFaces = {} + + local pX, pY, pZ = camX, camY, camZ + local cY, sY = m_cos(yaw), m_sin(yaw) + local cP, sP = m_cos(pitch), m_sin(pitch) + local fX = sY * cP + local fY = -sP + local fZ = -cY * cP + + local function project3D(wx, wy, wz) + local dx = wx - pX + local dy = wy - pY + local dz = wz - pZ + local fz_temp = dx * sY - dz * cY + local fz = fz_temp * cP - dy * sP + if fz <= 0.1 then return nil end + local rx = dx * cY + dz * sY + local ry = fz_temp * sP + dy * cP + return { + rx * (fsX / fz) + screenW * 0.5, + screenH * 0.5 - ry * (fsY / fz), + fz + } + end + + for cacheIndex, shades in pairs(worldCache) do + local x = m_floor(cacheIndex / PLANE) + local rem = cacheIndex % PLANE + local y = m_floor(rem / SIDE) + local z = rem % SIDE + + local wx = worldMinX + x + local wy = worldMinY + y + local wz = worldMinZ + z + + local dx = wx + 0.5 - pX + local dy = wy + 0.5 - pY + local dz = wz + 0.5 - pZ + if dx*dx + dy*dy + dz*dz > 900 then goto next_block end + if dx * fX + dy * fY + dz * fZ < 0 then goto next_block end + if isSolid(x+1, y, z) and isSolid(x-1, y, z) and isSolid(x, y+1, z) and isSolid(x, y-1, z) and isSolid(x, y, z+1) and isSolid(x, y, z-1) then goto next_block end + + for _, face in ipairs(FACES) do + local nx, ny, nz = x + face[1], y + face[2], z + face[3] + if not isSolid(nx, ny, nz) then + local v1, v2, v3, v4 = face[4], face[5], face[6], face[7] + local p1 = project3D(wx + v1[1], wy + v1[2], wz + v1[3]) + local p2 = project3D(wx + v2[1], wy + v2[2], wz + v2[3]) + local p3 = project3D(wx + v3[1], wy + v3[2], wz + v3[3]) + local p4 = project3D(wx + v4[1], wy + v4[2], wz + v4[3]) + if p1 and p2 and p3 and p4 then + faceCount = faceCount + 1 + renderFaces[faceCount] = { + depth = (p1[3] + p2[3] + p3[3] + p4[3]) * 0.25, + p1 = {p1[1], p1[2]}, p2 = {p2[1], p2[2]}, p3 = {p3[1], p3[2]}, p4 = {p4[1], p4[2]}, + color = shades[face[8]] + } + end + end + end + ::next_block:: + end + + local pCenter = project3D(playerX, playerY + 0.9, playerZ) + if pCenter then + local px1, px2 = playerX - 0.3, playerX + 0.3 + local py1, py2 = playerY, playerY + 1.8 + local pz1, pz2 = playerZ - 0.45, playerZ + 0.45 + local v = { + project3D(px1, py1, pz1), project3D(px2, py1, pz1), project3D(px2, py2, pz1), project3D(px1, py2, pz1), + project3D(px1, py1, pz2), project3D(px2, py1, pz2), project3D(px2, py2, pz2), project3D(px1, py2, pz2) + } + if v[1] and v[2] and v[3] and v[4] and v[5] and v[6] and v[7] and v[8] then + local pFaces = { + {v[1], v[2], v[3], v[4]}, {v[5], v[6], v[7], v[8]}, {v[1], v[2], v[6], v[5]}, + {v[3], v[4], v[8], v[7]}, {v[1], v[4], v[8], v[5]}, {v[2], v[3], v[7], v[6]} + } + for _, pf in ipairs(pFaces) do + faceCount = faceCount + 1 + renderFaces[faceCount] = { + depth = pCenter[3], + p1 = {pf[1][1], pf[1][2]}, p2 = {pf[2][1], pf[2][2]}, p3 = {pf[3][1], pf[3][2]}, p4 = {pf[4][1], pf[4][2]}, + color = PLAYER_COLOR + } + end + end + end + + table.sort(renderFaces, function(a, b) return a.depth > b.depth end) + local addQuadFilled = drawList.AddQuadFilled + for i = 1, faceCount do + local f = renderFaces[i] + addQuadFilled(drawList, f.p1, f.p2, f.p3, f.p4, f.color) + end +end + -- ========================================== -- 7. EVENT HANDLERS -- ========================================== --- Movement keys are tracked here; configurable keybinds are edge-detected in --- SetupAndRenderEvent because their .value field already represents key state. onEvent("KeyEvent", function(key, action) local keyName = keyMap[key] if keyName then - if action == 1 then - keys[keyName] = true - elseif action == 0 then - keys[keyName] = false - end + if action == 1 then keys[keyName] = true + elseif action == 0 then keys[keyName] = false end end end) --- Mouse wheel adjusts FOV. Only 192 scalar axis values are refreshed. onEvent("MouseEvent", function(button, action) if button ~= 4 then return end - - if action == 4 then - fovY = m_min(fovY + 0.1, 1.8) - elseif action == 3 then - fovY = m_max(fovY - 0.1, 0.1) - else - return - end - updateRayAxes() + if action == 4 then fovY = m_min(fovY + 0.1, 1.8) + elseif action == 3 then fovY = m_max(fovY - 0.1, 0.1) end + + -- ponytail: Renderer 1 needs ray axes updated on FOV change, Renderer 2 calculates it dynamically + if rendererMode == 1 then updateRayAxes() end end) --- This event is faster than TickEvent and explicitly safe for player access. --- Smaller scan batches greatly reduce frame-time spikes at high scan rates. onEvent("SetupAndRenderEvent", function() local oldFpX, oldFpY, oldFpZ = fpX, fpY, fpZ playerX, playerY, playerZ = getPlayerPosition() fpX, fpY, fpZ = m_floor(playerX), m_floor(playerY), m_floor(playerZ) - if fpX ~= oldFpX or fpY ~= oldFpY or fpZ ~= oldFpZ then - raycastDirty = true + if rendererMode == 1 then + if fpX ~= oldFpX or fpY ~= oldFpY or fpZ ~= oldFpZ then raycastDirty = true end end if not camInitialized then @@ -536,12 +567,8 @@ onEvent("SetupAndRenderEvent", function() local rescanDown = RescanKey.value local teleportDown = TeleportToPlayerKey.value - if uiDown and not uiKeyWasDown then - renderVisible = not renderVisible - end - if rescanDown and not rescanKeyWasDown and renderVisible then - resetCache(true) - end + if uiDown and not uiKeyWasDown then renderVisible = not renderVisible end + if rescanDown and not rescanKeyWasDown and renderVisible then resetCache(true) end if teleportDown and not teleportKeyWasDown and renderVisible then camX, camY, camZ = playerX, playerY + 1.6, playerZ notify("Camera teleported to player!") @@ -551,6 +578,22 @@ onEvent("SetupAndRenderEvent", function() rescanKeyWasDown = rescanDown teleportKeyWasDown = teleportDown + if LowQualityToggle.value and HighQualityToggle.value and not OneRenderWarnShowed then + client.notify("Choose only one of the renderers!") + OneRenderWarnShowed = true + elseif LowQualityToggle.value and rendererMode ~= 1 and not OneRenderWarnShowed then + rendererMode = 1 + raycastDirty = true + notify("Switched to Low Quality renderer") + elseif HighQualityToggle.value and rendererMode ~= 2 and not OneRenderWarnShowed then + rendererMode = 2 + notify("Switched to High Quality renderer") + end + + if LowQualityToggle.value ~= HighQualityToggle.value then + OneRenderWarnShowed = false + end + updateScan(getTime()) end) @@ -564,24 +607,19 @@ onEvent("ChangeDimensionEvent", function() raycastDirty = true end) --- RenderEvent only handles ImGui and cached numeric state. No player/world API --- calls occur here, matching Flarial's event safety contract. onEvent("RenderEvent", function() - if getScreenName() ~= "inventory_screen" then - renderVisible = false - end + if getScreenName() ~= "inventory_screen" then renderVisible = false end if not renderVisible then return end local dt = getDeltaTime() if dt < 0 then dt = 0 end if dt > 0.05 then dt = 0.05 end - local changed = false local rotationDelta = ROTATE_SPEED * dt - if keys["left"] then yaw = yaw - rotationDelta; changed = true end - if keys["right"] then yaw = yaw + rotationDelta; changed = true end - if keys["up"] then pitch = pitch - rotationDelta; changed = true end - if keys["down"] then pitch = pitch + rotationDelta; changed = true end + if keys["left"] then yaw = yaw - rotationDelta end + if keys["right"] then yaw = yaw + rotationDelta end + if keys["up"] then pitch = pitch - rotationDelta end + if keys["down"] then pitch = pitch + rotationDelta end if pitch > 1.5 then pitch = 1.5 end if pitch < -1.5 then pitch = -1.5 end @@ -596,24 +634,31 @@ onEvent("RenderEvent", function() if keys["s"] then camX = camX - sinYaw * speed; camZ = camZ + cosYaw * speed end if keys["a"] then camX = camX - cosYaw * speed; camZ = camZ - sinYaw * speed end if keys["d"] then camX = camX + cosYaw * speed; camZ = camZ + sinYaw * speed end - changed = true - end - if keys["space"] then camY = camY + speed; changed = true end - if keys["c"] then camY = camY - speed; changed = true end - if changed then raycastDirty = true end - - local now = getTime() - if raycastDirty and now - lastRaycastTime >= RAYCAST_INTERVAL_MS then - lastRaycastTime = now - raycastFrame() - rebuildDrawRuns() - raycastDirty = false end + if keys["space"] then camY = camY + speed end + if keys["c"] then camY = camY - speed end - local drawList = getForegroundDrawList() - local addRectFilled = drawList.AddRectFilled - for i = 1, drawRunCount do - local run = drawRuns[i] - addRectFilled(drawList, run.p1, run.p2, run.color, 0, 0) + -- ponytail: Strict branching. No cross-contamination of render loops. + if rendererMode == 1 then + if keys["w"] or keys["s"] or keys["a"] or keys["d"] or keys["space"] or keys["c"] or keys["left"] or keys["right"] or keys["up"] or keys["down"] then + raycastDirty = true + end + + local now = getTime() + if raycastDirty and now - lastRaycastTime >= RAYCAST_INTERVAL_MS then + lastRaycastTime = now + raycastFrame() + rebuildDrawRuns() + raycastDirty = false + end + + local drawList = getForegroundDrawList() + local addRectFilled = drawList.AddRectFilled + for i = 1, drawRunCount do + local run = drawRuns[i] + addRectFilled(drawList, run.p1, run.p2, run.color, 0, 0) + end + elseif rendererMode == 2 then + renderHologram() end -end) +end) \ No newline at end of file diff --git a/module/Flappy bird.lua b/module/Flappy bird.lua new file mode 100644 index 0000000..92e8dc2 --- /dev/null +++ b/module/Flappy bird.lua @@ -0,0 +1,310 @@ +name = "Flappy Bird" +description = "Flappy Bird on a virtual Game Boy inside the inventory" +author = "zebedelu" + +-- Configs +local openKey = settings.addKeybind("Open Flappy Bird", "Opens the game when in the inventory") +local fpsTextBox = settings.addSlider("FPS", "The FPS of the flappy bird", 24, 120, 12, false) + +local GAME_FPS = math.floor(tonumber(fpsTextBox.value)) +local frame_delay = 1.0 / GAME_FPS + +-- Game Boy Base Dimensions (Logical) +local GB_W, GB_H = 440, 680 +local SCR_W, SCR_H = 320, 280 + +-- State +local is_open = false +local state = "MENU" -- MENU, PLAYING, GAMEOVER +local score = 0 +local high_score = 0 +local bird_x, bird_y, bird_vel = 80, SCR_H/2, 0 +local bird_rot = 0 +local has_jumped = false +local pipes = {} +local last_pipe_time = 0 +local bg1, bg2 = 0, 0 +local last_frame = os.clock() + +-- Physics & Game Balance +local GRAVITY = 800 +local JUMP_VEL = 300 +local PIPE_SPEED = 150 +local PIPE_GAP = 120 +local PIPE_W = 50 + +function resetGame() + state = "MENU" + score = 0 + bird_x, bird_y, bird_vel = 80, SCR_H/2, 0 + bird_rot = 0 + has_jumped = false + pipes = {} + last_pipe_time = os.clock() +end + +function startGame() + state = "PLAYING" + score = 0 + bird_x, bird_y, bird_vel = 80, SCR_H/2, 0 + bird_rot = 0 + has_jumped = false + pipes = {} + last_pipe_time = os.clock() +end + +function gameOver() + if state == "PLAYING" then + state = "GAMEOVER" + if score > high_score then high_score = score end + end +end + +-- Ponytail: Helper for clouds +local function drawCloud(draw, x, y, s, alpha) + draw:AddCircleFilled({x, y}, 18 * s, {255, 255, 255, alpha}, 16) + draw:AddCircleFilled({x + 20 * s, y - 8 * s}, 24 * s, {255, 255, 255, alpha}, 16) + draw:AddCircleFilled({x + 45 * s, y + 2 * s}, 20 * s, {255, 255, 255, alpha}, 16) + draw:AddCircleFilled({x + 22 * s, y + 10 * s}, 18 * s, {255, 255, 255, alpha}, 16) +end + +-- Ponytail: Dynamic button that accepts scale and centers correctly +local function drawButton(draw, abs_x, abs_y, w, h, text, scale) + local m = ImGui.GetMousePos() + local mx, my = m.x or m[1], m.y or m[2] + local hover = mx >= abs_x and mx <= abs_x + w and my >= abs_y and my <= abs_y + h + local col = hover and {50, 150, 250, 255} or {80, 80, 80, 255} + + draw:AddRectFilled({abs_x, abs_y}, {abs_x + w, abs_y + h}, col, 4 * scale, 0) + + local font_size = 14 * scale + local offset_x = string.len(text) * (font_size * 0.28) + draw:AddText({abs_x + (w/2) - offset_x, abs_y + (h/2) - (font_size/2)}, {255, 255, 255, 255}, font_size, text) + return hover and ImGui.IsMouseClicked(0) +end + +onEvent("KeyEvent", function(key, isDown) + GAME_FPS = math.floor(tonumber(fpsTextBox.value)) + frame_delay = 1.0 / GAME_FPS + if openKey.value == true and isDown then + if client.getScreenName() == "inventory_screen" then + is_open = not is_open + if not is_open then resetGame() end + else + is_open = false + end + end + + if is_open and state == "PLAYING" and key == 32 and isDown then + if not has_jumped then + has_jumped = true + last_pipe_time = os.clock() + end + bird_vel = -JUMP_VEL + end +end) + +onEvent("RenderEvent", function() + local screen = client.getScreenName() + if not is_open or screen ~= "inventory_screen" then + if is_open and screen ~= "inventory_screen" then + is_open = false + resetGame() + end + return + end + + -- 1. Time and Scale Calculation + local now = os.clock() + local dt = now - last_frame + local disp = ImGui.GetDisplaySize() + local dx, dy = disp.x or disp[1], disp.y or disp[2] + + local scale = (dx * 0.8) / GB_W + if GB_H * scale > dy * 0.9 then + scale = (dy * 0.9) / GB_H + end + + local gx = (dx - GB_W * scale) / 2 + local gy = (dy - GB_H * scale) / 2 + local sx = gx + 60 * scale + local sy = gy + 110 * scale + local scr_w_s = SCR_W * scale + local scr_h_s = SCR_H * scale + + -- 2. Game Logic (24 FPS) + if dt >= frame_delay then + last_frame = now + + if state == "PLAYING" then + if has_jumped then + bird_vel = bird_vel + GRAVITY * dt + bird_y = bird_y + bird_vel * dt + bird_rot = util.clamp(bird_vel / JUMP_VEL * 0.4, -0.4, 0.5) + + for i, p in ipairs(pipes) do + p.x = p.x - PIPE_SPEED * dt + if not p.scored and p.x + PIPE_W < bird_x then + p.scored = true + score = score + 1 + end + end + while #pipes > 0 and pipes[1].x < -PIPE_W do table.remove(pipes, 1) end + + local interval = (#pipes == 0) and 2.0 or 1.5 + if now - last_pipe_time > interval then + table.insert(pipes, { x = SCR_W, gap_y = math.random(60, SCR_H - 90), scored = false }) + last_pipe_time = now + end + + if bird_y < 0 or bird_y > SCR_H - 20 then gameOver() end + for i, p in ipairs(pipes) do + if p.x < bird_x + 10 and p.x + PIPE_W > bird_x - 10 then + if bird_y - 10 < p.gap_y - PIPE_GAP/2 or bird_y + 10 > p.gap_y + PIPE_GAP/2 then + gameOver() + end + end + end + end + + -- Ponytail: 480 = 4 * 120px. Modulo greater than the screen ensures it spawns off-screen and disappears off-screen + bg1 = (bg1 - 10 * dt) % 480 + bg2 = (bg2 - 30 * dt) % 480 + end + end + + -- 3. Rendering + local draw = ImGui.GetForegroundDrawList() + + -- A. Screen Background (Blue) + draw:AddRectFilled({sx, sy}, {sx + scr_w_s, sy + scr_h_s}, {150, 220, 255, 255}, 0, 0) + + -- Section for Clouds + for i = 0, 2 do + local cx = sx + ((bg2 + i * 120) % 365) * scale + local cy = sy + 40 * scale + drawCloud(draw, cx-50, cy, scale * 0.6, 220) + end + + -- C. Static Ground + draw:AddRectFilled({sx, sy + (SCR_H - 20) * scale}, {sx + scr_w_s, sy + scr_h_s}, {60, 180, 100, 255}, 0, 0) + draw:AddRectFilled({sx, sy + (SCR_H - 20) * scale}, {sx + scr_w_s, sy + (SCR_H - 15) * scale}, {150, 230, 80, 255}, 0, 0) + + -- D. Pipes + for i, p in ipairs(pipes) do + local px = sx + p.x * scale + local py_top = sy + (p.gap_y - PIPE_GAP/2) * scale + local py_bot = sy + (p.gap_y + PIPE_GAP/2) * scale + local pw = PIPE_W * scale + + draw:AddRectFilled({px, sy}, {px + pw, py_top}, {100, 200, 100, 255}, 0, 0) + draw:AddRectFilled({px - 5 * scale, py_top - 20 * scale}, {px + pw + 5 * scale, py_top}, {80, 180, 80, 255}, 0, 0) + draw:AddRectFilled({px, py_bot}, {px + pw, sy + (SCR_H - 20) * scale}, {100, 200, 100, 255}, 0, 0) + draw:AddRectFilled({px - 5 * scale, py_bot}, {px + pw + 5 * scale, py_bot + 20 * scale}, {80, 180, 80, 255}, 0, 0) + end + + -- E. Bird + local wing_off = (math.floor(os.clock() * 10) % 2 == 0) and -5 or 5 + local bx, by = sx + bird_x * scale, sy + bird_y * scale + local cr, sr = math.cos(bird_rot), math.sin(bird_rot) + local function rot(px, py) + local dx, dy = px * scale, py * scale + return {bx + dx * cr - dy * sr, by + dx * sr + dy * cr} + end + draw:AddCircleFilled({bx, by}, 10 * scale, {255, 220, 0, 255}, 12) + draw:AddTriangleFilled(rot(5, -2), rot(15, 0), rot(5, 2), {255, 150, 0, 255}) + draw:AddCircleFilled(rot(4, -3), 2 * scale, {0, 0, 0, 255}, 4) + draw:AddTriangleFilled(rot(-5, wing_off), rot(5, 0), rot(-5, 5), {255, 200, 0, 255}) + + -- F. UI and Buttons + if state == "PLAYING" then + local fs = 20 * scale + local s_offset = string.len(tostring(score)) * (fs * 0.3) + draw:AddText({sx + (scr_w_s/2) - (s_offset/2), sy + 10 * scale}, {255, 255, 255, 255}, fs, tostring(score)) + elseif state == "MENU" then + draw:AddRectFilled({sx, sy}, {sx + scr_w_s, sy + scr_h_s}, {0, 0, 0, 150}, 0, 0) + + local title = "FLAPPY BIRD" + local tfs = 24 * scale + local t_off = string.len(title) * (tfs * 0.28) + draw:AddText({sx + (scr_w_s/2) - (t_off/2) - 40, sy + 40 * scale}, {255, 255, 0, 255}, tfs, title) + + local sub = "High Score: " .. tostring(high_score) + local sfs = 16 * scale + local s_off = string.len(sub) * (sfs * 0.28) + draw:AddText({sx + (scr_w_s/2) - (s_off/2) - 25, sy + 90 * scale}, {255, 255, 255, 255}, sfs, sub) + + local btn_w, btn_h = 110 * scale, 35 * scale + local btn_x = sx + (scr_w_s / 2) - (btn_w / 2) + local btn_y = sy + scr_h_s * 0.65 + if drawButton(draw, btn_x, btn_y, btn_w, btn_h, "Play", scale) then startGame() end + elseif state == "GAMEOVER" then + draw:AddRectFilled({sx, sy}, {sx + scr_w_s, sy + scr_h_s}, {0, 0, 0, 150}, 0, 0) + + local title = "GAME OVER" + local tfs = 24 * scale + local t_off = string.len(title) * (tfs * 0.28) + draw:AddText({sx + (scr_w_s/2) - (t_off/2) - 40, sy + 40 * scale}, {255, 0, 0, 255}, tfs, title) + + local p_txt = "Score: " .. tostring(score) + local pfs = 16 * scale + local p_off = string.len(p_txt) * (pfs * 0.28) + draw:AddText({sx + (scr_w_s/2) - (p_off/2) - 25, sy + 90 * scale}, {255, 255, 255, 255}, pfs, p_txt) + + local r_txt = "High Score: " .. tostring(high_score) + local rfs = 16 * scale + local r_off = string.len(r_txt) * (rfs * 0.28) + draw:AddText({sx + (scr_w_s/2) - (r_off/2) - 25, sy + 120 * scale}, {255, 255, 0, 255}, rfs, r_txt) + + local btn_w, btn_h = 110 * scale, 35 * scale + local btn_x = sx + (scr_w_s / 2) - (btn_w / 2) + local btn1_y = sy + scr_h_s * 0.65 + local btn2_y = sy + scr_h_s * 0.82 + + if drawButton(draw, btn_x, btn1_y, btn_w, btn_h, "Restart", scale) then startGame() end + if drawButton(draw, btn_x, btn2_y, btn_w, btn_h, "Exit", scale) then is_open = false; resetGame() end + end + + -- G. Masking (GameBoy Frame) + local bezel = 32 * scale + -- Black around the screen (Border) + draw:AddRectFilled({sx - bezel, sy - bezel}, {sx + scr_w_s + bezel, sy}, {50, 50, 50, 255}, 0, 0) + draw:AddRectFilled({sx - bezel, sy + scr_h_s}, {sx + scr_w_s + bezel, sy + scr_h_s + bezel}, {50, 50, 50, 255}, 0, 0) + draw:AddRectFilled({sx - bezel, sy}, {sx, sy + scr_h_s}, {50, 50, 50, 255}, 0, 0) + draw:AddRectFilled({sx + scr_w_s, sy}, {sx + scr_w_s + bezel, sy + scr_h_s}, {50, 50, 50, 255}, 0, 0) + + -- Beige Chassis (Final layer that hides everything leaking outside) + -- Top + draw:AddRectFilled({gx, gy+60}, {gx + GB_W * scale, sy - bezel}, {220, 210, 190, 255}, 12 * scale, 3) + -- Bottom + draw:AddRectFilled({gx, sy + scr_h_s + bezel}, {gx + GB_W * scale, gy + GB_H * scale}, {220, 210, 190, 255}, 12 * scale, 12) + -- Left + draw:AddRectFilled({gx, sy - bezel - 20}, {sx - bezel, sy + scr_h_s + bezel + 20}, {220, 210, 190, 255}, 0, 0) + -- Right + draw:AddRectFilled({sx + scr_w_s + bezel, sy - bezel - 20}, {gx + GB_W * scale, sy + scr_h_s + bezel + 20}, {220, 210, 190, 255}, 0, 0) + -- H. DMG Details (Reference) + -- DOT MATRIX Text + draw:AddText({sx, sy - 50 * scale}, {80, 80, 80, 255}, 15 * scale, "DOT MATRIX WITH STEREO SOUND") + + -- D-Pad (Black Cross with center) + draw:AddRectFilled({gx + 80 * scale - 35, gy + 500 * scale - 35}, {gx + 110 * scale - 35, gy + 570 * scale - 35}, {40, 40, 40, 255}, 0, 0) + draw:AddRectFilled({gx + 60 * scale - 35, gy + 520 * scale - 35}, {gx + 130 * scale - 35, gy + 550 * scale - 35}, {40, 40, 40, 255}, 0, 0) + + -- A/B Buttons (Magenta) + draw:AddCircleFilled({gx + 400 * scale, gy + 520 * scale}, 22 * scale, {180, 50, 100, 255}, 12) + draw:AddCircleFilled({gx + 340 * scale, gy + 550 * scale}, 22 * scale, {180, 50, 100, 255}, 12) + draw:AddText({gx + 395 * scale, gy + 510 * scale}, {255, 50, 50, 255}, 20 * scale, "A") + draw:AddText({gx + 335 * scale, gy + 540 * scale}, {255, 50, 50, 255}, 20 * scale, "B") + + -- Start/Select (Gray pill-shaped) + draw:AddLine({gx + 166 * scale, gy + 590 * scale}, {gx + 210 * scale, gy + 580 * scale}, {100, 100, 100, 255}, 12 * scale) + draw:AddLine({gx + 226 * scale, gy + 590 * scale}, {gx + 270 * scale, gy + 580 * scale}, {100, 100, 100, 255}, 12 * scale) + draw:AddText({gx + 170 * scale, gy + 600 * scale}, {80, 80, 80, 255}, 7 * scale, "SELECT") + draw:AddText({gx + 230 * scale, gy + 600 * scale}, {80, 80, 80, 255}, 7 * scale, "START") + + -- Speaker (Diagonal lines) + for i=0, 5 do + local off = i * 10 * scale + draw:AddLine({gx + 330 * scale + off, gy + 620 * scale - i * 8}, {gx + 350 * scale + off, gy + 660 * scale - i * 8}, {80, 80, 80, 255}, 2 * scale) + end +end) \ No newline at end of file diff --git a/module/Notify When Called.lua b/module/Notify When Called.lua index 8dc770e..ecc0fc3 100644 --- a/module/Notify When Called.lua +++ b/module/Notify When Called.lua @@ -60,13 +60,18 @@ local function findBestMatch(word, text) end local PlayerName +local FILE_PATH = 'Scripts\\Data\\' settings.addHeader("Configure Mention Sound") local Tolerance = settings.addSlider("Tolerance", "How accurate must the name be? (default: 100%)", 90, 100, 20, false) -local FilePath = settings.addTextBox("File path", "default: 'Scripts/Data/MentionedSound.mp3'", "Scripts\\Data\\MentionedSound.mp3", 150) +local FilePath = settings.addTextBox("File path", "default: 'MentionedSound.mp3'", "MentionedSound.mp3", 150) local Notification = settings.addToggle("Notification", "Notification in hotbar when called", true) +local NotiWhenAudioNotFound = settings.addToggle("No file found notification", "Notification in hotbar when not audio file found", true) function onEnable() + client.displayLocalMessage("To costumize the audio put the audio file in") + client.displayLocalMessage("%localappdata%/Flarial/Client/Scripts/Data OR The Data folder in Scripts") + client.displayLocalMessage("And configure the name of the file in module settings") PlayerName = "@"..player.name() end @@ -80,9 +85,15 @@ onEvent("ChatReceiveEvent", function(message, AuthorName, type) and "@"..AuthorName ~= PlayerName) or string.find(message, "@here") then if FilePath.value ~= "" then - audio.play(FilePath.value) + NoError = audio.play(FILE_PATH..FilePath.value) + if not NoError then + audio.play(FILE_PATH.."MentionedSound.mp3") + if NotiWhenAudioNotFound.value then + client.notify(string.format("No Audio File Found: %s", tostring(FilePath.value))) + end + end else - audio.play("Scripts\\Data\\MentionedSound.mp3") + audio.play(FILE_PATH.."MentionedSound.mp3") end if Notification.value then