diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index cbd2f1a2..f3722d3a 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -37,6 +37,8 @@ jobs: run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} id: deploy - name: Set deployment alias + # only if on branch next + if: github.ref == 'refs/heads/next' run: vercel alias set ${{ steps.deploy.outputs.stdout }} ${{ secrets.TEST_PREVIEW_DOMAIN }} --token=${{ secrets.VERCEL_TOKEN }} - uses: mshick/add-pr-comment@v2 with: diff --git a/README.MD b/README.MD index 36d20865..029786a7 100644 --- a/README.MD +++ b/README.MD @@ -83,6 +83,20 @@ You can also drag and drop any .dat or .mca (region files) into the browser wind world chunks have a *yellow* border, hostile mobs have a *red* outline, passive mobs have a *green* outline, players have a *blue* outline. +### Query Parameters + +Press `Y` to set query parameters to url of your current game state. + +- `?server=` - Display connect screen to the server on load +- `?username=` - Set the username on load +- `?proxy=` - Set the proxy server address on load +- `?version=` - Set the version on load +- `?reconnect=true` - Reconnect to the server on page reloads. Available in **dev mode only** and very useful on server testing. + +- `?loadSave=` - Load the save on load with the specified folder name (not title) +- `?singleplayer=1` - Create empty world on load. Nothing will be saved +- `?noSave=true` - Disable auto save on unload / disconnect / export. Only manual save with `/save` command will work + ### Notable Things that Power this Project - [Mineflayer](https://github.com/PrismarineJS/mineflayer) - Handles all client-side communications with the server (including the builtin one) - forked diff --git a/package.json b/package.json index 2b408359..b28f786e 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "stats.js": "^0.17.0", "tabbable": "^6.2.0", "title-case": "3.x", + "ua-parser-js": "^1.0.37", "valtio": "^1.11.1", "workbox-build": "^7.0.0" }, @@ -83,6 +84,7 @@ "@types/react-transition-group": "^4.4.7", "@types/stats.js": "^0.17.1", "@types/three": "0.128.0", + "@types/ua-parser-js": "^0.7.39", "@xmcl/installer": "^5.1.0", "assert": "^2.0.0", "browserify-zlib": "^0.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ad1edfc..e394cb98 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -141,6 +141,9 @@ importers: title-case: specifier: 3.x version: 3.0.3 + ua-parser-js: + specifier: ^1.0.37 + version: 1.0.37 valtio: specifier: ^1.11.1 version: 1.11.2(@types/react@18.2.20)(react@18.2.0) @@ -185,6 +188,9 @@ importers: '@types/three': specifier: 0.128.0 version: 0.128.0 + '@types/ua-parser-js': + specifier: ^0.7.39 + version: 0.7.39 '@xmcl/installer': specifier: ^5.1.0 version: 5.1.0 @@ -235,7 +241,7 @@ importers: version: 1.0.0 minecraft-inventory-gui: specifier: github:zardoy/minecraft-inventory-gui#next - version: github.com/zardoy/minecraft-inventory-gui/69003692b3041d94a420a65c7d3cc1b37737e838(@types/react@18.2.20)(react@18.2.0) + version: github.com/zardoy/minecraft-inventory-gui/e794b5d44d9cdaf58c4bf9fc5fbbc3a729f4b447(@types/react@18.2.20)(react@18.2.0) mineflayer: specifier: github:PrismarineJS/mineflayer version: github.com/PrismarineJS/mineflayer/cc98f1307e3ab48477d2a9ff29da4447f42b30bc @@ -5216,6 +5222,10 @@ packages: /@types/trusted-types@2.0.3: resolution: {integrity: sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==} + /@types/ua-parser-js@0.7.39: + resolution: {integrity: sha512-P/oDfpofrdtF5xw433SPALpdSchtJmY7nsJItf8h3KXqOslkbySh8zq4dSWXH2oTjRvJ5PczVEoCZPow6GicLg==} + dev: true + /@types/unist@2.0.8: resolution: {integrity: sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==} dev: true @@ -5591,7 +5601,7 @@ packages: dependencies: change-case: 4.1.2 colors: 1.4.0 - diamond-square: github.com/zardoy/diamond-square/789d7090748ddcae22bb89908db15ba448bdfbb0 + diamond-square: github.com/zardoy/diamond-square/915fce8e27fe8eb45464d89b9563956afa4f7687 emit-then: 2.0.0 event-promise: 0.0.1 exit-hook: 2.2.1 @@ -14079,6 +14089,10 @@ packages: hasBin: true dev: true + /ua-parser-js@1.0.37: + resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==} + dev: false + /ufo@1.3.1: resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==} dev: true @@ -15168,8 +15182,8 @@ packages: async: 2.6.4 dev: false - github.com/zardoy/diamond-square/789d7090748ddcae22bb89908db15ba448bdfbb0: - resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/789d7090748ddcae22bb89908db15ba448bdfbb0} + github.com/zardoy/diamond-square/915fce8e27fe8eb45464d89b9563956afa4f7687: + resolution: {tarball: https://codeload.github.com/zardoy/diamond-square/tar.gz/915fce8e27fe8eb45464d89b9563956afa4f7687} name: diamond-square version: 1.3.0 dependencies: @@ -15179,9 +15193,9 @@ packages: vec3: 0.1.8 dev: false - github.com/zardoy/minecraft-inventory-gui/69003692b3041d94a420a65c7d3cc1b37737e838(@types/react@18.2.20)(react@18.2.0): - resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/69003692b3041d94a420a65c7d3cc1b37737e838} - id: github.com/zardoy/minecraft-inventory-gui/69003692b3041d94a420a65c7d3cc1b37737e838 + github.com/zardoy/minecraft-inventory-gui/e794b5d44d9cdaf58c4bf9fc5fbbc3a729f4b447(@types/react@18.2.20)(react@18.2.0): + resolution: {tarball: https://codeload.github.com/zardoy/minecraft-inventory-gui/tar.gz/e794b5d44d9cdaf58c4bf9fc5fbbc3a729f4b447} + id: github.com/zardoy/minecraft-inventory-gui/e794b5d44d9cdaf58c4bf9fc5fbbc3a729f4b447 name: minecraft-inventory-gui version: 1.0.1 dependencies: diff --git a/prismarine-viewer/viewer/lib/moreBlockDataGenerated.json b/prismarine-viewer/viewer/lib/moreBlockDataGenerated.json index 152d1f83..a2ca2087 100644 --- a/prismarine-viewer/viewer/lib/moreBlockDataGenerated.json +++ b/prismarine-viewer/viewer/lib/moreBlockDataGenerated.json @@ -179,5 +179,536 @@ "flowering_azalea": true, "frogspawn": true, "decorated_pot": true + }, + "colors": { + "stone": "rgb(112, 112, 112)", + "granite": "rgb(151, 109, 77)", + "polished_granite": "rgb(151, 109, 77)", + "diorite": "rgb(255, 252, 245)", + "polished_diorite": "rgb(255, 252, 245)", + "andesite": "rgb(112, 112, 112)", + "polished_andesite": "rgb(112, 112, 112)", + "grass_block": "rgb(127, 178, 56)", + "dirt": "rgb(151, 109, 77)", + "coarse_dirt": "rgb(151, 109, 77)", + "podzol": "rgb(129, 86, 49)", + "cobblestone": "rgb(112, 112, 112)", + "oak_planks": "rgb(143, 119, 72)", + "spruce_planks": "rgb(129, 86, 49)", + "birch_planks": "rgb(247, 233, 163)", + "jungle_planks": "rgb(151, 109, 77)", + "acacia_planks": "rgb(216, 127, 51)", + "cherry_planks": "rgb(209, 177, 161)", + "dark_oak_planks": "rgb(102, 76, 51)", + "mangrove_planks": "rgb(153, 51, 51)", + "bamboo_planks": "rgb(229, 229, 51)", + "bamboo_mosaic": "rgb(229, 229, 51)", + "oak_sapling": "rgb(0, 124, 0)", + "spruce_sapling": "rgb(0, 124, 0)", + "birch_sapling": "rgb(0, 124, 0)", + "jungle_sapling": "rgb(0, 124, 0)", + "acacia_sapling": "rgb(0, 124, 0)", + "cherry_sapling": "rgb(242, 127, 165)", + "dark_oak_sapling": "rgb(0, 124, 0)", + "mangrove_propagule": "rgb(0, 124, 0)", + "bedrock": "rgb(112, 112, 112)", + "water": "rgb(64, 64, 255)", + "lava": "rgb(255, 0, 0)", + "sand": "rgb(247, 233, 163)", + "suspicious_sand": "rgb(247, 233, 163)", + "red_sand": "rgb(216, 127, 51)", + "gravel": "rgb(112, 112, 112)", + "suspicious_gravel": "rgb(112, 112, 112)", + "gold_ore": "rgb(112, 112, 112)", + "deepslate_gold_ore": "rgb(100, 100, 100)", + "iron_ore": "rgb(112, 112, 112)", + "deepslate_iron_ore": "rgb(100, 100, 100)", + "coal_ore": "rgb(112, 112, 112)", + "deepslate_coal_ore": "rgb(100, 100, 100)", + "nether_gold_ore": "rgb(112, 2, 0)", + "mangrove_roots": "rgb(129, 86, 49)", + "muddy_mangrove_roots": "rgb(129, 86, 49)", + "oak_wood": "rgb(143, 119, 72)", + "spruce_wood": "rgb(129, 86, 49)", + "birch_wood": "rgb(247, 233, 163)", + "jungle_wood": "rgb(151, 109, 77)", + "acacia_wood": "rgb(76, 76, 76)", + "cherry_wood": "rgb(57, 41, 35)", + "dark_oak_wood": "rgb(102, 76, 51)", + "mangrove_wood": "rgb(153, 51, 51)", + "stripped_oak_wood": "rgb(143, 119, 72)", + "stripped_spruce_wood": "rgb(129, 86, 49)", + "stripped_birch_wood": "rgb(247, 233, 163)", + "stripped_jungle_wood": "rgb(151, 109, 77)", + "stripped_acacia_wood": "rgb(216, 127, 51)", + "stripped_cherry_wood": "rgb(160, 77, 78)", + "stripped_dark_oak_wood": "rgb(102, 76, 51)", + "oak_leaves": "rgb(0, 124, 0)", + "spruce_leaves": "rgb(0, 124, 0)", + "birch_leaves": "rgb(0, 124, 0)", + "jungle_leaves": "rgb(0, 124, 0)", + "acacia_leaves": "rgb(0, 124, 0)", + "cherry_leaves": "rgb(242, 127, 165)", + "dark_oak_leaves": "rgb(0, 124, 0)", + "mangrove_leaves": "rgb(0, 124, 0)", + "azalea_leaves": "rgb(0, 124, 0)", + "flowering_azalea_leaves": "rgb(0, 124, 0)", + "sponge": "rgb(229, 229, 51)", + "wet_sponge": "rgb(229, 229, 51)", + "lapis_ore": "rgb(112, 112, 112)", + "deepslate_lapis_ore": "rgb(100, 100, 100)", + "lapis_block": "rgb(74, 128, 255)", + "dispenser": "rgb(112, 112, 112)", + "sandstone": "rgb(247, 233, 163)", + "chiseled_sandstone": "rgb(247, 233, 163)", + "cut_sandstone": "rgb(247, 233, 163)", + "note_block": "rgb(143, 119, 72)", + "sticky_piston": "rgb(112, 112, 112)", + "cobweb": "rgb(199, 199, 199)", + "grass": "rgb(0, 124, 0)", + "fern": "rgb(0, 124, 0)", + "dead_bush": "rgb(143, 119, 72)", + "seagrass": "rgb(64, 64, 255)", + "tall_seagrass": "rgb(64, 64, 255)", + "piston": "rgb(112, 112, 112)", + "piston_head": "rgb(112, 112, 112)", + "white_wool": "rgb(255, 255, 255)", + "orange_wool": "rgb(216, 127, 51)", + "magenta_wool": "rgb(178, 76, 216)", + "light_blue_wool": "rgb(102, 153, 216)", + "yellow_wool": "rgb(229, 229, 51)", + "lime_wool": "rgb(127, 204, 25)", + "pink_wool": "rgb(242, 127, 165)", + "gray_wool": "rgb(76, 76, 76)", + "light_gray_wool": "rgb(153, 153, 153)", + "cyan_wool": "rgb(76, 127, 153)", + "purple_wool": "rgb(127, 63, 178)", + "blue_wool": "rgb(51, 76, 178)", + "brown_wool": "rgb(102, 76, 51)", + "green_wool": "rgb(102, 127, 51)", + "red_wool": "rgb(153, 51, 51)", + "black_wool": "rgb(25, 25, 25)", + "moving_piston": "rgb(112, 112, 112)", + "dandelion": "rgb(0, 124, 0)", + "torchflower": "rgb(0, 124, 0)", + "poppy": "rgb(0, 124, 0)", + "blue_orchid": "rgb(0, 124, 0)", + "allium": "rgb(0, 124, 0)", + "azure_bluet": "rgb(0, 124, 0)", + "red_tulip": "rgb(0, 124, 0)", + "orange_tulip": "rgb(0, 124, 0)", + "white_tulip": "rgb(0, 124, 0)", + "pink_tulip": "rgb(0, 124, 0)", + "oxeye_daisy": "rgb(0, 124, 0)", + "cornflower": "rgb(0, 124, 0)", + "wither_rose": "rgb(0, 124, 0)", + "lily_of_the_valley": "rgb(0, 124, 0)", + "brown_mushroom": "rgb(102, 76, 51)", + "red_mushroom": "rgb(153, 51, 51)", + "gold_block": "rgb(250, 238, 77)", + "iron_block": "rgb(167, 167, 167)", + "bricks": "rgb(153, 51, 51)", + "tnt": "rgb(255, 0, 0)", + "bookshelf": "rgb(143, 119, 72)", + "chiseled_bookshelf": "rgb(143, 119, 72)", + "mossy_cobblestone": "rgb(112, 112, 112)", + "obsidian": "rgb(25, 25, 25)", + "fire": "rgb(255, 0, 0)", + "soul_fire": "rgb(102, 153, 216)", + "spawner": "rgb(112, 112, 112)", + "chest": "rgb(143, 119, 72)", + "diamond_ore": "rgb(112, 112, 112)", + "deepslate_diamond_ore": "rgb(100, 100, 100)", + "diamond_block": "rgb(92, 219, 213)", + "crafting_table": "rgb(143, 119, 72)", + "wheat": "rgb(0, 124, 0)", + "farmland": "rgb(151, 109, 77)", + "furnace": "rgb(112, 112, 112)", + "oak_sign": "rgb(143, 119, 72)", + "birch_sign": "rgb(247, 233, 163)", + "acacia_sign": "rgb(216, 127, 51)", + "oak_wall_sign": "rgb(143, 119, 72)", + "birch_wall_sign": "rgb(247, 233, 163)", + "acacia_wall_sign": "rgb(216, 127, 51)", + "birch_hanging_sign": "rgb(247, 233, 163)", + "acacia_hanging_sign": "rgb(216, 127, 51)", + "cherry_hanging_sign": "rgb(160, 77, 78)", + "crimson_hanging_sign": "rgb(148, 63, 97)", + "warped_hanging_sign": "rgb(58, 142, 140)", + "bamboo_hanging_sign": "rgb(229, 229, 51)", + "spruce_wall_hanging_sign": "rgb(143, 119, 72)", + "birch_wall_hanging_sign": "rgb(247, 233, 163)", + "acacia_wall_hanging_sign": "rgb(216, 127, 51)", + "cherry_wall_hanging_sign": "rgb(160, 77, 78)", + "crimson_wall_hanging_sign": "rgb(148, 63, 97)", + "warped_wall_hanging_sign": "rgb(58, 142, 140)", + "bamboo_wall_hanging_sign": "rgb(229, 229, 51)", + "stone_pressure_plate": "rgb(112, 112, 112)", + "iron_door": "rgb(167, 167, 167)", + "redstone_ore": "rgb(112, 112, 112)", + "deepslate_redstone_ore": "rgb(100, 100, 100)", + "snow": "rgb(255, 255, 255)", + "ice": "rgb(160, 160, 255)", + "snow_block": "rgb(255, 255, 255)", + "cactus": "rgb(0, 124, 0)", + "clay": "rgb(164, 168, 184)", + "sugar_cane": "rgb(0, 124, 0)", + "jukebox": "rgb(151, 109, 77)", + "pumpkin": "rgb(216, 127, 51)", + "netherrack": "rgb(112, 2, 0)", + "soul_sand": "rgb(102, 76, 51)", + "soul_soil": "rgb(102, 76, 51)", + "basalt": "rgb(25, 25, 25)", + "polished_basalt": "rgb(25, 25, 25)", + "glowstone": "rgb(247, 233, 163)", + "carved_pumpkin": "rgb(216, 127, 51)", + "jack_o_lantern": "rgb(216, 127, 51)", + "oak_trapdoor": "rgb(143, 119, 72)", + "spruce_trapdoor": "rgb(129, 86, 49)", + "birch_trapdoor": "rgb(247, 233, 163)", + "jungle_trapdoor": "rgb(151, 109, 77)", + "acacia_trapdoor": "rgb(216, 127, 51)", + "cherry_trapdoor": "rgb(209, 177, 161)", + "dark_oak_trapdoor": "rgb(102, 76, 51)", + "mangrove_trapdoor": "rgb(153, 51, 51)", + "bamboo_trapdoor": "rgb(229, 229, 51)", + "stone_bricks": "rgb(112, 112, 112)", + "mossy_stone_bricks": "rgb(112, 112, 112)", + "cracked_stone_bricks": "rgb(112, 112, 112)", + "chiseled_stone_bricks": "rgb(112, 112, 112)", + "mud_bricks": "rgb(135, 107, 98)", + "infested_stone": "rgb(164, 168, 184)", + "infested_cobblestone": "rgb(164, 168, 184)", + "infested_stone_bricks": "rgb(164, 168, 184)", + "infested_mossy_stone_bricks": "rgb(164, 168, 184)", + "infested_cracked_stone_bricks": "rgb(164, 168, 184)", + "infested_chiseled_stone_bricks": "rgb(164, 168, 184)", + "brown_mushroom_block": "rgb(151, 109, 77)", + "red_mushroom_block": "rgb(153, 51, 51)", + "mushroom_stem": "rgb(199, 199, 199)", + "melon": "rgb(127, 204, 25)", + "attached_pumpkin_stem": "rgb(0, 124, 0)", + "attached_melon_stem": "rgb(0, 124, 0)", + "pumpkin_stem": "rgb(0, 124, 0)", + "melon_stem": "rgb(0, 124, 0)", + "vine": "rgb(0, 124, 0)", + "glow_lichen": "rgb(127, 167, 150)", + "mycelium": "rgb(127, 63, 178)", + "lily_pad": "rgb(0, 124, 0)", + "nether_bricks": "rgb(112, 2, 0)", + "nether_brick_fence": "rgb(112, 2, 0)", + "nether_wart": "rgb(153, 51, 51)", + "enchanting_table": "rgb(153, 51, 51)", + "brewing_stand": "rgb(167, 167, 167)", + "cauldron": "rgb(112, 112, 112)", + "end_portal": "rgb(25, 25, 25)", + "end_portal_frame": "rgb(102, 127, 51)", + "end_stone": "rgb(247, 233, 163)", + "dragon_egg": "rgb(25, 25, 25)", + "cocoa": "rgb(0, 124, 0)", + "emerald_ore": "rgb(112, 112, 112)", + "deepslate_emerald_ore": "rgb(100, 100, 100)", + "ender_chest": "rgb(112, 112, 112)", + "emerald_block": "rgb(0, 217, 58)", + "command_block": "rgb(102, 76, 51)", + "beacon": "rgb(92, 219, 213)", + "carrots": "rgb(0, 124, 0)", + "potatoes": "rgb(0, 124, 0)", + "anvil": "rgb(167, 167, 167)", + "chipped_anvil": "rgb(167, 167, 167)", + "damaged_anvil": "rgb(167, 167, 167)", + "trapped_chest": "rgb(143, 119, 72)", + "light_weighted_pressure_plate": "rgb(250, 238, 77)", + "heavy_weighted_pressure_plate": "rgb(167, 167, 167)", + "daylight_detector": "rgb(143, 119, 72)", + "redstone_block": "rgb(255, 0, 0)", + "nether_quartz_ore": "rgb(112, 2, 0)", + "hopper": "rgb(112, 112, 112)", + "quartz_block": "rgb(255, 252, 245)", + "chiseled_quartz_block": "rgb(255, 252, 245)", + "quartz_pillar": "rgb(255, 252, 245)", + "dropper": "rgb(112, 112, 112)", + "white_terracotta": "rgb(209, 177, 161)", + "orange_terracotta": "rgb(159, 82, 36)", + "magenta_terracotta": "rgb(149, 87, 108)", + "light_blue_terracotta": "rgb(112, 108, 138)", + "yellow_terracotta": "rgb(186, 133, 36)", + "lime_terracotta": "rgb(103, 117, 53)", + "pink_terracotta": "rgb(160, 77, 78)", + "gray_terracotta": "rgb(57, 41, 35)", + "light_gray_terracotta": "rgb(135, 107, 98)", + "cyan_terracotta": "rgb(87, 92, 92)", + "purple_terracotta": "rgb(122, 73, 88)", + "blue_terracotta": "rgb(76, 62, 92)", + "brown_terracotta": "rgb(76, 50, 35)", + "green_terracotta": "rgb(76, 82, 42)", + "red_terracotta": "rgb(142, 60, 46)", + "black_terracotta": "rgb(37, 22, 16)", + "slime_block": "rgb(127, 178, 56)", + "iron_trapdoor": "rgb(167, 167, 167)", + "prismarine": "rgb(76, 127, 153)", + "prismarine_bricks": "rgb(92, 219, 213)", + "dark_prismarine": "rgb(92, 219, 213)", + "prismarine_slab": "rgb(76, 127, 153)", + "prismarine_brick_slab": "rgb(92, 219, 213)", + "dark_prismarine_slab": "rgb(92, 219, 213)", + "sea_lantern": "rgb(255, 252, 245)", + "hay_block": "rgb(229, 229, 51)", + "white_carpet": "rgb(255, 255, 255)", + "orange_carpet": "rgb(216, 127, 51)", + "magenta_carpet": "rgb(178, 76, 216)", + "light_blue_carpet": "rgb(102, 153, 216)", + "yellow_carpet": "rgb(229, 229, 51)", + "lime_carpet": "rgb(127, 204, 25)", + "pink_carpet": "rgb(242, 127, 165)", + "gray_carpet": "rgb(76, 76, 76)", + "light_gray_carpet": "rgb(153, 153, 153)", + "cyan_carpet": "rgb(76, 127, 153)", + "purple_carpet": "rgb(127, 63, 178)", + "blue_carpet": "rgb(51, 76, 178)", + "brown_carpet": "rgb(102, 76, 51)", + "green_carpet": "rgb(102, 127, 51)", + "red_carpet": "rgb(153, 51, 51)", + "black_carpet": "rgb(25, 25, 25)", + "terracotta": "rgb(216, 127, 51)", + "coal_block": "rgb(25, 25, 25)", + "packed_ice": "rgb(160, 160, 255)", + "sunflower": "rgb(0, 124, 0)", + "lilac": "rgb(0, 124, 0)", + "rose_bush": "rgb(0, 124, 0)", + "peony": "rgb(0, 124, 0)", + "tall_grass": "rgb(0, 124, 0)", + "large_fern": "rgb(0, 124, 0)", + "white_banner": "rgb(143, 119, 72)", + "orange_banner": "rgb(143, 119, 72)", + "magenta_banner": "rgb(143, 119, 72)", + "light_blue_banner": "rgb(143, 119, 72)", + "yellow_banner": "rgb(143, 119, 72)", + "lime_banner": "rgb(143, 119, 72)", + "pink_banner": "rgb(143, 119, 72)", + "gray_banner": "rgb(143, 119, 72)", + "light_gray_banner": "rgb(143, 119, 72)", + "cyan_banner": "rgb(143, 119, 72)", + "purple_banner": "rgb(143, 119, 72)", + "blue_banner": "rgb(143, 119, 72)", + "brown_banner": "rgb(143, 119, 72)", + "green_banner": "rgb(143, 119, 72)", + "red_banner": "rgb(143, 119, 72)", + "black_banner": "rgb(143, 119, 72)", + "white_wall_banner": "rgb(143, 119, 72)", + "orange_wall_banner": "rgb(143, 119, 72)", + "magenta_wall_banner": "rgb(143, 119, 72)", + "light_blue_wall_banner": "rgb(143, 119, 72)", + "yellow_wall_banner": "rgb(143, 119, 72)", + "lime_wall_banner": "rgb(143, 119, 72)", + "pink_wall_banner": "rgb(143, 119, 72)", + "gray_wall_banner": "rgb(143, 119, 72)", + "light_gray_wall_banner": "rgb(143, 119, 72)", + "cyan_wall_banner": "rgb(143, 119, 72)", + "purple_wall_banner": "rgb(143, 119, 72)", + "blue_wall_banner": "rgb(143, 119, 72)", + "brown_wall_banner": "rgb(143, 119, 72)", + "green_wall_banner": "rgb(143, 119, 72)", + "red_wall_banner": "rgb(143, 119, 72)", + "black_wall_banner": "rgb(143, 119, 72)", + "red_sandstone": "rgb(216, 127, 51)", + "chiseled_red_sandstone": "rgb(216, 127, 51)", + "cut_red_sandstone": "rgb(216, 127, 51)", + "oak_slab": "rgb(143, 119, 72)", + "spruce_slab": "rgb(129, 86, 49)", + "birch_slab": "rgb(247, 233, 163)", + "jungle_slab": "rgb(151, 109, 77)", + "acacia_slab": "rgb(216, 127, 51)", + "cherry_slab": "rgb(209, 177, 161)", + "dark_oak_slab": "rgb(102, 76, 51)", + "mangrove_slab": "rgb(153, 51, 51)", + "bamboo_slab": "rgb(229, 229, 51)", + "bamboo_mosaic_slab": "rgb(229, 229, 51)", + "stone_slab": "rgb(112, 112, 112)", + "smooth_stone_slab": "rgb(112, 112, 112)", + "sandstone_slab": "rgb(247, 233, 163)", + "cut_sandstone_slab": "rgb(247, 233, 163)", + "petrified_oak_slab": "rgb(143, 119, 72)", + "cobblestone_slab": "rgb(112, 112, 112)", + "brick_slab": "rgb(153, 51, 51)", + "stone_brick_slab": "rgb(112, 112, 112)", + "mud_brick_slab": "rgb(135, 107, 98)", + "nether_brick_slab": "rgb(112, 2, 0)", + "quartz_slab": "rgb(255, 252, 245)", + "red_sandstone_slab": "rgb(216, 127, 51)", + "cut_red_sandstone_slab": "rgb(216, 127, 51)", + "purpur_slab": "rgb(178, 76, 216)", + "smooth_stone": "rgb(112, 112, 112)", + "smooth_sandstone": "rgb(247, 233, 163)", + "smooth_quartz": "rgb(255, 252, 245)", + "smooth_red_sandstone": "rgb(216, 127, 51)", + "chorus_plant": "rgb(127, 63, 178)", + "chorus_flower": "rgb(127, 63, 178)", + "purpur_block": "rgb(178, 76, 216)", + "purpur_pillar": "rgb(178, 76, 216)", + "end_stone_bricks": "rgb(247, 233, 163)", + "torchflower_crop": "rgb(0, 124, 0)", + "pitcher_crop": "rgb(0, 124, 0)", + "pitcher_plant": "rgb(0, 124, 0)", + "beetroots": "rgb(0, 124, 0)", + "dirt_path": "rgb(151, 109, 77)", + "end_gateway": "rgb(25, 25, 25)", + "repeating_command_block": "rgb(127, 63, 178)", + "chain_command_block": "rgb(102, 127, 51)", + "frosted_ice": "rgb(160, 160, 255)", + "magma_block": "rgb(112, 2, 0)", + "nether_wart_block": "rgb(153, 51, 51)", + "red_nether_bricks": "rgb(112, 2, 0)", + "bone_block": "rgb(247, 233, 163)", + "observer": "rgb(112, 112, 112)", + "kelp": "rgb(64, 64, 255)", + "kelp_plant": "rgb(64, 64, 255)", + "dried_kelp_block": "rgb(102, 127, 51)", + "turtle_egg": "rgb(247, 233, 163)", + "sniffer_egg": "rgb(153, 51, 51)", + "dead_tube_coral_block": "rgb(76, 76, 76)", + "dead_brain_coral_block": "rgb(76, 76, 76)", + "dead_bubble_coral_block": "rgb(76, 76, 76)", + "dead_fire_coral_block": "rgb(76, 76, 76)", + "dead_horn_coral_block": "rgb(76, 76, 76)", + "tube_coral_block": "rgb(51, 76, 178)", + "brain_coral_block": "rgb(242, 127, 165)", + "bubble_coral_block": "rgb(127, 63, 178)", + "fire_coral_block": "rgb(153, 51, 51)", + "horn_coral_block": "rgb(229, 229, 51)", + "dead_tube_coral": "rgb(76, 76, 76)", + "dead_brain_coral": "rgb(76, 76, 76)", + "dead_bubble_coral": "rgb(76, 76, 76)", + "dead_fire_coral": "rgb(76, 76, 76)", + "dead_horn_coral": "rgb(76, 76, 76)", + "tube_coral": "rgb(51, 76, 178)", + "brain_coral": "rgb(242, 127, 165)", + "bubble_coral": "rgb(127, 63, 178)", + "fire_coral": "rgb(153, 51, 51)", + "horn_coral": "rgb(229, 229, 51)", + "dead_tube_coral_fan": "rgb(76, 76, 76)", + "dead_brain_coral_fan": "rgb(76, 76, 76)", + "dead_bubble_coral_fan": "rgb(76, 76, 76)", + "dead_fire_coral_fan": "rgb(76, 76, 76)", + "dead_horn_coral_fan": "rgb(76, 76, 76)", + "tube_coral_fan": "rgb(51, 76, 178)", + "brain_coral_fan": "rgb(242, 127, 165)", + "bubble_coral_fan": "rgb(127, 63, 178)", + "fire_coral_fan": "rgb(153, 51, 51)", + "horn_coral_fan": "rgb(229, 229, 51)", + "dead_tube_coral_wall_fan": "rgb(76, 76, 76)", + "dead_brain_coral_wall_fan": "rgb(76, 76, 76)", + "dead_bubble_coral_wall_fan": "rgb(76, 76, 76)", + "dead_fire_coral_wall_fan": "rgb(76, 76, 76)", + "dead_horn_coral_wall_fan": "rgb(76, 76, 76)", + "tube_coral_wall_fan": "rgb(51, 76, 178)", + "brain_coral_wall_fan": "rgb(242, 127, 165)", + "bubble_coral_wall_fan": "rgb(127, 63, 178)", + "fire_coral_wall_fan": "rgb(153, 51, 51)", + "horn_coral_wall_fan": "rgb(229, 229, 51)", + "sea_pickle": "rgb(102, 127, 51)", + "blue_ice": "rgb(160, 160, 255)", + "conduit": "rgb(92, 219, 213)", + "bamboo_sapling": "rgb(143, 119, 72)", + "bamboo": "rgb(0, 124, 0)", + "bubble_column": "rgb(64, 64, 255)", + "scaffolding": "rgb(247, 233, 163)", + "loom": "rgb(143, 119, 72)", + "barrel": "rgb(143, 119, 72)", + "smoker": "rgb(112, 112, 112)", + "blast_furnace": "rgb(112, 112, 112)", + "cartography_table": "rgb(143, 119, 72)", + "fletching_table": "rgb(143, 119, 72)", + "grindstone": "rgb(167, 167, 167)", + "lectern": "rgb(143, 119, 72)", + "smithing_table": "rgb(143, 119, 72)", + "stonecutter": "rgb(112, 112, 112)", + "bell": "rgb(250, 238, 77)", + "lantern": "rgb(167, 167, 167)", + "soul_lantern": "rgb(167, 167, 167)", + "campfire": "rgb(129, 86, 49)", + "soul_campfire": "rgb(129, 86, 49)", + "sweet_berry_bush": "rgb(0, 124, 0)", + "warped_hyphae": "rgb(86, 44, 62)", + "stripped_warped_hyphae": "rgb(86, 44, 62)", + "warped_nylium": "rgb(22, 126, 134)", + "warped_fungus": "rgb(76, 127, 153)", + "warped_wart_block": "rgb(20, 180, 133)", + "warped_roots": "rgb(76, 127, 153)", + "nether_sprouts": "rgb(76, 127, 153)", + "crimson_hyphae": "rgb(92, 25, 29)", + "stripped_crimson_hyphae": "rgb(92, 25, 29)", + "crimson_nylium": "rgb(189, 48, 49)", + "crimson_fungus": "rgb(112, 2, 0)", + "shroomlight": "rgb(153, 51, 51)", + "weeping_vines": "rgb(112, 2, 0)", + "weeping_vines_plant": "rgb(112, 2, 0)", + "twisting_vines": "rgb(76, 127, 153)", + "twisting_vines_plant": "rgb(76, 127, 153)", + "crimson_roots": "rgb(112, 2, 0)", + "crimson_planks": "rgb(148, 63, 97)", + "warped_planks": "rgb(58, 142, 140)", + "structure_block": "rgb(153, 153, 153)", + "jigsaw": "rgb(153, 153, 153)", + "composter": "rgb(143, 119, 72)", + "target": "rgb(255, 252, 245)", + "bee_nest": "rgb(229, 229, 51)", + "beehive": "rgb(143, 119, 72)", + "honey_block": "rgb(216, 127, 51)", + "honeycomb_block": "rgb(216, 127, 51)", + "netherite_block": "rgb(25, 25, 25)", + "ancient_debris": "rgb(25, 25, 25)", + "crying_obsidian": "rgb(25, 25, 25)", + "respawn_anchor": "rgb(25, 25, 25)", + "lodestone": "rgb(167, 167, 167)", + "blackstone": "rgb(25, 25, 25)", + "polished_blackstone_pressure_plate": "rgb(25, 25, 25)", + "chiseled_nether_bricks": "rgb(112, 2, 0)", + "cracked_nether_bricks": "rgb(112, 2, 0)", + "amethyst_block": "rgb(127, 63, 178)", + "budding_amethyst": "rgb(127, 63, 178)", + "amethyst_cluster": "rgb(127, 63, 178)", + "tuff": "rgb(57, 41, 35)", + "calcite": "rgb(209, 177, 161)", + "tinted_glass": "rgb(76, 76, 76)", + "powder_snow": "rgb(255, 255, 255)", + "sculk_sensor": "rgb(76, 127, 153)", + "sculk": "rgb(25, 25, 25)", + "sculk_vein": "rgb(25, 25, 25)", + "sculk_catalyst": "rgb(25, 25, 25)", + "sculk_shrieker": "rgb(25, 25, 25)", + "oxidized_copper": "rgb(22, 126, 134)", + "weathered_copper": "rgb(58, 142, 140)", + "exposed_copper": "rgb(135, 107, 98)", + "copper_block": "rgb(216, 127, 51)", + "deepslate_copper_ore": "rgb(100, 100, 100)", + "lightning_rod": "rgb(216, 127, 51)", + "pointed_dripstone": "rgb(76, 50, 35)", + "dripstone_block": "rgb(76, 50, 35)", + "cave_vines": "rgb(0, 124, 0)", + "cave_vines_plant": "rgb(0, 124, 0)", + "spore_blossom": "rgb(0, 124, 0)", + "azalea": "rgb(0, 124, 0)", + "flowering_azalea": "rgb(0, 124, 0)", + "moss_carpet": "rgb(102, 127, 51)", + "pink_petals": "rgb(0, 124, 0)", + "moss_block": "rgb(102, 127, 51)", + "big_dripleaf": "rgb(0, 124, 0)", + "big_dripleaf_stem": "rgb(0, 124, 0)", + "small_dripleaf": "rgb(0, 124, 0)", + "hanging_roots": "rgb(151, 109, 77)", + "rooted_dirt": "rgb(151, 109, 77)", + "mud": "rgb(87, 92, 92)", + "deepslate": "rgb(100, 100, 100)", + "infested_deepslate": "rgb(100, 100, 100)", + "raw_iron_block": "rgb(216, 175, 147)", + "raw_copper_block": "rgb(216, 127, 51)", + "raw_gold_block": "rgb(250, 238, 77)", + "ochre_froglight": "rgb(247, 233, 163)", + "verdant_froglight": "rgb(127, 167, 150)", + "pearlescent_froglight": "rgb(242, 127, 165)", + "frogspawn": "rgb(64, 64, 255)", + "reinforced_deepslate": "rgb(100, 100, 100)", + "decorated_pot": "rgb(142, 60, 46)" } } diff --git a/src/GlobalSearchInput.tsx b/src/GlobalSearchInput.tsx new file mode 100644 index 00000000..c29c64a4 --- /dev/null +++ b/src/GlobalSearchInput.tsx @@ -0,0 +1,34 @@ +import { useSnapshot } from 'valtio' +import { miscUiState } from './globalState' +import Input from './react/Input' + +function InnerSearch () { + const { currentTouch } = useSnapshot(miscUiState) + + return
+ { + customEvents.emit('search', value) + }} + /> +
+} + +// todo remove component as its not possible to reuse this component atm +export default () => { + const { displaySearchInput } = useSnapshot(miscUiState) + + return displaySearchInput ? : null +} diff --git a/src/botUtils.ts b/src/botUtils.ts index cc624c5b..dcf764e2 100644 --- a/src/botUtils.ts +++ b/src/botUtils.ts @@ -105,3 +105,15 @@ export const formatMessage = (message: MessageInput) => { return msglist } + +const blockToItemRemaps = { + water: 'water_bucket', + lava: 'lava_bucket', + redstone_wire: 'redstone', + tripwire: 'tripwire_hook' +} + +export const getItemFromBlock = (block: import('prismarine-block').Block) => { + const item = loadedData.blocks[blockToItemRemaps[block.name] ?? block.name] + return item +} diff --git a/src/builtinCommands.ts b/src/builtinCommands.ts index 71208baf..e68daa03 100644 --- a/src/builtinCommands.ts +++ b/src/builtinCommands.ts @@ -106,7 +106,7 @@ const commands: Array<{ { command: ['/save'], async invoke () { - await saveServer() + await saveServer(false) } } ] diff --git a/src/controls.ts b/src/controls.ts index 4ddc349d..475fe603 100644 --- a/src/controls.ts +++ b/src/controls.ts @@ -14,6 +14,7 @@ import { chatInputValueGlobal } from './react/ChatContainer' import { fsState } from './loadSave' import { showOptionsModal } from './react/SelectOption' import widgets from './react/widgets' +import { getItemFromBlock } from './botUtils' // doesnt seem to work for now const customKeymaps = proxy(JSON.parse(localStorage.keymap || '{}')) @@ -443,7 +444,7 @@ const toggleFly = (newState = !isFlying(), sendAbilities?: boolean) => { const selectItem = async () => { const block = bot.blockAtCursor(5) if (!block) return - const itemId = loadedData.itemsByName[block.name]?.id + const itemId = getItemFromBlock(block)?.id if (!itemId) return const Item = require('prismarine-item')(bot.version) const item = new Item(itemId, 1, 0) diff --git a/src/flyingSquidUtils.ts b/src/flyingSquidUtils.ts index 1aef8d07..09a9760c 100644 --- a/src/flyingSquidUtils.ts +++ b/src/flyingSquidUtils.ts @@ -17,15 +17,16 @@ export function nameToMcOfflineUUID (name) { return (new UUID(javaUUID('OfflinePlayer:' + name))).toString() } -export async function savePlayers () { +export async function savePlayers (autoSave: boolean) { + if (autoSave && new URL(location.href).searchParams.get('noSave') === 'true') return //@ts-expect-error TODO await localServer!.savePlayersSingleplayer() } // todo flying squid should expose save function instead -export const saveServer = async () => { +export const saveServer = async (autoSave = true) => { if (!localServer || fsState.isReadonly) return // todo const worlds = [(localServer as any).overworld] as Array - await Promise.all([savePlayers(), ...worlds.map(async world => world.saveNow())]) + await Promise.all([savePlayers(autoSave), ...worlds.map(async world => world.saveNow())]) } diff --git a/src/globalState.ts b/src/globalState.ts index 7b6985a3..73ee7ac5 100644 --- a/src/globalState.ts +++ b/src/globalState.ts @@ -141,7 +141,8 @@ export const miscUiState = proxy({ loadedDataVersion: null as string | null, appLoaded: false, usingGamepadInput: false, - appConfig: null as AppConfig | null + appConfig: null as AppConfig | null, + displaySearchInput: false, }) export const resetStateAfterDisconnect = () => { diff --git a/src/globals.d.ts b/src/globals.d.ts index 2f6acb5a..fee3f5ec 100644 --- a/src/globals.d.ts +++ b/src/globals.d.ts @@ -15,6 +15,7 @@ declare const customEvents: import('typed-emitter').default<{ singleplayer (): void digStart () gameLoaded (): void + search (q: string): void }> declare const beforeRenderFrame: Array<() => void> diff --git a/src/importsWorkaround.js b/src/importsWorkaround.js index 33815d6b..21bc4585 100644 --- a/src/importsWorkaround.js +++ b/src/importsWorkaround.js @@ -1,2 +1,7 @@ // workaround for mineflayer process.versions.node = '18.0.0' + +if (!navigator.getGamepads) { + console.warn('navigator.getGamepads is not available, adding a workaround') + navigator.getGamepads ??= () => [] +} diff --git a/src/menus/components/common.js b/src/menus/components/common.js index 5ad74faf..3e827de1 100644 --- a/src/menus/components/common.js +++ b/src/menus/components/common.js @@ -30,7 +30,7 @@ const commonCss = css` /** @returns {boolean} */ function isMobile () { - return window.matchMedia('(pointer: coarse)').matches + return window.matchMedia('(pointer: coarse)').matches || navigator.userAgent.includes('Mobile') } // todo there are better workarounds and proper way to detect notch diff --git a/src/menus/hud.js b/src/menus/hud.js index 9aef54ef..17537e0e 100644 --- a/src/menus/hud.js +++ b/src/menus/hud.js @@ -117,12 +117,8 @@ class Hud extends LitElement { this.isReady = true window.dispatchEvent(new CustomEvent('hud-ready', { detail: this })) - watchValue(options, (o) => { - miscUiState.currentTouch = o.alwaysShowMobileControls || isMobile() - this.showMobileControls(miscUiState.currentTouch) - }) - watchValue(miscUiState, o => { + this.showMobileControls(o.currentTouch) //@ts-expect-error this.shadowRoot.host.style.display = o.gameLoaded ? 'block' : 'none' }) diff --git a/src/playerWindows.ts b/src/playerWindows.ts index 9899ccaa..1d5844de 100644 --- a/src/playerWindows.ts +++ b/src/playerWindows.ts @@ -9,7 +9,7 @@ import DispenserGui from 'minecraft-assets/minecraft-assets/data/1.17.1/gui/cont import Dirt from 'minecraft-assets/minecraft-assets/data/1.17.1/blocks/dirt.png' import { subscribeKey } from 'valtio/utils' -import MinecraftData from 'minecraft-data' +import MinecraftData, { RecipeItem } from 'minecraft-data' import { getVersion } from 'prismarine-viewer/viewer/lib/version' import { versionToNumber } from 'prismarine-viewer/viewer/prepare/utils' import itemsPng from 'prismarine-viewer/public/textures/items.png' @@ -20,6 +20,8 @@ import PrismarineBlockLoader from 'prismarine-block' import { flat } from '@xmcl/text-component' import mojangson from 'mojangson' import nbt from 'prismarine-nbt' +import { splitEvery, equals } from 'rambda' +import PItem, { Item } from 'prismarine-item' import { activeModalStack, hideCurrentModal, miscUiState, showModal } from './globalState' import invspriteJson from './invsprite.json' import { options } from './optionsStorage' @@ -53,6 +55,7 @@ let lastWindow /** bot version */ let version: string let PrismarineBlock: typeof PrismarineBlockLoader.Block +let PrismarineItem: typeof Item export const onGameLoad = (onLoad) => { let loaded = 0 @@ -65,6 +68,7 @@ export const onGameLoad = (onLoad) => { getImage({ path: 'items' }, onImageLoaded) getImage({ path: 'items-legacy' }, onImageLoaded) PrismarineBlock = PrismarineBlockLoader(version) + PrismarineItem = PItem(version) bot.on('windowOpen', (win) => { if (implementedContainersGuiMap[win.type]) { @@ -76,12 +80,44 @@ export const onGameLoad = (onLoad) => { // todo format bot._client.emit('chat', { message: JSON.stringify({ - text: `[client error] cannot open unimplemented window ${win.id} (${win.type}). Items: ${win.slots.map(slot => slot?.name).join(', ')}` + text: `[client error] cannot open unimplemented window ${win.id} (${win.type}). Slots: ${win.slots.map(item => getItemName(item) ?? '(empty)').join(', ')}` }) }) bot.currentWindow?.['close']() } }) + + bot.inventory.on('updateSlot', ((_oldSlot, oldItem, newItem) => { + const oldSlot = _oldSlot as number + if (!miscUiState.singleplayer) return + const { craftingResultSlot } = bot.inventory + if (oldSlot === craftingResultSlot && oldItem && !newItem) { + for (let i = 1; i < 5; i++) { + const count = bot.inventory.slots[i]?.count + if (count && count > 1) { + const slot = bot.inventory.slots[i]! + slot.count-- + void bot.creative.setInventorySlot(i, slot) + } else { + void bot.creative.setInventorySlot(i, null) + } + } + return + } + const craftingSlots = bot.inventory.slots.slice(1, 5) + const resultingItem = getResultingRecipe(craftingSlots, 2) + void bot.creative.setInventorySlot(craftingResultSlot, resultingItem ?? null) + }) as any) + + bot.on('windowClose', () => { + // todo hide up to the window itself! + hideCurrentModal() + }) + + customEvents.on('search', (q) => { + if (!lastWindow) return + upJei(q) + }) } const findTextureInBlockStates = (name) => { @@ -192,7 +228,8 @@ const isFullBlock = (block: string) => { return shape[0] === 0 && shape[1] === 0 && shape[2] === 0 && shape[3] === 1 && shape[4] === 1 && shape[5] === 1 } -const renderSlot = (slot: import('prismarine-item').Item, skipBlock = false): { texture: string, blockData?, scale?: number, slice?: number[] } | undefined => { +type RenderSlot = Pick +const renderSlot = (slot: RenderSlot, skipBlock = false): { texture: string, blockData?, scale?: number, slice?: number[] } | undefined => { const itemName = slot.name const isItem = loadedData.itemsByName[itemName] const fullBlock = isFullBlock(itemName) @@ -239,8 +276,8 @@ type PossibleItemProps = { Damage?: number display?: { Name?: JsonString } // {"text":"Knife","color":"white","italic":"true"} } -export const getItemName = (item: import('prismarine-item').Item) => { - if (!item.nbt) return +export const getItemName = (item: import('prismarine-item').Item | null) => { + if (!item?.nbt) return const itemNbt: PossibleItemProps = nbt.simplify(item.nbt) const customName = itemNbt.display?.Name if (!customName) return @@ -260,22 +297,25 @@ export const renderSlotExternal = (slot) => { } } -const upInventory = (inventory: boolean) => { - // inv.pwindow.inv.slots[2].displayName = 'test' - // inv.pwindow.inv.slots[2].blockData = getBlockData('dirt') - const updateSlots = (inventory ? bot.inventory : bot.currentWindow)!.slots.map(slot => { +const mapSlots = (slots: Array) => { + return slots.map(slot => { // todo stateid if (!slot) return try { const slotCustomProps = renderSlot(slot) - Object.assign(slot, { ...slotCustomProps, displayName: getItemName(slot) ?? slot.displayName }) + Object.assign(slot, { ...slotCustomProps, displayName: ('nbt' in slot ? getItemName(slot) : undefined) ?? slot.displayName }) } catch (err) { console.error(err) } return slot }) - const customSlots = updateSlots +} + +const upInventory = (isInventory: boolean) => { + // inv.pwindow.inv.slots[2].displayName = 'test' + // inv.pwindow.inv.slots[2].blockData = getBlockData('dirt') + const customSlots = mapSlots((isInventory ? bot.inventory : bot.currentWindow)!.slots) lastWindow.pwindow.setSlots(customSlots) } @@ -299,6 +339,16 @@ const implementedContainersGuiMap = { 'minecraft:crafting': 'CraftingWin' } +const upJei = (search: string) => { + search = search.toLowerCase() + // todo fix pre flat + const matchedSlots = loadedData.itemsArray.map(x => { + if (!x.displayName.toLowerCase().includes(search)) return null! + return new PrismarineItem(x.id, 1) + }).filter(Boolean) + lastWindow.pwindow.win.jeiSlots = mapSlots(matchedSlots) +} + const openWindow = (type: string | undefined) => { // if (activeModalStack.some(x => x.reactType?.includes?.('player_win:'))) { if (activeModalStack.length) { // game is not in foreground, don't close current modal @@ -313,6 +363,7 @@ const openWindow = (type: string | undefined) => { if (type !== undefined && bot.currentWindow) bot.currentWindow['close']() lastWindow.destroy() lastWindow = null + miscUiState.displaySearchInput = false destroyFn() }) cleanLoadedImagesCache() @@ -321,7 +372,7 @@ const openWindow = (type: string | undefined) => { inv.canvas.style.position = 'fixed' inv.canvas.style.inset = '0' // todo scaling - inv.canvasManager.setScale(window.innerHeight < 480 ? 2 : window.innerHeight < 700 ? 3 : 4) + inv.canvasManager.setScale(window.innerWidth < 470 ? 1.5 : window.innerHeight < 480 || window.innerWidth < 760 ? 2 : window.innerHeight < 700 ? 3 : 4) inv.canvasManager.onClose = () => { hideCurrentModal() @@ -330,10 +381,35 @@ const openWindow = (type: string | undefined) => { lastWindow = inv const upWindowItems = () => { - upInventory(type === undefined) + void Promise.resolve().then(() => upInventory(type === undefined)) } upWindowItems() + lastWindow.pwindow.touch = miscUiState.currentTouch + lastWindow.pwindow.onJeiClick = (slotItem, _index, isRightclick) => { + // slotItem is the slot from mapSlots + const itemId = loadedData.itemsByName[slotItem.name]?.id + if (!itemId) { + console.error(`Item for block ${slotItem.name} not found`) + return + } + const item = new PrismarineItem(itemId, isRightclick ? 64 : 1, slotItem.metadata) + const freeSlot = bot.inventory.firstEmptyInventorySlot() + if (freeSlot === null) return + void bot.creative.setInventorySlot(freeSlot, item) + } + + if (bot.game.gameMode === 'creative') { + lastWindow.pwindow.win.jeiSlotsPage = 0 + // todo workaround so inventory opens immediately (but still lags) + setTimeout(() => { + upJei('') + }) + miscUiState.displaySearchInput = true + } else { + lastWindow.pwindow.win.jeiSlots = [] + } + if (type === undefined) { // player inventory bot.inventory.on('updateSlot', upWindowItems) @@ -341,10 +417,6 @@ const openWindow = (type: string | undefined) => { bot.inventory.off('updateSlot', upWindowItems) } } else { - bot.on('windowClose', () => { - // todo hide up to the window itself! - hideCurrentModal() - }) //@ts-expect-error bot.currentWindow.on('updateSlot', () => { upWindowItems() @@ -357,3 +429,49 @@ let destroyFn = () => { } export const openPlayerInventory = () => { openWindow(undefined) } + +const getResultingRecipe = (slots: Array, gridRows: number) => { + const inputSlotsItems = slots.map(blockSlot => blockSlot?.type) + let currentShape = splitEvery(gridRows, inputSlotsItems as Array) + // todo rewrite with candidates search + if (currentShape.length > 1) { + // eslint-disable-next-line @typescript-eslint/no-for-in-array + for (const slotX in currentShape[0]) { + if (currentShape[0][slotX] !== undefined) { + for (const [otherY] of Array.from({ length: gridRows }).entries()) { + if (currentShape[otherY]?.[slotX] === undefined) { + currentShape[otherY]![slotX] = null + } + } + } + } + } + currentShape = currentShape.map(arr => arr.filter(x => x !== undefined)).filter(x => x.length !== 0) + + // todo rewrite + // eslint-disable-next-line @typescript-eslint/require-array-sort-compare + const slotsIngredients = [...inputSlotsItems].sort().filter(item => item !== undefined) + type Result = RecipeItem | undefined + let shapelessResult: Result + let shapeResult: Result + outer: for (const [id, recipeVariants] of Object.entries(loadedData.recipes)) { + for (const recipeVariant of recipeVariants) { + if ('inShape' in recipeVariant && equals(currentShape, recipeVariant.inShape as number[][])) { + shapeResult = recipeVariant.result! + break outer + } + if ('ingredients' in recipeVariant && equals(slotsIngredients, recipeVariant.ingredients?.sort() as number[])) { + shapelessResult = recipeVariant.result + break outer + } + } + } + const result = shapeResult ?? shapelessResult + if (!result) return + const id = typeof result === 'number' ? result : Array.isArray(result) ? result[0] : result.id + if (!id) return + const count = (typeof result === 'number' ? undefined : Array.isArray(result) ? result[1] : result.count) ?? 1 + const metadata = typeof result === 'object' && !Array.isArray(result) ? result.metadata : undefined + const item = new PrismarineItem(id, count, metadata) + return item +} diff --git a/src/react/ChatContainer.tsx b/src/react/ChatContainer.tsx index 91c9b425..ccb8e9a2 100644 --- a/src/react/ChatContainer.tsx +++ b/src/react/ChatContainer.tsx @@ -1,10 +1,11 @@ -import { useUsingTouch } from '@dimaka/interface' -import { proxy, subscribe } from 'valtio' +import { proxy, subscribe, useSnapshot } from 'valtio' import { useEffect, useMemo, useRef, useState } from 'react' import { isCypress } from '../standaloneUtils' import { MessageFormatPart } from '../botUtils' +import { miscUiState } from '../globalState' import { MessagePart } from './MessageFormatted' import './ChatContainer.css' +import { isIos } from './utils' export type Message = { parts: MessageFormatPart[], @@ -13,7 +14,7 @@ export type Message = { faded?: boolean } -const MessageLine = ({ message }: {message: Message}) => { +const MessageLine = ({ message }: { message: Message }) => { const classes = { 'chat-message-fadeout': message.fading, 'chat-message-fade': message.fading, @@ -52,7 +53,7 @@ export const fadeMessage = (message: Message, initialTimeout: boolean, requestUp } export default ({ messages, opacity = 1, fetchCompletionItems, opened, sendMessage, onClose }: Props) => { - const usingTouch = useUsingTouch() + const usingTouch = useSnapshot(miscUiState).currentTouch const sendHistoryRef = useRef(JSON.parse(window.sessionStorage.chatHistory || '[]')) @@ -205,7 +206,7 @@ export default ({ messages, opacity = 1, fetchCompletionItems, opened, sendMessa {messages.map((m) => ( ))} - } + || undefined} ) : null} - auxInputFocus('ArrowUp')} - onChange={() => { }} - /> - { - if (e.code === 'ArrowUp') { - if (chatHistoryPos.current === 0) return - if (chatHistoryPos.current === sendHistoryRef.current.length) { // started navigating history - inputCurrentlyEnteredValue.current = e.currentTarget.value - } - chatHistoryPos.current-- - updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || '') - } else if (e.code === 'ArrowDown') { - if (chatHistoryPos.current === sendHistoryRef.current.length) return - chatHistoryPos.current++ - updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || inputCurrentlyEnteredValue.current || '') +
{ + e.preventDefault() + const message = chatInput.current.value + if (message) { + setSendHistory([...sendHistoryRef.current, message]) + const result = sendMessage?.(message) + if (result !== false) { + onClose?.() } - if (e.code === 'Tab') { - if (completionItemsSource.length) { - if (completionItems.length) { - acceptComplete(completionItems[0]) + } + }}> + {isIos && auxInputFocus('ArrowUp')} + onChange={() => { }} + />} + { + if (e.code === 'ArrowUp') { + if (chatHistoryPos.current === 0) return + if (chatHistoryPos.current === sendHistoryRef.current.length) { // started navigating history + inputCurrentlyEnteredValue.current = e.currentTarget.value } - } else { - void fetchCompletions(false) + chatHistoryPos.current-- + updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || '') + } else if (e.code === 'ArrowDown') { + if (chatHistoryPos.current === sendHistoryRef.current.length) return + chatHistoryPos.current++ + updateInputValue(sendHistoryRef.current[chatHistoryPos.current] || inputCurrentlyEnteredValue.current || '') } - e.preventDefault() - } - if (e.code === 'Space') { - resetCompletionItems() - if (chatInput.current.value.startsWith('/')) { - // alternative we could just simply use keyup, but only with keydown we can display suggestions popup as soon as possible - void fetchCompletions(true, getCompleteValue(getDefaultCompleteValue() + ' ')) + if (e.code === 'Tab') { + if (completionItemsSource.length) { + if (completionItems.length) { + acceptComplete(completionItems[0]) + } + } else { + void fetchCompletions(false) + } + e.preventDefault() } - } - if (e.code === 'Enter') { - const message = chatInput.current.value - if (message) { - setSendHistory([...sendHistoryRef.current, message]) - const result = sendMessage?.(message) - if (result !== false) { - onClose?.() + if (e.code === 'Space') { + resetCompletionItems() + if (chatInput.current.value.startsWith('/')) { + // alternative we could just simply use keyup, but only with keydown we can display suggestions popup as soon as possible + void fetchCompletions(true, getCompleteValue(getDefaultCompleteValue() + ' ')) } } - } - }} - /> - auxInputFocus('ArrowDown')} - onChange={() => { }} - /> + }} + /> + {isIos && auxInputFocus('ArrowDown')} + onChange={() => { }} + />} +