Spaces:
Sleeping
Sleeping
| 'use client' | |
| import { create } from 'zustand' | |
| import type { Player, PlayerInventory } from '@/types' | |
| import { CREATIVE_BLOCKS } from '@/engine/constants' | |
| interface PlayerStore { | |
| player: Player | null | |
| initPlayer: (spawnY?: number) => void | |
| updatePosition: (pos: [number, number, number]) => void | |
| updateRotation: (rot: [number, number]) => void | |
| updateVelocity: (vel: [number, number, number]) => void | |
| setHealth: (hp: number) => void | |
| setFood: (food: number) => void | |
| setGamemode: (mode: Player['gamemode']) => void | |
| setSelectedSlot: (slot: number) => void | |
| setSneaking: (v: boolean) => void | |
| setSprinting: (v: boolean) => void | |
| setFlying: (v: boolean) => void | |
| damage: (amount: number) => void | |
| heal: (amount: number) => void | |
| feed: (amount: number) => void | |
| starve: (amount: number) => void | |
| } | |
| export const usePlayerStore = create<PlayerStore>((set, get) => ({ | |
| player: null, | |
| initPlayer: (spawnY = 100) => { | |
| const inventory: PlayerInventory = { | |
| hotbar: Array(9).fill(null), | |
| main: Array(27).fill(null), | |
| armor: Array(4).fill(null), | |
| offhand: null, | |
| } | |
| // Fill hotbar with a diverse selection of creative blocks | |
| const starterBlocks = [ | |
| CREATIVE_BLOCKS[0], // stone | |
| CREATIVE_BLOCKS[1], // granite | |
| CREATIVE_BLOCKS[3], // dirt | |
| CREATIVE_BLOCKS[4], // grass | |
| CREATIVE_BLOCKS[7], // sand | |
| CREATIVE_BLOCKS[10], // oak planks | |
| CREATIVE_BLOCKS[8], // cobblestone | |
| CREATIVE_BLOCKS[12], // oak log | |
| CREATIVE_BLOCKS[5], // bedrock | |
| ] | |
| starterBlocks.forEach((blockId, i) => { | |
| if (blockId !== undefined) { | |
| inventory.hotbar[i] = { id: blockId, count: 64, damage: 0 } | |
| } | |
| }) | |
| set({ | |
| player: { | |
| id: 'player', | |
| uuid: crypto.randomUUID(), | |
| position: [8, spawnY, 8], | |
| velocity: [0, 0, 0], | |
| rotation: [0, 0], | |
| health: 20, | |
| maxHealth: 20, | |
| onGround: false, | |
| gamemode: 'creative', | |
| inventory, | |
| selectedSlot: 0, | |
| foodLevel: 20, | |
| saturation: 5, | |
| experience: 0, | |
| experienceLevel: 0, | |
| flying: true, | |
| sneaking: false, | |
| sprinting: false, | |
| } | |
| }) | |
| }, | |
| updatePosition: (pos) => set(s => s.player ? { player: { ...s.player, position: pos } } : s), | |
| updateRotation: (rot) => set(s => s.player ? { player: { ...s.player, rotation: rot } } : s), | |
| updateVelocity: (vel) => set(s => s.player ? { player: { ...s.player, velocity: vel } } : s), | |
| setHealth: (hp) => set(s => s.player ? { | |
| player: { ...s.player, health: Math.max(0, Math.min(s.player.maxHealth, hp)) } | |
| } : s), | |
| setFood: (food) => set(s => s.player ? { | |
| player: { ...s.player, foodLevel: Math.max(0, Math.min(20, food)) } | |
| } : s), | |
| setGamemode: (mode) => set(s => s.player ? { | |
| player: { | |
| ...s.player, | |
| gamemode: mode, | |
| flying: mode === 'creative' ? true : s.player.flying, | |
| } | |
| } : s), | |
| setSelectedSlot: (slot) => set(s => s.player ? { player: { ...s.player, selectedSlot: slot } } : s), | |
| setSneaking: (v) => set(s => s.player ? { player: { ...s.player, sneaking: v } } : s), | |
| setSprinting: (v) => set(s => s.player ? { player: { ...s.player, sprinting: v } } : s), | |
| setFlying: (v) => set(s => s.player ? { player: { ...s.player, flying: v } } : s), | |
| damage: (amount) => set(s => { | |
| if (!s.player) return s | |
| const newHealth = Math.max(0, s.player.health - amount) | |
| return { player: { ...s.player, health: newHealth } } | |
| }), | |
| heal: (amount) => set(s => { | |
| if (!s.player) return s | |
| return { player: { ...s.player, health: Math.min(s.player.maxHealth, s.player.health + amount) } } | |
| }), | |
| feed: (amount) => set(s => { | |
| if (!s.player) return s | |
| return { player: { ...s.player, foodLevel: Math.min(20, s.player.foodLevel + amount) } } | |
| }), | |
| starve: (amount) => set(s => { | |
| if (!s.player) return s | |
| return { player: { ...s.player, foodLevel: Math.max(0, s.player.foodLevel - amount) } } | |
| }), | |
| })) | |