Spelers Beheer
Admin interface voor speler accounts en data.
Spelers Overzicht
┌─────────────────────────────────────────────────────────────────┐
│ Spelers Online: 42 / 1,234 │
├─────────────────────────────────────────────────────────────────┤
│ [Zoeken op username... ] [🔍] [Alleen online ☐] │
├─────────────────────────────────────────────────────────────────┤
│ 🟢 milena123 │ Milena │ Lvl 15 │ 2024-01-15 │ Details │
│ 🟢 bosvriend42 │ Tim │ Lvl 8 │ 2024-01-15 │ Details │
│ ⚫ natuurkind │ Anna │ Lvl 23 │ 2024-01-14 │ Details │
│ 🔴 gebanned │ Troll │ Lvl 2 │ 2024-01-10 │ Details │
└─────────────────────────────────────────────────────────────────┘
Status Indicatoren
| Indicator | Betekenis |
|---|---|
| 🟢 | Online |
| ⚫ | Offline |
| 🔴 | Gebanned |
| ⚠️ | Parental lock actief |
Speler Detail
┌─────────────────────────────────────────────────────────────────┐
│ milena123 [🔙 Terug]│
├─────────────────────────────────────────────────────────────────┤
│ │
│ Basis Info Account │
│ ────────── ─────── │
│ Display Name: Milena Aangemaakt: 2024-01-01 │
│ Level: 15 Laatst online: 5 min │
│ Speeltijd: 48u 23m Identity: 0x7f3a... │
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Tabs: [Inventory] [Resources] [Quests] [Clubs] [Log] ││
│ ├─────────────────────────────────────────────────────────────┤│
│ │ ││
│ │ Resources ││
│ │ ───────── ││
│ │ 🌰 Eikels: 1,234 [+100] [-100] ││
│ │ 🥜 Beukenootjes: 5,678 [+100] [-100] ││
│ │ 🪵 Hout: 342 [+100] [-100] ││
│ │ 🪨 Steen: 156 [+100] [-100] ││
│ │ ││
│ └─────────────────────────────────────────────────────────────┘│
│ │
│ Acties │
│ ────── │
│ [Geef Item] [Geef Container] [Reset Positie] [Ban Speler] │
│ │
└─────────────────────────────────────────────────────────────────┘
Inventory Viewer
// components/InventoryViewer.tsx
export function InventoryViewer({ playerId }: { playerId: string }) {
const { data: containers } = useQuery({
queryKey: ['containers', playerId],
queryFn: () => spacetime.query(
`SELECT * FROM player_container WHERE owner = '${playerId}'`
)
});
return (
<div className="grid grid-cols-2 gap-4">
{containers?.map(container => (
<ContainerGrid
key={container.id}
container={container}
items={items.filter(i => i.container_id === container.id)}
/>
))}
</div>
);
}
Admin Acties
Geef Item
async function giveItem(username: string, itemId: string, quantity: number) {
await spacetime.call('give_item_to_player', [username, itemId, quantity]);
}
// UI Component
<Dialog title="Geef Item">
<ItemSelector onSelect={setSelectedItem} />
<NumberInput
label="Aantal"
value={quantity}
onChange={setQuantity}
min={1}
max={999}
/>
<Button onClick={() => giveItem(player.username, selectedItem, quantity)}>
Geef Item
</Button>
</Dialog>
Geef Container
async function giveContainer(username: string, containerType: string) {
await spacetime.call('give_container', [username, containerType]);
}
Wijzig Resources
async function adjustResource(
username: string,
resourceType: string,
amount: number
) {
if (amount > 0) {
await spacetime.call('give_resource_to_player', [
username, resourceType, amount
]);
} else {
await spacetime.call('remove_resource_from_player', [
username, resourceType, Math.abs(amount)
]);
}
}
Ban Speler
interface BanDialogProps {
player: Player;
onBan: () => void;
}
function BanDialog({ player, onBan }: BanDialogProps) {
const [reason, setReason] = useState('');
const [duration, setDuration] = useState(24); // uren
const handleBan = async () => {
await spacetime.call('ban_player', [
player.identity,
reason,
duration
]);
onBan();
};
return (
<Dialog title={`Ban ${player.username}`}>
<TextArea
label="Reden"
value={reason}
onChange={e => setReason(e.target.value)}
required
/>
<Select
label="Duur"
value={duration}
onChange={e => setDuration(Number(e.target.value))}
>
<option value={1}>1 uur</option>
<option value={24}>24 uur</option>
<option value={168}>1 week</option>
<option value={720}>30 dagen</option>
<option value={0}>Permanent</option>
</Select>
<Button variant="danger" onClick={handleBan}>
Ban Speler
</Button>
</Dialog>
);
}
Activiteit Log
┌─────────────────────────────────────────────────────────────────┐
│ Activiteit Log - milena123 │
├─────────────────────────────────────────────────────────────────┤
│ 15:42 │ Logged in │
│ 15:43 │ Completed quest: daily_harvest │
│ 15:45 │ Purchased: leather_backpack (500 eikels) │
│ 15:48 │ Joined club: forest_friends │
│ 15:52 │ Donated 100 hout to club │
│ 16:01 │ Logged out │
└─────────────────────────────────────────────────────────────────┘
Zoeken & Filteren
interface PlayerFilters {
search: string;
onlineOnly: boolean;
minLevel: number;
maxLevel: number;
createdAfter: Date | null;
isBanned: boolean | null;
}
function buildPlayerQuery(filters: PlayerFilters): string {
let query = 'SELECT * FROM player WHERE 1=1';
if (filters.search) {
query += ` AND (username LIKE '%${filters.search}%'
OR display_name LIKE '%${filters.search}%')`;
}
if (filters.minLevel > 0) {
query += ` AND level >= ${filters.minLevel}`;
}
// etc...
return query + ' ORDER BY last_online DESC LIMIT 100';
}
Bulk Acties
// Meerdere spelers selecteren en actie uitvoeren
async function bulkGiveItem(
usernames: string[],
itemId: string,
quantity: number
) {
for (const username of usernames) {
await spacetime.call('give_item_to_player', [username, itemId, quantity]);
}
}
// Event reward aan alle online spelers
async function giveToAllOnline(itemId: string, quantity: number) {
const online = await spacetime.query('SELECT username FROM player_online');
await bulkGiveItem(online.map(p => p.username), itemId, quantity);
}