diff --git a/assets/females/10.png b/assets/females/10.png index 729672a..c768bda 100644 Binary files a/assets/females/10.png and b/assets/females/10.png differ diff --git a/assets/females/11.png b/assets/females/11.png index 16b2634..dd97db0 100644 Binary files a/assets/females/11.png and b/assets/females/11.png differ diff --git a/assets/females/12.png b/assets/females/12.png index a412bca..7513363 100644 Binary files a/assets/females/12.png and b/assets/females/12.png differ diff --git a/assets/females/13.png b/assets/females/13.png index b005228..94b013a 100644 Binary files a/assets/females/13.png and b/assets/females/13.png differ diff --git a/assets/females/14.png b/assets/females/14.png index f440924..965da2d 100644 Binary files a/assets/females/14.png and b/assets/females/14.png differ diff --git a/assets/females/15.png b/assets/females/15.png index 0290b96..0c1ab9d 100644 Binary files a/assets/females/15.png and b/assets/females/15.png differ diff --git a/assets/females/9_avatar.png b/assets/females/16.png similarity index 100% rename from assets/females/9_avatar.png rename to assets/females/16.png diff --git a/assets/females/17.png b/assets/females/17.png new file mode 100644 index 0000000..729672a Binary files /dev/null and b/assets/females/17.png differ diff --git a/assets/females/10_avatar.png b/assets/females/18.png similarity index 100% rename from assets/females/10_avatar.png rename to assets/females/18.png diff --git a/assets/females/19.png b/assets/females/19.png new file mode 100644 index 0000000..16b2634 Binary files /dev/null and b/assets/females/19.png differ diff --git a/assets/females/1_avatar.png b/assets/females/2.png similarity index 100% rename from assets/females/1_avatar.png rename to assets/females/2.png diff --git a/assets/females/20.png b/assets/females/20.png new file mode 100644 index 0000000..a412bca Binary files /dev/null and b/assets/females/20.png differ diff --git a/assets/females/12_avatar.png b/assets/females/21.png similarity index 100% rename from assets/females/12_avatar.png rename to assets/females/21.png diff --git a/assets/females/22.png b/assets/females/22.png new file mode 100644 index 0000000..b005228 Binary files /dev/null and b/assets/females/22.png differ diff --git a/assets/females/13_avatar.png b/assets/females/23.png similarity index 100% rename from assets/females/13_avatar.png rename to assets/females/23.png diff --git a/assets/females/24.png b/assets/females/24.png new file mode 100644 index 0000000..f440924 Binary files /dev/null and b/assets/females/24.png differ diff --git a/assets/females/14_avatar.png b/assets/females/25.png similarity index 100% rename from assets/females/14_avatar.png rename to assets/females/25.png diff --git a/assets/females/26.png b/assets/females/26.png new file mode 100644 index 0000000..0290b96 Binary files /dev/null and b/assets/females/26.png differ diff --git a/assets/females/15_avatar.png b/assets/females/27.png similarity index 100% rename from assets/females/15_avatar.png rename to assets/females/27.png diff --git a/assets/females/16_avatar.png b/assets/females/28.png similarity index 100% rename from assets/females/16_avatar.png rename to assets/females/28.png diff --git a/assets/females/17_avatar.png b/assets/females/29.png similarity index 100% rename from assets/females/17_avatar.png rename to assets/females/29.png diff --git a/assets/females/2_avatar.png b/assets/females/2_avatar.png deleted file mode 100644 index 89cbb82..0000000 Binary files a/assets/females/2_avatar.png and /dev/null differ diff --git a/assets/females/3.png b/assets/females/3.png index 3936d22..89cbb82 100644 Binary files a/assets/females/3.png and b/assets/females/3.png differ diff --git a/assets/females/18_avatar.png b/assets/females/30.png similarity index 100% rename from assets/females/18_avatar.png rename to assets/females/30.png diff --git a/assets/females/21_avatar.png b/assets/females/31.png similarity index 100% rename from assets/females/21_avatar.png rename to assets/females/31.png diff --git a/assets/females/22_avatar.png b/assets/females/32.png similarity index 100% rename from assets/females/22_avatar.png rename to assets/females/32.png diff --git a/assets/females/23_avatar.png b/assets/females/33.png similarity index 100% rename from assets/females/23_avatar.png rename to assets/females/33.png diff --git a/assets/females/24_avatar.png b/assets/females/34.png similarity index 100% rename from assets/females/24_avatar.png rename to assets/females/34.png diff --git a/assets/females/25_avatar.png b/assets/females/35.png similarity index 100% rename from assets/females/25_avatar.png rename to assets/females/35.png diff --git a/assets/females/26_avatar.png b/assets/females/36.png similarity index 100% rename from assets/females/26_avatar.png rename to assets/females/36.png diff --git a/assets/females/27_avatar.png b/assets/females/37.png similarity index 100% rename from assets/females/27_avatar.png rename to assets/females/37.png diff --git a/assets/females/28_avatar.png b/assets/females/38.png similarity index 100% rename from assets/females/28_avatar.png rename to assets/females/38.png diff --git a/assets/females/29_avatar.png b/assets/females/39.png similarity index 100% rename from assets/females/29_avatar.png rename to assets/females/39.png diff --git a/assets/females/3_avatar.png b/assets/females/3_avatar.png deleted file mode 100644 index 32f387f..0000000 Binary files a/assets/females/3_avatar.png and /dev/null differ diff --git a/assets/females/4.png b/assets/females/4.png index e003ca6..3936d22 100644 Binary files a/assets/females/4.png and b/assets/females/4.png differ diff --git a/assets/females/30_avatar.png b/assets/females/40.png similarity index 100% rename from assets/females/30_avatar.png rename to assets/females/40.png diff --git a/assets/females/31_avatar.png b/assets/females/41.png similarity index 100% rename from assets/females/31_avatar.png rename to assets/females/41.png diff --git a/assets/females/4_avatar.png b/assets/females/4_avatar.png deleted file mode 100644 index 81a900a..0000000 Binary files a/assets/females/4_avatar.png and /dev/null differ diff --git a/assets/females/5.png b/assets/females/5.png index 483ede6..32f387f 100644 Binary files a/assets/females/5.png and b/assets/females/5.png differ diff --git a/assets/females/5_avatar.png b/assets/females/5_avatar.png deleted file mode 100644 index 7648396..0000000 Binary files a/assets/females/5_avatar.png and /dev/null differ diff --git a/assets/females/6.png b/assets/females/6.png index c768bda..e003ca6 100644 Binary files a/assets/females/6.png and b/assets/females/6.png differ diff --git a/assets/females/6_avatar.png b/assets/females/6_avatar.png deleted file mode 100644 index dd97db0..0000000 Binary files a/assets/females/6_avatar.png and /dev/null differ diff --git a/assets/females/7.png b/assets/females/7.png index 7513363..81a900a 100644 Binary files a/assets/females/7.png and b/assets/females/7.png differ diff --git a/assets/females/7_avatar.png b/assets/females/7_avatar.png deleted file mode 100644 index 94b013a..0000000 Binary files a/assets/females/7_avatar.png and /dev/null differ diff --git a/assets/females/8.png b/assets/females/8.png index 965da2d..483ede6 100644 Binary files a/assets/females/8.png and b/assets/females/8.png differ diff --git a/assets/females/9.png b/assets/females/9.png index 0c1ab9d..7648396 100644 Binary files a/assets/females/9.png and b/assets/females/9.png differ diff --git a/assets/males/10.png b/assets/males/10.png index 1435917..b7e6e08 100644 Binary files a/assets/males/10.png and b/assets/males/10.png differ diff --git a/assets/males/11.png b/assets/males/11.png index 54fdc65..ce3af48 100644 Binary files a/assets/males/11.png and b/assets/males/11.png differ diff --git a/assets/males/12.png b/assets/males/12.png index d06f8e5..ba6d626 100644 Binary files a/assets/males/12.png and b/assets/males/12.png differ diff --git a/assets/males/13.png b/assets/males/13.png index 201b41b..3b29019 100644 Binary files a/assets/males/13.png and b/assets/males/13.png differ diff --git a/assets/males/14.png b/assets/males/14.png index 1eace0a..2127a01 100644 Binary files a/assets/males/14.png and b/assets/males/14.png differ diff --git a/assets/males/15.png b/assets/males/15.png index 2738d67..2ecf337 100644 Binary files a/assets/males/15.png and b/assets/males/15.png differ diff --git a/assets/males/16.png b/assets/males/16.png index 6c12a71..23179a9 100644 Binary files a/assets/males/16.png and b/assets/males/16.png differ diff --git a/assets/males/17.png b/assets/males/17.png new file mode 100644 index 0000000..8d41a38 Binary files /dev/null and b/assets/males/17.png differ diff --git a/assets/males/9_avatar.png b/assets/males/18.png similarity index 100% rename from assets/males/9_avatar.png rename to assets/males/18.png diff --git a/assets/males/19.png b/assets/males/19.png new file mode 100644 index 0000000..1435917 Binary files /dev/null and b/assets/males/19.png differ diff --git a/assets/males/1_avatar.png b/assets/males/1_avatar.png deleted file mode 100644 index 6ef31ba..0000000 Binary files a/assets/males/1_avatar.png and /dev/null differ diff --git a/assets/males/2.png b/assets/males/2.png index c7366af..6ef31ba 100644 Binary files a/assets/males/2.png and b/assets/males/2.png differ diff --git a/assets/males/10_avatar.png b/assets/males/20.png similarity index 100% rename from assets/males/10_avatar.png rename to assets/males/20.png diff --git a/assets/males/21.png b/assets/males/21.png new file mode 100644 index 0000000..54fdc65 Binary files /dev/null and b/assets/males/21.png differ diff --git a/assets/males/11_avatar.png b/assets/males/22.png similarity index 100% rename from assets/males/11_avatar.png rename to assets/males/22.png diff --git a/assets/males/23.png b/assets/males/23.png new file mode 100644 index 0000000..d06f8e5 Binary files /dev/null and b/assets/males/23.png differ diff --git a/assets/males/12_avatar.png b/assets/males/24.png similarity index 100% rename from assets/males/12_avatar.png rename to assets/males/24.png diff --git a/assets/males/25.png b/assets/males/25.png new file mode 100644 index 0000000..201b41b Binary files /dev/null and b/assets/males/25.png differ diff --git a/assets/males/13_avatar.png b/assets/males/26.png similarity index 100% rename from assets/males/13_avatar.png rename to assets/males/26.png diff --git a/assets/males/27.png b/assets/males/27.png new file mode 100644 index 0000000..1eace0a Binary files /dev/null and b/assets/males/27.png differ diff --git a/assets/males/14_avatar.png b/assets/males/28.png similarity index 100% rename from assets/males/14_avatar.png rename to assets/males/28.png diff --git a/assets/males/29.png b/assets/males/29.png new file mode 100644 index 0000000..2738d67 Binary files /dev/null and b/assets/males/29.png differ diff --git a/assets/males/2_avatar.png b/assets/males/2_avatar.png deleted file mode 100644 index 95d6c60..0000000 Binary files a/assets/males/2_avatar.png and /dev/null differ diff --git a/assets/males/3.png b/assets/males/3.png index a1c0edb..c7366af 100644 Binary files a/assets/males/3.png and b/assets/males/3.png differ diff --git a/assets/males/15_avatar.png b/assets/males/30.png similarity index 100% rename from assets/males/15_avatar.png rename to assets/males/30.png diff --git a/assets/males/31.png b/assets/males/31.png new file mode 100644 index 0000000..6c12a71 Binary files /dev/null and b/assets/males/31.png differ diff --git a/assets/males/16_avatar.png b/assets/males/32.png similarity index 100% rename from assets/males/16_avatar.png rename to assets/males/32.png diff --git a/assets/males/17_avatar.png b/assets/males/33.png similarity index 100% rename from assets/males/17_avatar.png rename to assets/males/33.png diff --git a/assets/males/18_avatar.png b/assets/males/34.png similarity index 100% rename from assets/males/18_avatar.png rename to assets/males/34.png diff --git a/assets/males/19_avatar.png b/assets/males/35.png similarity index 100% rename from assets/males/19_avatar.png rename to assets/males/35.png diff --git a/assets/males/20_avatar.png b/assets/males/36.png similarity index 100% rename from assets/males/20_avatar.png rename to assets/males/36.png diff --git a/assets/males/21_avatar.png b/assets/males/37.png similarity index 100% rename from assets/males/21_avatar.png rename to assets/males/37.png diff --git a/assets/males/22_avatar.png b/assets/males/38.png similarity index 100% rename from assets/males/22_avatar.png rename to assets/males/38.png diff --git a/assets/males/23_avatar.png b/assets/males/39.png similarity index 100% rename from assets/males/23_avatar.png rename to assets/males/39.png diff --git a/assets/males/3_avatar.png b/assets/males/3_avatar.png deleted file mode 100644 index 08df947..0000000 Binary files a/assets/males/3_avatar.png and /dev/null differ diff --git a/assets/males/4.png b/assets/males/4.png index 6be2e7f..95d6c60 100644 Binary files a/assets/males/4.png and b/assets/males/4.png differ diff --git a/assets/males/24_avatar.png b/assets/males/40.png similarity index 100% rename from assets/males/24_avatar.png rename to assets/males/40.png diff --git a/assets/males/25_avatar.png b/assets/males/41.png similarity index 100% rename from assets/males/25_avatar.png rename to assets/males/41.png diff --git a/assets/males/26_avatar.png b/assets/males/42.png similarity index 100% rename from assets/males/26_avatar.png rename to assets/males/42.png diff --git a/assets/males/27_avatar.png b/assets/males/43.png similarity index 100% rename from assets/males/27_avatar.png rename to assets/males/43.png diff --git a/assets/males/28_avatar.png b/assets/males/44.png similarity index 100% rename from assets/males/28_avatar.png rename to assets/males/44.png diff --git a/assets/males/29_avatar.png b/assets/males/45.png similarity index 100% rename from assets/males/29_avatar.png rename to assets/males/45.png diff --git a/assets/males/30_avatar.png b/assets/males/46.png similarity index 100% rename from assets/males/30_avatar.png rename to assets/males/46.png diff --git a/assets/males/31_avatar.png b/assets/males/47.png similarity index 100% rename from assets/males/31_avatar.png rename to assets/males/47.png diff --git a/assets/males/4_avatar.png b/assets/males/4_avatar.png deleted file mode 100644 index cc6154a..0000000 Binary files a/assets/males/4_avatar.png and /dev/null differ diff --git a/assets/males/5.png b/assets/males/5.png index 3fd78f3..a1c0edb 100644 Binary files a/assets/males/5.png and b/assets/males/5.png differ diff --git a/assets/males/5_avatar.png b/assets/males/5_avatar.png deleted file mode 100644 index b7e6e08..0000000 Binary files a/assets/males/5_avatar.png and /dev/null differ diff --git a/assets/males/6.png b/assets/males/6.png index ce3af48..08df947 100644 Binary files a/assets/males/6.png and b/assets/males/6.png differ diff --git a/assets/males/6_avatar.png b/assets/males/6_avatar.png deleted file mode 100644 index ba6d626..0000000 Binary files a/assets/males/6_avatar.png and /dev/null differ diff --git a/assets/males/7.png b/assets/males/7.png index 3b29019..6be2e7f 100644 Binary files a/assets/males/7.png and b/assets/males/7.png differ diff --git a/assets/males/7_avatar.png b/assets/males/7_avatar.png deleted file mode 100644 index 2127a01..0000000 Binary files a/assets/males/7_avatar.png and /dev/null differ diff --git a/assets/males/8.png b/assets/males/8.png index 2ecf337..cc6154a 100644 Binary files a/assets/males/8.png and b/assets/males/8.png differ diff --git a/assets/males/8_avatar.png b/assets/males/8_avatar.png deleted file mode 100644 index 23179a9..0000000 Binary files a/assets/males/8_avatar.png and /dev/null differ diff --git a/assets/males/9.png b/assets/males/9.png index 8d41a38..3fd78f3 100644 Binary files a/assets/males/9.png and b/assets/males/9.png differ diff --git a/src/server/main.py b/src/server/main.py index 96f99bd..f680c20 100644 --- a/src/server/main.py +++ b/src/server/main.py @@ -35,6 +35,47 @@ game_instance = { "is_paused": True # 默认启动为暂停状态,等待前端连接唤醒 } +# Cache for avatar IDs +AVATAR_ASSETS = { + "males": [], + "females": [] +} + +def scan_avatar_assets(): + """Scan assets directory for avatar images""" + global AVATAR_ASSETS + + def get_ids(subdir): + directory = os.path.join(ASSETS_PATH, subdir) + if not os.path.exists(directory): + return [] + ids = [] + for f in os.listdir(directory): + if f.lower().endswith('.png'): + try: + name = os.path.splitext(f)[0] + ids.append(int(name)) + except ValueError: + pass + return sorted(ids) + + AVATAR_ASSETS["males"] = get_ids("males") + AVATAR_ASSETS["females"] = get_ids("females") + print(f"Loaded avatar assets: {len(AVATAR_ASSETS['males'])} males, {len(AVATAR_ASSETS['females'])} females") + +def get_avatar_pic_id(avatar_id: str, gender_val: str) -> int: + """Deterministically get a valid pic_id for an avatar""" + key = "females" if gender_val == "female" else "males" + available = AVATAR_ASSETS.get(key, []) + + if not available: + return 1 + + # Use hash to pick an index from available IDs + # Use abs() because hash can be negative + idx = abs(hash(str(avatar_id))) % len(available) + return available[idx] + # 触发配置重载的标记 (technique.csv updated) # 简易的命令行参数检查 (不使用 argparse 以避免冲突和时序问题) @@ -217,7 +258,7 @@ async def game_loop(): "x": int(getattr(a, "pos_x", 0)), "y": int(getattr(a, "pos_y", 0)), "gender": a.gender.value, # 使用 value (male/female) 而不是 str (中文) - "pic_id": (hash(a.id) % 15) + 1, + "pic_id": get_avatar_pic_id(str(a.id), a.gender.value), "action": getattr(a, "current_action", {}).get("name", "发呆") if hasattr(a, "current_action") and a.current_action else "发呆" }) @@ -253,6 +294,7 @@ async def game_loop(): @asynccontextmanager async def lifespan(app: FastAPI): # 启动时初始化 + scan_avatar_assets() init_game() # 启动后台任务 asyncio.create_task(game_loop()) @@ -356,6 +398,11 @@ async def websocket_endpoint(websocket: WebSocket): print(f"WS Error: {e}") manager.disconnect(websocket) +@app.get("/api/meta/avatars") +def get_avatar_meta(): + return AVATAR_ASSETS + + @app.get("/api/state") def get_state(): """获取当前世界的一个快照(调试模式)""" @@ -403,7 +450,7 @@ def get_state(): "y": ay, "action": str(aaction), "gender": str(a.gender.value), - "pic_id": (hash(a.id) % 15) + 1 + "pic_id": get_avatar_pic_id(aid, str(a.gender.value)) }) except Exception as e: return {"step": 3, "error": str(e)} @@ -534,6 +581,7 @@ def get_detail_info( ): """获取结构化详情信息,替代/增强 hover info""" world = game_instance.get("world") + if world is None: raise HTTPException(status_code=503, detail="World not initialized") diff --git a/web/src/api/game.ts b/web/src/api/game.ts index f1862ac..a6ef572 100644 --- a/web/src/api/game.ts +++ b/web/src/api/game.ts @@ -23,6 +23,10 @@ export const gameApi = { return httpClient.get('/api/map'); }, + fetchAvatarMeta() { + return httpClient.get<{ males: number[]; females: number[] }>('/api/meta/avatars'); + }, + // --- Information --- fetchHoverInfo(params: HoverParams) { diff --git a/web/src/components/game/AnimatedAvatar.vue b/web/src/components/game/AnimatedAvatar.vue index cb5aa98..5657f34 100644 --- a/web/src/components/game/AnimatedAvatar.vue +++ b/web/src/components/game/AnimatedAvatar.vue @@ -14,7 +14,7 @@ const emit = defineEmits<{ (e: 'select', payload: { type: 'avatar'; id: string; name?: string }): void }>() -const { textures } = useTextures() +const { textures, availableAvatars } = useTextures() // Target position (grid coordinates) const targetX = ref(props.avatar.x) @@ -50,7 +50,25 @@ useSharedTicker((delta) => { }) function getTexture() { - const key = `${(props.avatar.gender || 'male').toLowerCase()}_${props.avatar.pic_id || 1}` + const gender = (props.avatar.gender || 'male').toLowerCase() + let pid = props.avatar.pic_id + + // Fallback logic if pic_id is missing + if (!pid) { + const list = availableAvatars.value[gender === 'female' ? 'females' : 'males'] + if (list && list.length > 0) { + let hash = 0 + const str = props.avatar.id || props.avatar.name || 'default' + for (let i = 0; i < str.length; i++) { + hash = str.charCodeAt(i) + ((hash << 5) - hash) + } + pid = list[Math.abs(hash) % list.length] + } else { + pid = 1 + } + } + + const key = `${gender}_${pid}` return textures.value[key] } diff --git a/web/src/components/game/composables/useTextures.ts b/web/src/components/game/composables/useTextures.ts index a7eae9e..76c8ac5 100644 --- a/web/src/components/game/composables/useTextures.ts +++ b/web/src/components/game/composables/useTextures.ts @@ -1,5 +1,6 @@ import { ref } from 'vue' import { Assets, Texture, TextureStyle } from 'pixi.js' +import { gameApi } from '@/api/game' // 设置全局纹理缩放模式为 nearest (像素风) TextureStyle.defaultOptions.scaleMode = 'nearest' @@ -7,6 +8,7 @@ TextureStyle.defaultOptions.scaleMode = 'nearest' // 全局纹理缓存,避免重复加载 const textures = ref>({}) const isLoaded = ref(false) +const availableAvatars = ref<{ males: number[], females: number[] }>({ males: [], females: [] }) export function useTextures() { @@ -14,6 +16,19 @@ export function useTextures() { const loadBaseTextures = async () => { if (isLoaded.value) return + // Load Avatar Meta first + try { + const meta = await gameApi.fetchAvatarMeta() + if (meta.males) availableAvatars.value.males = meta.males + if (meta.females) availableAvatars.value.females = meta.females + console.log('Avatar meta loaded:', availableAvatars.value) + } catch (e) { + console.warn('Failed to load avatar meta, using default range', e) + // Fallback + availableAvatars.value.males = Array.from({length: 47}, (_, i) => i + 1) + availableAvatars.value.females = Array.from({length: 41}, (_, i) => i + 1) + } + const manifest: Record = { 'PLAIN': '/assets/tiles/plain.png', 'WATER': '/assets/tiles/water.png', @@ -41,19 +56,24 @@ export function useTextures() { } }) - const avatarPromises = Array.from({ length: 16 }, (_, index) => index + 1).map(async (i) => { - const maleUrl = `/assets/males/${i}.png` - const femaleUrl = `/assets/females/${i}.png` - - await Promise.allSettled([ - Assets.load(maleUrl).then((tex) => { - textures.value[`male_${i}`] = tex - }), - Assets.load(femaleUrl).then((tex) => { - textures.value[`female_${i}`] = tex - }) - ]) - }) + // Load Avatars based on available IDs + const avatarPromises: Promise[] = [] + + for (const id of availableAvatars.value.males) { + avatarPromises.push( + Assets.load(`/assets/males/${id}.png`) + .then(tex => { textures.value[`male_${id}`] = tex }) + .catch(e => console.warn(`Failed male_${id}`, e)) + ) + } + + for (const id of availableAvatars.value.females) { + avatarPromises.push( + Assets.load(`/assets/females/${id}.png`) + .then(tex => { textures.value[`female_${id}`] = tex }) + .catch(e => console.warn(`Failed female_${id}`, e)) + ) + } await Promise.all([...tilePromises, ...avatarPromises]) @@ -83,7 +103,8 @@ export function useTextures() { textures, isLoaded, loadBaseTextures, - loadSectTexture + loadSectTexture, + availableAvatars } }