mirror of
https://github.com/setube/ogame-vue-ts.git
synced 2026-05-12 07:55:11 +08:00
重构App.vue,首页独立无侧边栏,其他页面采用统一侧边栏布局。新增右下角固定通知区,集成返回顶部、队列通知、外交通知和敌方警报。移除新手引导组件,替换为弱引导提示系统。支持星球重命名弹窗。优化NPC成长与行为定时器逻辑,提升性能和可维护性。删除issue模板及相关文档描述。
190 lines
6.3 KiB
TypeScript
190 lines
6.3 KiB
TypeScript
import type { Planet, DebrisField, NPC } from '@/types/game'
|
||
import { decryptData, encryptData } from './crypto'
|
||
import pkg from '../../package.json'
|
||
|
||
/**
|
||
* 数据迁移工具
|
||
* 用于从旧版本数据结构迁移到新版本
|
||
*/
|
||
|
||
/**
|
||
* 执行数据迁移
|
||
* 将旧版本的 universePlanets 和 debrisFields 从 gameStore 迁移到 universeStore
|
||
*/
|
||
export const migrateGameData = (): void => {
|
||
try {
|
||
const storageKey = pkg.name
|
||
const universeStorageKey = `${pkg.name}-universe`
|
||
|
||
// 读取旧的加密存档
|
||
const oldEncryptedData = localStorage.getItem(storageKey)
|
||
if (!oldEncryptedData) return
|
||
|
||
// 尝试解密(如果是加密格式)
|
||
let oldData: any
|
||
try {
|
||
oldData = decryptData(oldEncryptedData)
|
||
} catch {
|
||
// 解密失败,可能是新格式(未加密),直接解析
|
||
try {
|
||
oldData = JSON.parse(oldEncryptedData)
|
||
} catch {
|
||
return // 无法解析,放弃迁移
|
||
}
|
||
}
|
||
|
||
// 标记是否有数据需要保存
|
||
let needsSave = false
|
||
|
||
// 修复NPC数据(确保所有必需字段都存在)
|
||
if (oldData.npcs && Array.isArray(oldData.npcs)) {
|
||
const now = Date.now()
|
||
const playerId = oldData.player?.id
|
||
|
||
oldData.npcs.forEach((npc: NPC) => {
|
||
// 确保NPC有必需的时间字段,并设置随机冷却避免同时行动
|
||
if (npc.lastSpyTime === undefined || npc.lastSpyTime === 0) {
|
||
// 0-4分钟的随机延迟
|
||
const randomSpyOffset = Math.random() * 240 * 1000
|
||
npc.lastSpyTime = now - randomSpyOffset
|
||
needsSave = true
|
||
}
|
||
if (npc.lastAttackTime === undefined || npc.lastAttackTime === 0) {
|
||
// 0-8分钟的随机延迟
|
||
const randomAttackOffset = Math.random() * 480 * 1000
|
||
npc.lastAttackTime = now - randomAttackOffset
|
||
needsSave = true
|
||
}
|
||
// 确保NPC有必需的数组字段
|
||
if (!npc.fleetMissions) {
|
||
npc.fleetMissions = []
|
||
needsSave = true
|
||
}
|
||
if (!npc.playerSpyReports) {
|
||
npc.playerSpyReports = {}
|
||
needsSave = true
|
||
}
|
||
if (!npc.relations) {
|
||
npc.relations = {}
|
||
needsSave = true
|
||
}
|
||
if (!npc.allies) {
|
||
npc.allies = []
|
||
needsSave = true
|
||
}
|
||
if (!npc.enemies) {
|
||
npc.enemies = []
|
||
needsSave = true
|
||
}
|
||
|
||
// 如果NPC与玩家没有建立关系,自动建立中立关系
|
||
if (playerId && !npc.relations[playerId]) {
|
||
npc.relations[playerId] = {
|
||
fromId: npc.id,
|
||
toId: playerId,
|
||
reputation: 0,
|
||
status: 'neutral' as const,
|
||
lastUpdated: now,
|
||
history: []
|
||
}
|
||
needsSave = true
|
||
}
|
||
})
|
||
}
|
||
|
||
// 初始化玩家积分(如果不存在)
|
||
if (oldData.player && oldData.player.points === undefined) {
|
||
// 积分会在游戏启动时通过 initGame 计算,这里设置为0
|
||
oldData.player.points = 0
|
||
needsSave = true
|
||
}
|
||
|
||
// 迁移 player.diplomaticRelations 到 npc.relations
|
||
// 旧版本使用 player.diplomaticRelations[npcId] 存储玩家对NPC的关系
|
||
// 新版本统一使用 npc.relations[playerId] 存储NPC对玩家的关系
|
||
if (oldData.player?.diplomaticRelations && oldData.npcs && Array.isArray(oldData.npcs)) {
|
||
const playerId = oldData.player.id
|
||
const playerRelations = oldData.player.diplomaticRelations as Record<string, any>
|
||
|
||
Object.entries(playerRelations).forEach(([npcId, relation]) => {
|
||
const npc = oldData.npcs.find((n: NPC) => n.id === npcId)
|
||
if (npc) {
|
||
if (!npc.relations) {
|
||
npc.relations = {}
|
||
}
|
||
// 如果NPC对玩家的关系不存在,使用玩家对NPC的关系数据
|
||
if (!npc.relations[playerId]) {
|
||
npc.relations[playerId] = {
|
||
...relation,
|
||
fromId: npcId,
|
||
toId: playerId
|
||
}
|
||
needsSave = true
|
||
} else {
|
||
// 如果两边都有数据,使用声望值更极端的那个(偏离0更远的)
|
||
const existingReputation = npc.relations[playerId].reputation || 0
|
||
const playerReputation = relation.reputation || 0
|
||
if (Math.abs(playerReputation) > Math.abs(existingReputation)) {
|
||
npc.relations[playerId].reputation = playerReputation
|
||
npc.relations[playerId].status = relation.status
|
||
needsSave = true
|
||
}
|
||
}
|
||
}
|
||
})
|
||
|
||
// 删除旧的 diplomaticRelations 字段
|
||
delete oldData.player.diplomaticRelations
|
||
needsSave = true
|
||
console.log('[Migration] Migrated player.diplomaticRelations to npc.relations')
|
||
}
|
||
|
||
// 检查是否需要迁移地图数据
|
||
const hasOldMapData = oldData.universePlanets || oldData.debrisFields
|
||
|
||
if (hasOldMapData) {
|
||
// 准备 universeStore 数据
|
||
const universeData: {
|
||
planets: Record<string, Planet>
|
||
debrisFields: Record<string, DebrisField>
|
||
} = {
|
||
planets: {},
|
||
debrisFields: {}
|
||
}
|
||
|
||
// 迁移星球数据(排除玩家星球)
|
||
if (oldData.universePlanets) {
|
||
const oldPlanets = oldData.universePlanets as Record<string, Planet>
|
||
const playerPlanets = oldData.player?.planets || []
|
||
const playerPlanetIds = new Set(playerPlanets.map((p: Planet) => p.id))
|
||
Object.entries(oldPlanets).forEach(([key, planet]) => {
|
||
// 只迁移非玩家星球
|
||
if (!playerPlanetIds.has(planet.id)) {
|
||
universeData.planets[key] = planet
|
||
}
|
||
})
|
||
delete oldData.universePlanets
|
||
needsSave = true
|
||
}
|
||
|
||
// 迁移残骸场数据
|
||
if (oldData.debrisFields) {
|
||
universeData.debrisFields = oldData.debrisFields
|
||
delete oldData.debrisFields
|
||
needsSave = true
|
||
}
|
||
|
||
// 保存universeStore数据
|
||
localStorage.setItem(universeStorageKey, encryptData(universeData))
|
||
}
|
||
|
||
// 如果有任何数据被修改,保存gameStore数据
|
||
if (needsSave) {
|
||
localStorage.setItem(storageKey, encryptData(oldData))
|
||
console.log('[Migration] Game data migrated successfully')
|
||
}
|
||
} catch (error) {
|
||
console.error('[Migration] Failed to migrate game data:', error)
|
||
}
|
||
}
|