From 1c2e2490310cff5efa4514d3aa824aba68c0585a Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Mon, 10 Mar 2025 22:48:51 +0300 Subject: [PATCH 01/15] fix panorama direction --- src/panorama.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/panorama.ts b/src/panorama.ts index 3c888246..cf7290ed 100644 --- a/src/panorama.ts +++ b/src/panorama.ts @@ -83,8 +83,13 @@ export async function addPanoramaCubeMap () { const panorMaterials = [] as THREE.MeshBasicMaterial[] await updateResourcePackSupportPanorama() for (const file of panoramaFiles) { + const texture = loader.load(await possiblyLoadPanoramaFromResourcePack(file)) + texture.repeat.x = -1 + texture.offset.x = 1 + texture.wrapS = THREE.RepeatWrapping + texture.wrapT = THREE.RepeatWrapping panorMaterials.push(new THREE.MeshBasicMaterial({ - map: loader.load(await possiblyLoadPanoramaFromResourcePack(file)), + map: texture, transparent: true, side: THREE.DoubleSide })) From 8232737a75de27857fcbb8f0604954def5e11268 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Mar 2025 01:34:37 +0300 Subject: [PATCH 02/15] fix panorama files order --- src/panorama.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/panorama.ts b/src/panorama.ts index cf7290ed..7459187f 100644 --- a/src/panorama.ts +++ b/src/panorama.ts @@ -14,12 +14,12 @@ let shouldDisplayPanorama = false let panoramaUsesResourcePack = null as boolean | null const panoramaFiles = [ - 'panorama_1.png', // WS - 'panorama_3.png', // ES - 'panorama_4.png', // Up - 'panorama_5.png', // Down - 'panorama_0.png', // NS - 'panorama_2.png' // SS + 'panorama_3.png', // right (+x) + 'panorama_1.png', // left (-x) + 'panorama_4.png', // top (+y) + 'panorama_5.png', // bottom (-y) + 'panorama_0.png', // front (+z) + 'panorama_2.png', // back (-z) ] const panoramaResourcePackPath = 'assets/minecraft/textures/gui/title/background' From e60d10e1216691c4780ec46579ceae8a13aa48c1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Mar 2025 01:40:56 +0300 Subject: [PATCH 03/15] fix panorama seams! --- src/panorama.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/panorama.ts b/src/panorama.ts index 7459187f..8def97c4 100644 --- a/src/panorama.ts +++ b/src/panorama.ts @@ -84,14 +84,23 @@ export async function addPanoramaCubeMap () { await updateResourcePackSupportPanorama() for (const file of panoramaFiles) { const texture = loader.load(await possiblyLoadPanoramaFromResourcePack(file)) - texture.repeat.x = -1 - texture.offset.x = 1 - texture.wrapS = THREE.RepeatWrapping - texture.wrapT = THREE.RepeatWrapping + + // Instead of using repeat/offset to flip, we'll use the texture matrix + texture.matrixAutoUpdate = false + texture.matrix.set( + -1, 0, 1, 0, 1, 0, 0, 0, 1 + ) + + texture.wrapS = THREE.ClampToEdgeWrapping // Changed from RepeatWrapping + texture.wrapT = THREE.ClampToEdgeWrapping // Changed from RepeatWrapping + texture.minFilter = THREE.LinearFilter + texture.magFilter = THREE.LinearFilter + panorMaterials.push(new THREE.MeshBasicMaterial({ map: texture, transparent: true, - side: THREE.DoubleSide + side: THREE.DoubleSide, + depthWrite: false })) } From 14d3bba5f51b3ba43384f1837fccc793de4c8099 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Mar 2025 02:04:22 +0300 Subject: [PATCH 04/15] rm serverslist storybook --- src/react/ServersList.stories.tsx | 57 ------------------------------- 1 file changed, 57 deletions(-) delete mode 100644 src/react/ServersList.stories.tsx diff --git a/src/react/ServersList.stories.tsx b/src/react/ServersList.stories.tsx deleted file mode 100644 index 0a0ef151..00000000 --- a/src/react/ServersList.stories.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import type { Meta, StoryObj } from '@storybook/react' - -import { useState } from 'react' -import AddServerOrConnect from './AddServerOrConnect' -import ServersList from './ServersList' - -const meta: Meta = { - component: ServersList, - render (args) { - const [addOpen, setAddOpen] = useState(false) - const [username, setUsername] = useState('') - - return addOpen ? - { - setAddOpen(false) - }} - accounts={['testting']} - onConfirm={(info) => { - console.log('add server', info) - }} - /> : - { - console.log('joinServer', ip) - }} - initialProxies={{ - proxies: ['localhost', 'mc.hypixel.net'], - selected: 'localhost', - }} - updateProxies={newData => { - console.log('setProxies', newData) - }} - onWorldAction={() => { }} - onGeneralAction={(action) => { - if (action === 'create') { - setAddOpen(true) - } - }} - username={username} - setUsername={setUsername} - /> - }, -} - -export default meta -type Story = StoryObj - -export const Primary: Story = { - args: { - }, -} From 734d195be00db5d39ba76593b038c884b83ee16e Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Mar 2025 02:11:36 +0300 Subject: [PATCH 05/15] fix errors spamming from players list --- src/react/PlayerListOverlayProvider.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/react/PlayerListOverlayProvider.tsx b/src/react/PlayerListOverlayProvider.tsx index 5fb98c60..2f2cac54 100644 --- a/src/react/PlayerListOverlayProvider.tsx +++ b/src/react/PlayerListOverlayProvider.tsx @@ -30,15 +30,15 @@ export default () => { } } - useMemo(() => { + useEffect(() => { function requestUpdate () { - // Placeholder for requestUpdate logic - setPlayers(bot.players) + setPlayers(bot?.players ?? {}) } bot.on('playerUpdated', () => requestUpdate()) bot.on('playerJoined', () => requestUpdate()) bot.on('playerLeft', () => requestUpdate()) + requestUpdate() const interval = setInterval(() => { requestUpdate() }, 1000) From d5cc6d325ef8768ddd4003a47be84821d9049678 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Mar 2025 19:21:41 +0300 Subject: [PATCH 06/15] just casually doing a major client rename --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 50d96a6a..783ff50e 100644 --- a/index.html +++ b/index.html @@ -128,17 +128,17 @@ window.loadedPlugins[pluginName] = await import(script) } --> - Prismarine Web Client + Minecraft Web Client - + - + From 6263c9ae66af86708e3b3140903dafb06c5f345a Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Mar 2025 19:22:50 +0300 Subject: [PATCH 07/15] also rename in manifest --- assets/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/manifest.json b/assets/manifest.json index 9ec96f08..4310ae7f 100644 --- a/assets/manifest.json +++ b/assets/manifest.json @@ -1,6 +1,6 @@ { - "name": "Prismarine Web Client", - "short_name": "Prismarine Web Client", + "name": "Minecraft Web Client", + "short_name": "Minecraft Web Client", "scope": "./", "start_url": "./", "icons": [ From ec953fd5d1e2f6c8bc76b57a35c4e281235ca90a Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Mar 2025 19:37:34 +0300 Subject: [PATCH 08/15] feat: never force resort items in the list and allow to resort manually with shift+up/down --- src/react/ServersListProvider.tsx | 43 ++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index 56ec75b6..de01c25c 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -86,6 +86,35 @@ const Inner = ({ hidden, customServersList }: { hidden?: boolean, customServersL const [serversList, setServersList] = useState(() => (customServersList ? [] : getInitialServersList())) const [additionalData, setAdditionalData] = useState>({}) + // Add keyboard handler for moving servers + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (['input', 'textarea', 'select'].includes((e.target as HTMLElement)?.tagName?.toLowerCase())) return + if (!e.shiftKey || selectedIndex === undefined) return + if (e.key !== 'ArrowUp' && e.key !== 'ArrowDown') return + e.preventDefault() + e.stopImmediatePropagation() + + const newIndex = e.key === 'ArrowUp' + ? Math.max(0, selectedIndex - 1) + : Math.min(serversList.length - 1, selectedIndex + 1) + + if (newIndex === selectedIndex) return + + // Move server in the list + const newList = [...serversList] + const oldItem = newList[selectedIndex] + newList[selectedIndex] = newList[newIndex] + newList[newIndex] = oldItem + + setServersList(newList) + setSelectedIndex(newIndex) + } + + document.addEventListener('keydown', handleKeyDown) + return () => document.removeEventListener('keydown', handleKeyDown) + }, [selectedIndex, serversList]) + useEffect(() => { if (customServersList) { setServersList(customServersList.map(row => { @@ -105,10 +134,11 @@ const Inner = ({ hidden, customServersList }: { hidden?: boolean, customServersL setNewServersList(serversList) }, [serversList]) + const serversListSorted = useMemo(() => serversList.map((server, index) => ({ ...server, index })), [serversList]) // by lastJoined - const serversListSorted = useMemo(() => { - return serversList.map((server, index) => ({ ...server, index })).sort((a, b) => (b.lastJoined ?? 0) - (a.lastJoined ?? 0)) - }, [serversList]) + // const serversListSorted = useMemo(() => { + // return serversList.map((server, index) => ({ ...server, index })).sort((a, b) => (b.lastJoined ?? 0) - (a.lastJoined ?? 0)) + // }, [serversList]) const isEditScreenModal = useIsModalActive('editServer') @@ -313,6 +343,13 @@ const Inner = ({ hidden, customServersList }: { hidden?: boolean, customServersL // find and update const server = serversList.find(s => s.ip === ip) if (server) { + // move to top + const newList = [...serversList] + const index = newList.indexOf(server) + const thisItem = newList[index] + newList.splice(index, 1) + newList.unshift(thisItem) + server.lastJoined = Date.now() server.numConnects = (server.numConnects || 0) + 1 setNewServersList(serversList) From a6018c6891a34e5667a702a8d59228fdf5aa1ff0 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Tue, 11 Mar 2025 19:42:13 +0300 Subject: [PATCH 09/15] remove not working google drive button to avoid confusion --- src/react/SingleplayerProvider.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/react/SingleplayerProvider.tsx b/src/react/SingleplayerProvider.tsx index 6672de6e..36111fb5 100644 --- a/src/react/SingleplayerProvider.tsx +++ b/src/react/SingleplayerProvider.tsx @@ -283,10 +283,10 @@ const Inner = () => { return Date: Tue, 11 Mar 2025 19:55:03 +0300 Subject: [PATCH 10/15] add groups into UI for future work --- src/react/ServersListProvider.tsx | 3 +- src/react/Singleplayer.tsx | 77 +++++++++++++++++++++++------- src/react/SingleplayerProvider.tsx | 1 + 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/src/react/ServersListProvider.tsx b/src/react/ServersListProvider.tsx index de01c25c..f0543e21 100644 --- a/src/react/ServersListProvider.tsx +++ b/src/react/ServersListProvider.tsx @@ -406,7 +406,8 @@ const Inner = ({ hidden, customServersList }: { hidden?: boolean, customServersL worldNameRight: additional?.textNameRight ?? '', worldNameRightGrayed: additional?.textNameRightGrayed ?? '', iconSrc: additional?.icon, - offline: additional?.offline + offline: additional?.offline, + group: 'Custom Servers' } })} initialProxies={{ diff --git a/src/react/Singleplayer.tsx b/src/react/Singleplayer.tsx index 6d7d6b0e..d3a32423 100644 --- a/src/react/Singleplayer.tsx +++ b/src/react/Singleplayer.tsx @@ -1,5 +1,5 @@ import classNames from 'classnames' -import { Fragment, useEffect, useMemo, useRef, useState } from 'react' +import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react' // todo optimize size import missingWorldPreview from 'mc-assets/dist/other-textures/latest/gui/presets/isles.png' @@ -29,6 +29,21 @@ export interface WorldProps { onInteraction?(interaction: 'enter' | 'space') elemRef?: React.Ref offline?: boolean + group?: string +} + +const GroupHeader = ({ name, count, expanded, onToggle }: { name: string, count: number, expanded: boolean, onToggle: () => void }) => { + return
+
+ {expanded ? '▼' : '▶'} + {name} + ({count}) +
+
} const World = ({ name, isFocused, title, lastPlayed, size, detail = '', onFocus, onInteraction, iconSrc, formattedTextOverride, worldNameRight, worldNameRightGrayed, elemRef, offline }: WorldProps & { ref?: React.Ref }) => { @@ -159,6 +174,7 @@ export default ({ const [search, setSearch] = useState('') const [focusedWorld, setFocusedWorld] = useState(defaultSelectedRow === undefined ? '' : worldData?.[defaultSelectedRow]?.name ?? '') + const [expandedGroups, setExpandedGroups] = useState>({}) useEffect(() => { setFocusedWorld('') @@ -179,6 +195,13 @@ export default ({ } const isSmallWidth = useIsSmallWidth() + const toggleGroup = (groupName: string) => { + setExpandedGroups(prev => ({ + ...prev, + [groupName]: prev[groupName] === undefined ? false : !prev[groupName] + })) + } + return