hope to release soon (#60)

This commit is contained in:
Vitaly 2024-02-15 04:59:24 +03:00 committed by GitHub
commit f4d5a4695d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
26 changed files with 890 additions and 124 deletions

View file

@ -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:

View file

@ -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=<server_address>` - Display connect screen to the server on load
- `?username=<username>` - Set the username on load
- `?proxy=<proxy_address>` - Set the proxy server address on load
- `?version=<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.
<!-- - `?password=<password>` - Set the password on load -->
- `?loadSave=<save_name>` - 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

View file

@ -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",

28
pnpm-lock.yaml generated
View file

@ -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:

View file

@ -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)"
}
}

34
src/GlobalSearchInput.tsx Normal file
View file

@ -0,0 +1,34 @@
import { useSnapshot } from 'valtio'
import { miscUiState } from './globalState'
import Input from './react/Input'
function InnerSearch () {
const { currentTouch } = useSnapshot(miscUiState)
return <div style={{
position: 'fixed',
top: 5,
left: 0,
right: 0,
margin: 'auto',
zIndex: 11,
width: 'min-content',
}}>
<Input
autoFocus={currentTouch === false}
width={50}
placeholder='Search...'
defaultValue=""
onChange={({ target: { value } }) => {
customEvents.emit('search', value)
}}
/>
</div>
}
// todo remove component as its not possible to reuse this component atm
export default () => {
const { displaySearchInput } = useSnapshot(miscUiState)
return displaySearchInput ? <InnerSearch /> : null
}

View file

@ -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
}

View file

@ -106,7 +106,7 @@ const commands: Array<{
{
command: ['/save'],
async invoke () {
await saveServer()
await saveServer(false)
}
}
]

View file

@ -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)

View file

@ -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<import('prismarine-world').world.World>
await Promise.all([savePlayers(), ...worlds.map(async world => world.saveNow())])
await Promise.all([savePlayers(autoSave), ...worlds.map(async world => world.saveNow())])
}

View file

@ -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 = () => {

1
src/globals.d.ts vendored
View file

@ -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>

View file

@ -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 ??= () => []
}

View file

@ -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

View file

@ -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'
})

View file

@ -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<import('prismarine-item').Item, 'name' | 'displayName'>
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<RenderSlot | Item | null>) => {
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<Item | null>, gridRows: number) => {
const inputSlotsItems = slots.map(blockSlot => blockSlot?.type)
let currentShape = splitEvery(gridRows, inputSlotsItems as Array<number | undefined | null>)
// 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
}

View file

@ -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) => (
<MessageLine key={m.id} message={m} />
))}
</div>}
</div> || undefined}
</div>
<div className={`chat-wrapper chat-input-wrapper ${usingTouch ? 'input-mobile' : ''}`} hidden={!opened}>
@ -220,78 +221,81 @@ export default ({ messages, opacity = 1, fetchCompletionItems, opened, sendMessa
</div>
</div>
) : null}
<input
value=''
type="text"
className="chat-mobile-hidden"
id="chatinput-next-command"
spellCheck={false}
autoComplete="off"
onFocus={() => auxInputFocus('ArrowUp')}
onChange={() => { }}
/>
<input
defaultValue=''
ref={chatInput}
type="text"
className="chat-input"
id="chatinput"
spellCheck={false}
autoComplete="off"
aria-autocomplete="both"
onChange={onMainInputChange}
onKeyDown={(e) => {
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 || '')
<form onSubmit={(e) => {
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 && <input
value=''
type="text"
className="chat-mobile-hidden"
id="chatinput-next-command"
spellCheck={false}
autoComplete="off"
onFocus={() => auxInputFocus('ArrowUp')}
onChange={() => { }}
/>}
<input
defaultValue=''
ref={chatInput}
type="text"
className="chat-input"
id="chatinput"
spellCheck={false}
autoComplete="off"
aria-autocomplete="both"
onChange={onMainInputChange}
onKeyDown={(e) => {
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() + ' '))
}
}
}
}}
/>
<input
value=''
type="text"
className="chat-mobile-hidden"
id="chatinput-prev-command"
spellCheck={false}
autoComplete="off"
onFocus={() => auxInputFocus('ArrowDown')}
onChange={() => { }}
/>
}}
/>
{isIos && <input
value=''
type="text"
className="chat-mobile-hidden"
id="chatinput-prev-command"
spellCheck={false}
autoComplete="off"
onFocus={() => auxInputFocus('ArrowDown')}
onChange={() => { }}
/>}
<button type='submit' style={{ visibility: 'hidden' }} />
</form>
</div>
</div>
</>

View file

@ -27,26 +27,29 @@ export default ({ cancelClick, createClick, customizeClick, versions, defaultVer
}, [])
return <Screen title="Create world" backdrop="dirt">
<div style={{ display: 'flex' }}>
<form style={{ display: 'flex' }} onSubmit={(e) => {
e.preventDefault()
createClick()
}}>
<Input
autoFocus
value={title}
onChange={({ target: { value } }) => {
creatingWorldState.title = value
}}
onEnterPress={() => {
createClick()
}}
placeholder='World name'
/>
<select value={version} onChange={({ target: { value } }) => {
<select value={version} style={{
background: 'gray',
color: 'white'
}} onChange={({ target: { value } }) => {
creatingWorldState.version = value
}}>
{versions.map(({ version, label }) => {
return <option key={version} value={version}>{label}</option>
})}
</select>
</div>
</form>
<div style={{ display: 'flex' }}>
<Button onClick={() => {
const index = worldTypes.indexOf(type)

View file

@ -1,6 +1,6 @@
import { useUsingTouch } from '@dimaka/interface'
import { useEffect, useState } from 'react'
import Button from './Button'
import { useUsingTouch } from './utils'
export default () => {
const [fullScreen, setFullScreen] = useState(false)

View file

@ -1,21 +1,17 @@
import React, { useEffect, useRef } from 'react'
import styles from './input.module.css'
import { useUsingTouch } from './utils'
interface Props extends React.ComponentProps<'input'> {
autoFocus?: boolean
onEnterPress?: (e) => void
}
export default ({ autoFocus, onEnterPress, ...inputProps }: Props) => {
export default ({ autoFocus, ...inputProps }: Props) => {
const ref = useRef<HTMLInputElement>(null!)
const isTouch = useUsingTouch()
useEffect(() => {
if (onEnterPress) {
ref.current.addEventListener('keydown', (e) => {
if (e.code === 'Enter') onEnterPress(e)
})
}
if (!autoFocus || matchMedia('(pointer: coarse)').matches) return // Don't make screen keyboard popup on mobile
if (!autoFocus || isTouch) return // Don't make screen keyboard popup on mobile
ref.current.focus()
}, [])

View file

@ -1,9 +1,10 @@
import { LeftTouchArea, RightTouchArea, useInterfaceState, useUsingTouch } from '@dimaka/interface'
import { LeftTouchArea, RightTouchArea, useInterfaceState } from '@dimaka/interface'
import { css } from '@emotion/css'
import { useSnapshot } from 'valtio'
import { contro } from '../controls'
import { miscUiState, activeModalStack } from '../globalState'
import { watchValue, options } from '../optionsStorage'
import { useUsingTouch } from './utils'
// todo
useInterfaceState.setState({

View file

@ -1,6 +1,7 @@
import { useSnapshot } from 'valtio'
import { useEffect, useRef } from 'react'
import { activeModalStack } from '../globalState'
import { UAParser } from 'ua-parser-js'
import { activeModalStack, miscUiState } from '../globalState'
export const useIsModalActive = (modal: string) => {
return useSnapshot(activeModalStack).at(-1)?.reactType === modal
@ -25,3 +26,11 @@ export function useDidUpdateEffect (fn, inputs) {
}
}, inputs)
}
export const useUsingTouch = () => {
return useSnapshot(miscUiState).currentTouch
}
export const ua = new UAParser(navigator.userAgent)
export const isIos = ua.getOS().name === 'iOS'

View file

@ -18,6 +18,7 @@ import SoundMuffler from './react/SoundMuffler'
import TouchControls from './react/TouchControls'
import widgets from './react/widgets'
import { useIsWidgetActive } from './react/utils'
import GlobalSearchInput from './GlobalSearchInput'
const Portal = ({ children, to }) => {
return createPortal(children, to)
@ -63,6 +64,7 @@ const InGameUi = () => {
<Portal to={document.body}>
{/* becaues of z-index */}
<TouchControls />
<GlobalSearchInput />
</Portal>
</>
}

View file

@ -15,6 +15,7 @@
.backdrop {
position: fixed;
inset: 0;
height: 100dvh;
background: rgba(0, 0, 0, 0.75);
}

View file

@ -51,6 +51,7 @@ body {
-ms-user-select: none;
user-select: none;
font-family: minecraft, mojangles, monospace;
z-index: -5;
}
#react-root {
@ -148,6 +149,11 @@ body {
animation-fill-mode: forwards;
}
.full-svg svg {
width: 100%;
height: 100%;
}
.muted {
color: #999;
}

View file

@ -3,6 +3,8 @@
import { subscribeKey } from 'valtio/utils'
import { options, watchValue } from './optionsStorage'
import { reloadChunks } from './utils'
import { miscUiState } from './globalState'
import { isMobile } from './menus/components/common'
subscribeKey(options, 'renderDistance', reloadChunks)
subscribeKey(options, 'multiplayerRenderDistance', reloadChunks)
@ -14,7 +16,17 @@ watchValue(options, o => {
document.documentElement.style.setProperty('--guiScale', `${o.guiScale}`)
})
/** happens once */
export const watchOptionsAfterViewerInit = () => {
const updateTouch = (o) => {
miscUiState.currentTouch = o.alwaysShowMobileControls || isMobile()
}
watchValue(options, updateTouch)
window.matchMedia('(pointer: coarse)').addEventListener('change', (e) => {
updateTouch(options)
})
watchValue(options, o => {
if (!viewer) return
viewer.world.showChunkBorders = o.showChunkBorders