Skip to content

Commit

Permalink
Merge pull request #176 from Lodestone-Team/145-0.4.3-player-list
Browse files Browse the repository at this point in the history
#145 Implement Minecraft player list component
  • Loading branch information
kevinzhang03 authored Mar 1, 2023
2 parents 851cfac + 1b18ace commit dca1fa3
Show file tree
Hide file tree
Showing 8 changed files with 381 additions and 93 deletions.
275 changes: 191 additions & 84 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@headlessui/react": "^1.7.0",
"@headlessui/tailwindcss": "^0.1.2",
"@monaco-editor/react": "^4.4.6",
"@next/font": "^13.1.6",
"@next/font": "^13.2.1",
"@tanstack/react-query": "^4.13.5",
"@tanstack/react-virtual": "^3.0.0-beta.32",
"@tauri-apps/api": "^1.2.0",
Expand All @@ -38,7 +38,7 @@
"monaco-editor": "^0.34.0",
"msw": "^0.47.4",
"msw-storybook-addon": "^1.7.0",
"next": "^13.1.6",
"next": "^13.2.1",
"npm": "^8.19.2",
"patch-package": "^6.4.7",
"rc-tooltip": "^5.2.2",
Expand Down Expand Up @@ -85,7 +85,7 @@
"autoprefixer": "^10.4.8",
"babel-loader": "^8.2.5",
"eslint": "^8.22.0",
"eslint-config-next": "^13.0.0",
"eslint-config-next": "^13.2.1",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-storybook": "^0.6.10",
"eslint-plugin-tailwindcss": "^3.8.0",
Expand Down
2 changes: 2 additions & 0 deletions src/bindings/InstanceInfo.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { InstanceState } from './InstanceState';
import type { InstanceUuid } from './InstanceUuid';
import type { Player } from './Player';

export type GameType = 'minecraft';

Expand All @@ -22,4 +23,5 @@ export interface InstanceInfo {
state: InstanceState;
player_count: number | null;
max_player_count: number | null;
player_list: Array<Player> | null;
}
100 changes: 100 additions & 0 deletions src/components/Minecraft/MinecraftPlayerList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { InstanceContext } from 'data/InstanceContext';
import { useContext } from 'react';
import { PlayerListItem, PlayerListCard } from 'components/PlayerListCard';
import { useState, useMemo } from 'react';
import { faArrowDown, faArrowUp } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
// import { Player } from 'bindings/Player';

export default function MinecraftPlayerList() {

const { selectedInstance: instance } = useContext(InstanceContext);
const uuid = instance?.uuid;

// Ascending order is referring to alphabetical order
// Note: Arrow will point DOWN when sorting in ascending order, as seen on the figma
const [sortAscending, setSortAscending] = useState(true);

// Update playerList every time there a player leaves or joins
// Also sorts and updates when sort button is pressed
const updatedPlayerList = useMemo(() => {
if (!instance?.player_list) return null;
const playerList = [...instance.player_list];
playerList.sort((a, b) => {
if (sortAscending) {
return a.name.localeCompare(b.name);
} else {
return b.name.localeCompare(a.name);
}
});
return playerList;
}, [instance, sortAscending]);

// Catch case where server instance is not available; return early
if (!instance || !uuid) {
return (
<div
className="relative flex h-full w-full flex-row justify-center overflow-y-auto px-4 pt-8 pb-10 @container"
key={uuid}
>
<div className="flex h-fit min-h-full w-full grow flex-col items-start gap-2">
<div className="flex min-w-0 flex-row items-center gap-4">
<h1 className="dashboard-instance-heading truncate whitespace-pre">
Instance not found
</h1>
</div>
</div>
</div>
);
}

// API to get the avatar head png 16x16 px
const mcHeadURL = 'https://mc-heads.net/avatar/';
const avatarDimension = 16;

return (
<div>
<h2 className="text-h3 font-extrabold tracking-medium">Player List</h2>
{updatedPlayerList && updatedPlayerList.length ? (
<>
<h3 className="text-medium font-medium italic tracking-medium text-white/50">
All players currently online
</h3>
<button
className="mt-4 mb-2 flex items-center justify-center text-small font-medium tracking-medium text-white/50"
onClick={() => setSortAscending(!sortAscending)}
>
NAME
{sortAscending ? (
<FontAwesomeIcon icon={faArrowDown} className="mx-1.5" />
) : (
<FontAwesomeIcon icon={faArrowUp} className="mx-1.5" />
)}
</button>
{updatedPlayerList.length > 0 && (
<PlayerListCard>
{updatedPlayerList.map((player) => (
<PlayerListItem key={player.uuid}>
<img
src={`${mcHeadURL}${player.uuid}/${avatarDimension}.png`}
alt={`Avatar of ${player.name}`}
className={`mx-1 h-4 w-4`}
draggable="false"
style={{ imageRendering: "pixelated", userSelect: 'none' }}
/>
<div className="mx-1 text-medium" >
{player.name}
</div>
</PlayerListItem>
))}
</PlayerListCard>
)}
</>
) : (
<h3 className="text-medium font-medium italic tracking-medium text-white/50">
No players online
</h3>
)}
</div>
);
}
4 changes: 4 additions & 0 deletions src/components/Minecraft/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default as MinecraftPerformanceCard } from './MinecraftPerformanceCard';
export { default as MinecraftGeneralCard } from './MinecraftGeneralCard';
export { default as MinecraftSettingCard } from './MinecraftSettingCard';
export { default as MinecraftPlayerList } from './MinecraftPlayerList';
51 changes: 51 additions & 0 deletions src/components/PlayerListCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { ReactNode } from 'react';
import * as React from 'react';

interface ItemProps {
children: ReactNode;
className?: string;
}

export function PlayerListItem({ children, className = '' }: ItemProps) {
return (
<div className={`flex items-center rounded-xl ${className}`}>
{children}
</div>
);
}

interface CardProps {
children: ReactNode;
className?: string;
}

export function PlayerListCard({ children, className }: CardProps) {
const numItems = React.Children.count(children);

if (numItems === 0) {
return null;
}

if (numItems === 1) {
return (
<div
className={`flex h-fit w-full flex-col rounded border border-gray-faded/30 bg-gray-850 p-2 ${className}`}
>
{children}
</div>
);
}

return (
<div
className={`flex h-fit w-full flex-col rounded border border-gray-faded/30 bg-gray-850 p-2 ${className}`}
>
{React.Children.map(children, (child, index) => (
<>
{index > 0 && <hr className="my-2 mx-[-0.5rem] border-gray-faded/30" />}
{child}
</>
))}
</div>
);
}
17 changes: 16 additions & 1 deletion src/data/EventStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { LODESTONE_PORT } from 'utils/util';
import { UserPermission } from 'bindings/UserPermission';
import { PublicUser } from 'bindings/PublicUser';
import { toast } from 'react-toastify';
import { Player } from 'bindings/Player';

/**
* does not return anything, call this for the side effect of subscribing to the event stream
Expand Down Expand Up @@ -61,6 +62,17 @@ export const useEventStream = () => {
},
[queryClient]
);
const updateInstancePlayerList = useCallback(
(uuid: string, players: Player[]) => {
updateInstance(uuid, queryClient, (oldInfo) => {
return {
...oldInfo,
player_list: players,
};
});
},
[queryClient]
);
const updatePermission = useCallback(
(permission: UserPermission) => {
queryClient.setQueryData(
Expand Down Expand Up @@ -135,7 +147,10 @@ export const useEventStream = () => {
console.log(`Got player change on ${name}: ${player_list}`);
console.log(`${players_joined} joined ${name}`);
console.log(`${players_left} left ${name}`);
if (fresh) updateInstancePlayerCount(uuid, player_list.length);
if (fresh) {
updateInstancePlayerList(uuid, player_list);
updateInstancePlayerCount(uuid, player_list.length);
}

// we don't need match statement on the type of player yet because there's only MinecraftPlayyer for now
const player_list_names = player_list.map((p) => p.name);
Expand Down
19 changes: 14 additions & 5 deletions src/data/InstanceTabListMap.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import {
MinecraftPerformanceCard,
MinecraftPlayerList,
MinecraftGeneralCard,
MinecraftSettingCard
} from 'components/Minecraft';

import GameConsole from 'components/GameConsole';
import MinecraftGeneralCard from 'components/Minecraft/MinecraftGeneralCard';
import MinecraftSettingCard from 'components/Minecraft/MinecraftSettingCard';
import FileViewer from 'components/FileViewer';
import DashboardCard from 'components/DashboardCard';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import MinecraftOverview from 'components/Minecraft/MinecraftOverview';
import MinecraftPerformanceCard from 'components/Minecraft/MinecraftPerformanceCard';
// import MinecraftOverview from 'components/Minecraft/MinecraftOverview';

import {
faChartLine,
Expand All @@ -23,7 +27,12 @@ const InstanceTabListMap = {
path: 'overview',
width: 'max-w-4xl',
icon: <FontAwesomeIcon icon={faChartLine} />,
content: <MinecraftOverview/>,
content: (
<>
<MinecraftPerformanceCard />
<MinecraftPlayerList />
</>
),
},
{
title: 'Settings',
Expand Down

0 comments on commit dca1fa3

Please sign in to comment.