UNPKG

maestrale

Version:
1,129 lines (1,115 loc) 29.5 kB
import { ShareCfg } from "@maestrale/data"; import { computed, isRef, ref, shallowReactive, shallowRef, toRaw, toValue, watch } from "@vue/reactivity"; export * from "@maestrale/data" //#region src/core/attributes.ts function createAttributes(options = {}) { return { durability: 0, cannon: 0, torpedo: 0, antiaircraft: 0, air: 0, reload: 0, hit: 0, dodge: 0, speed: 0, luck: 0, antisub: 0, ...options }; } //#endregion //#region src/utils.ts const ShipFleetKey = Symbol(); function nonNullable(obj) { return obj !== null && obj !== void 0; } function* entries(obj) { for (const key in obj) yield [key, obj[key]]; } //#endregion //#region src/core/commander.ts var Commander = class { data_template; level; name; constructor(id) { this.id = id; this.data_template = ShareCfg.commander_data_template[id]; this.level = ref(this.maxLevel); this.name = ref(this.originalName); } get originalName() { return this.data_template.name; } get nationality() { return this.data_template.nationality; } get rarity() { return this.data_template.rarity; } get painting() { return this.data_template.painting; } get maxLevel() { return this.data_template.max_level; } getAbility(baseVal) { return Math.floor(baseVal * (1 + 3 / 38 * (this.level.value - 1))); } support = computed(() => { return this.getAbility(this.data_template.support_value); }); command = computed(() => { return this.getAbility(this.data_template.command_value); }); tactic = computed(() => { return this.getAbility(this.data_template.tactic_value); }); attrRates = computed(() => { const attrs = createAttributes(); for (const [key] of entries(attrs)) { const coefficient = getCoefficient(key); const efficiency = this.support.value * coefficient[0] + this.command.value * coefficient[1] + this.tactic.value * coefficient[2]; const percent = 6 * efficiency / (250 + efficiency) / 100; attrs[key] = Math.round(percent * 1e3) / 1e3; } return attrs; }); abilities = shallowReactive([]); }; function createCommander(id) { if (!(id in ShareCfg.commander_data_template)) return null; return new Commander(id); } function getCoefficient(attr) { switch (attr) { case "durability": return [ .9, 0, 0 ]; case "cannon": return [ .3, .6, 0 ]; case "torpedo": return [ 0, .3, .6 ]; case "antiaircraft": return [ 0, 0, .9 ]; case "air": return [ .6, 0, .3 ]; case "antisub": return [ 0, .9, 0 ]; default: return [ 0, 0, 0 ]; } } var CommanderAbility = class { data_template; effects; constructor(id) { this.id = id; this.data_template = ShareCfg.commander_ability_template[id]; this.effects = this.data_template.add.map(([type, nationalities, shipTypes, key, value]) => ({ type, nationalities, shipTypes, key, value })); } get name() { return this.data_template.name; } get desc() { return this.data_template.desc; } get icon() { return this.data_template.icon; } get worth() { return this.data_template.worth; } }; function createCommanderAbility(id) { if (!(id in ShareCfg.commander_ability_template)) return null; return new CommanderAbility(id); } //#endregion //#region src/core/equip.ts var Equip = class { data_statistics; data_template; level; constructor(id) { this.id = id; this.data_statistics = []; this.data_template = []; for (let i = id; i !== 0;) { const stat = ShareCfg.equip_data_statistics[i]; const temp = ShareCfg.equip_data_template[i]; this.data_statistics.push(stat); this.data_template.push(temp); i = temp.next; } this.level = ref(this.maxLevel); } curStat = computed(() => { return { ...this.data_statistics[0], ...this.data_statistics[this.level.value] }; }); get name() { return this.data_statistics[0].name; } get icon() { return this.data_statistics[0].icon; } get nationality() { return this.data_statistics[0].nationality; } get rarity() { return this.data_statistics[0].rarity; } get type() { return this.data_statistics[0].type; } get maxLevel() { return this.data_statistics.length - 1; } attrs = computed(() => { const res = {}; for (const i of [ 1, 2, 3 ]) { const attrKey = `attribute_${i}`; const valueKey = `value_${i}`; if (attrKey in this.curStat.value) { const attr = this.curStat.value[attrKey]; const value = Number(this.curStat.value[valueKey]); res[attr] = value; } } return res; }); }; function createEquip(id) { if (id % 10 !== 0 || !(id in ShareCfg.equip_data_template)) return null; return new Equip(id); } //#endregion //#region src/core/fleet.ts var Fleet = class { name; constructor(name) { this.name = ref(name); } commander1 = shallowRef(null); commander2 = shallowRef(null); commanders = computed(() => [this.commander1.value, this.commander2.value]); }; var SurfaceFleet = class extends Fleet { constructor(name) { super(name); track(this); } ships = computed(() => [ this.main1.value, this.main2.value, this.main3.value, this.vanguard1.value, this.vanguard2.value, this.vanguard3.value ]); main1 = shallowRef(null); main2 = shallowRef(null); main3 = shallowRef(null); vanguard1 = shallowRef(null); vanguard2 = shallowRef(null); vanguard3 = shallowRef(null); }; var SubmarineFleet = class extends Fleet { constructor(name) { super(name); track(this); } ships = computed(() => [ this.submarine1.value, this.submarine2.value, this.submarine3.value ]); submarine1 = shallowRef(null); submarine2 = shallowRef(null); submarine3 = shallowRef(null); }; function createFleet(type, name = "新编队") { switch (type) { case "surface": return new SurfaceFleet(name); case "submarine": return new SubmarineFleet(name); } } function track(fleet) { watch(fleet.ships, (newVal, oldVal) => { for (let i = 0; i < newVal.length; i++) { const oldShip = oldVal[i]; const newShip = newVal[i]; if (oldShip === newShip) continue; if (oldShip && !fleet.ships.value.includes(oldShip)) oldShip[ShipFleetKey].value = null; if (newShip) newShip[ShipFleetKey].value = fleet; } }); } //#endregion //#region src/types.ts let StrengthenType = /* @__PURE__ */ function(StrengthenType$1) { StrengthenType$1[StrengthenType$1["General"] = 0] = "General"; StrengthenType$1[StrengthenType$1["Meta"] = 1] = "Meta"; StrengthenType$1[StrengthenType$1["Blueprint"] = 2] = "Blueprint"; return StrengthenType$1; }({}); let Favor = /* @__PURE__ */ function(Favor$1) { Favor$1[Favor$1["Disappointed"] = 0] = "Disappointed"; Favor$1[Favor$1["Stranger"] = 1] = "Stranger"; Favor$1[Favor$1["Friendly"] = 2] = "Friendly"; Favor$1[Favor$1["Like"] = 3] = "Like"; Favor$1[Favor$1["Love"] = 4] = "Love"; Favor$1[Favor$1["Pledge"] = 5] = "Pledge"; Favor$1[Favor$1["PledgePlus"] = 6] = "PledgePlus"; return Favor$1; }({}); //#endregion //#region src/core/power.ts function usePower(ship) { const attrsPower = computed(() => { const attrs = createAttributes(); for (const [key] of entries(attrs)) { const baseAttr = Math.floor(ship[key].value); const equipAttr = ship.equipAttrs.value[key]; const techAttr = ship.techAttrs.value[key]; attrs[key] = baseAttr + equipAttr + techAttr; } return attrs.durability * .2 + attrs.cannon + attrs.torpedo + attrs.antiaircraft + attrs.air + attrs.reload + attrs.hit * 2 + attrs.dodge * 2 + attrs.speed + attrs.antisub; }); const equipPower = computed(() => { return ship.equips.value.reduce((res, equip) => { if (equip) { const [base, strengthen] = getEquipPower(equip.rarity); res += base + strengthen * (1 + equip.level.value); } return res; }, 0); }); const transPower = computed(() => { let res = 0; if (ship.transform) { for (let i = 0; i < 6; i++) for (const templates of ship.transform.matrix[i]) for (const { enable } of templates) if (enable.value) res += getTransPower(i); } return res; }); const power = computed(() => { return Math.floor(attrsPower.value + equipPower.value + transPower.value); }); return power; } function getEquipPower(rarity) { switch (rarity) { case 1: return [30, 5]; case 2: return [50, 8]; case 3: return [80, 10]; case 4: return [120, 12]; case 5: return [180, 15]; case 6: return [300, 20]; } } function getTransPower(index) { switch (index) { case 0: return 10; case 1: return 15; case 2: return 20; case 3: return 25; case 4: return 30; case 5: return 50; } } //#endregion //#region src/core/spweapon.ts var SPWeapon = class { data_statistics; level; constructor(id) { this.id = id; this.data_statistics = []; for (let i = id; i !== 0;) { const stat = ShareCfg.spweapon_data_statistics[i]; this.data_statistics.push(stat); if (stat.next - i > 1) break; i = stat.next; } this.level = ref(this.maxLevel); } curStat = computed(() => { return { ...this.data_statistics[0], ...this.data_statistics[this.level.value] }; }); get name() { return this.data_statistics[0].name; } get icon() { return this.data_statistics[0].icon; } get rarity() { return this.data_statistics[0].rarity; } get maxLevel() { return this.data_statistics.length - 1; } attrs = computed(() => { const res = {}; for (const i of [1, 2]) { const attrKey = `attribute_${i}`; const valueKey = `value_${i}`; const randomValueKey = `value_${i}_random`; if (attrKey in this.curStat.value) { const attr = this.curStat.value[attrKey]; const value = this.curStat.value[valueKey]; const randomValue = this.curStat.value[randomValueKey]; res[attr] = value + randomValue; } } return res; }); }; function createSPWeapon(id) { if (id % 10 !== 0 || !(id in ShareCfg.spweapon_data_statistics)) return null; return new SPWeapon(id); } //#endregion //#region src/core/ship.ts var Ship = class { breakout; maxBreakout; strengthen; transform; constructor(id, technology) { this.id = id; this.technology = technology; this.maxBreakout = 0; const baseId = id * 10 + 1; const data_breakout = baseId in ShareCfg.ship_meta_breakout ? ShareCfg.ship_meta_breakout : ShareCfg.ship_data_breakout; for (let i = baseId; i !== 0;) { this.maxBreakout++; i = data_breakout[i].breakout_id; } if (id in ShareCfg.ship_data_blueprint) { const { breakout,...strengthen } = useStrengthenBlueprint(this); this.breakout = breakout; this.strengthen = { type: StrengthenType.Blueprint, ...strengthen }; } else if (id in ShareCfg.ship_strengthen_meta) { this.breakout = ref(this.maxBreakout); this.strengthen = { type: StrengthenType.Meta, ...useStrengthenMeta(this) }; } else { this.breakout = ref(this.maxBreakout); this.strengthen = { type: StrengthenType.General, ...useStrengthenGeneral(this) }; } if (id in ShareCfg.ship_data_trans) this.transform = useTransform(this); } get curStat() { return ShareCfg.ship_data_statistics[this.curId.value]; } get curTemp() { return ShareCfg.ship_data_template[this.curId.value]; } get curSkin() { return ShareCfg.ship_skin_template[this.id * 10 + (this.transform?.isModernized.value ? 9 : 0)]; } curId = computed(() => { return this.transform?.isModernized.value && this.transform?.modernizedId.value || this.id * 10 + this.breakout.value; }); level = ref(125); favor = ref(Favor.Love); name = computed(() => { const name = this.curStat.name; if (this.transform?.isModernized.value) { const suffixes = [".改", "·改"]; return (name.endsWith(suffixes[0]) || name.endsWith(suffixes[1]) ? name.slice(0, -2) : name) + suffixes[0]; } else return name; }); armor = computed(() => { return this.curStat.armor_type; }); nationality = computed(() => { return this.curStat.nationality; }); rarity = computed(() => { return this.curStat.rarity + (this.transform?.isModernized.value ? 1 : 0); }); type = computed(() => { return this.curStat.type; }); painting = computed(() => { return this.curSkin.painting; }); star = computed(() => { return this.maxStar.value - this.maxBreakout + this.breakout.value; }); maxStar = computed(() => { return Math.max(4, this.rarity.value); }); getAttr(index, attrName) { const favorRate = 1 + (["speed", "luck"].includes(attrName) ? 0 : getFavorRate(this.favor.value)); return (this.curStat.attrs[index] + this.curStat.attrs_growth[index] * (this.level.value - 1) / 1e3 + this.strengthen.attrs.value[attrName]) * favorRate + this.transAttrs.value[attrName]; } transAttrs = computed(() => { const attrs = createAttributes(); const templates = this.transform?.matrix.flat(2) ?? []; for (const template of templates) if (template.enable.value) for (const effect of template.effect) for (const [attr, val] of entries(effect)) attrs[attr] += val; return attrs; }); equipAttrs = computed(() => { const attrs = createAttributes(); for (const equip of [...this.equips.value, this.spweapon.value]) { if (!equip) continue; for (const [attr, val] of entries(equip.attrs.value)) attrs[attr] += val; } return attrs; }); techAttrs = computed(() => { const attrs = createAttributes(); if (this.breakout.value === this.maxBreakout) for (const [key] of entries(attrs)) attrs[key] += this.technology.get(this.type.value, key); return attrs; }); commanderAttrs = computed(() => { const attrs = createAttributes(); const commanders = this.fleet.value?.commanders.value.filter(nonNullable) ?? []; const effects = commanders.flatMap((commander) => commander.abilities).filter(nonNullable).flatMap((ability) => ability.effects).filter((effect) => effect.type === 1 && (!effect.nationalities.length || effect.nationalities.includes(this.nationality.value)) && (!effect.shipTypes.length || effect.shipTypes.includes(this.type.value))); for (const effect of effects) { const key = ShareCfg.attribute_info_by_type[effect.key].name; attrs[key] += effect.value; } return attrs; }); durability = computed(() => { return this.getAttr(0, "durability"); }); cannon = computed(() => { return this.getAttr(1, "cannon"); }); torpedo = computed(() => { return this.getAttr(2, "torpedo"); }); antiaircraft = computed(() => { return this.getAttr(3, "antiaircraft"); }); air = computed(() => { return this.getAttr(4, "air"); }); reload = computed(() => { return this.getAttr(5, "reload"); }); hit = computed(() => { return this.getAttr(7, "hit"); }); dodge = computed(() => { return this.getAttr(8, "dodge"); }); speed = computed(() => { return this.getAttr(9, "speed"); }); luck = computed(() => { return this.getAttr(10, "luck"); }); antisub = computed(() => { return this.getAttr(11, "antisub"); }); oxy_max = computed(() => { return this.curStat.oxy_max; }); ammo = computed(() => { return this.curStat.ammo; }); oil = computed(() => { const levelRate = .5 + .005 * Math.min(99, this.level.value); return Math.floor(([ 8, 17, 22 ].includes(this.type.value) ? 0 : 1) + this.curTemp.oil_at_end * levelRate); }); power = usePower(this); equipSlotTypes = computed(() => { return [ this.curTemp.equip_1, this.curTemp.equip_2, this.curTemp.equip_3, this.curTemp.equip_4, this.curTemp.equip_5 ]; }); equip1 = shallowRef(null); equip2 = shallowRef(null); equip3 = shallowRef(null); equip4 = shallowRef(null); equip5 = shallowRef(null); equips = computed(() => [ this.equip1.value, this.equip2.value, this.equip3.value, this.equip4.value, this.equip5.value ]); spweapon = shallowRef(null); [ShipFleetKey] = shallowRef(null); fleet = computed(() => this[ShipFleetKey].value); }; function createShip(id, options) { if (!(id + "1" in ShareCfg.ship_data_statistics)) return null; const { equips = [], spweapon = null, technology } = options; const ship = new Ship(id, technology); equips.push(...Array.from({ length: 5 - equips.length }, () => null)); ship.equip1.value = normalizeEquip(equips[0]); ship.equip2.value = normalizeEquip(equips[1]); ship.equip3.value = normalizeEquip(equips[2]); ship.equip4.value = normalizeEquip(equips[3]); ship.equip5.value = normalizeEquip(equips[4]); ship.spweapon.value = normalizeSPWeapon(spweapon); return ship; } function normalizeEquip(equip) { return typeof equip === "number" ? createEquip(equip) : equip; } function normalizeSPWeapon(spweapon) { return typeof spweapon === "number" ? createSPWeapon(spweapon) : spweapon; } function useStrengthenBlueprint(ship) { const data_blueprint = ShareCfg.ship_data_blueprint[ship.id]; const data_strengthen = [...data_blueprint.strengthen_effect, ...data_blueprint.fate_strengthen].map((i) => ShareCfg.ship_strengthen_blueprint[i]); const blueprintMax1 = data_strengthen.slice(0, 30).reduce((res, item) => { return res + item.need_exp; }, 0) / 10; const blueprintMax2 = data_strengthen.slice(30).reduce((res, item) => { return res + item.need_exp; }, 0) / 10; const blueprint = ref(blueprintMax1 + blueprintMax2); const blueprint1 = computed({ get: () => { return Math.min(blueprint.value, blueprintMax1); }, set: (value) => { blueprint.value = value; } }); const blueprint2 = computed({ get: () => { return Math.max(0, blueprint.value - blueprintMax1); }, set: (value) => { blueprint.value = value + blueprintMax1; } }); const blueprintLevel = computed({ get: () => { let level = 0; let exp = 0; for (const item of data_strengthen) { exp += item.need_exp; if (blueprint.value >= exp / 10) level++; else break; } return level; }, set: (level) => { let exp = 0; for (let i = 0; i < level; i++) exp += data_strengthen[i].need_exp; blueprint.value = exp / 10; } }); const attrs = computed(() => { const res = createAttributes(); for (let i = 0; i < blueprintLevel.value; i++) { const item = data_strengthen[i]; for (const attr of item.effect_attr) res[attr[0]] += attr[1]; res.cannon += item.effect[0] / 100; res.torpedo += item.effect[1] / 100; res.air += item.effect[3] / 100; res.reload += item.effect[4] / 100; } return res; }); const breakout = computed({ get: () => { const lv = blueprintLevel.value; if (lv < 10) return 1; else if (lv < 20) return 2; else if (lv < 30) return 3; else return 4; }, set: (value) => { blueprintLevel.value = { 1: 0, 2: 10, 3: 20, 4: 30 }[value] ?? 0; } }); return { blueprintMax1, blueprintMax2, blueprint, blueprint1, blueprint2, blueprintLevel, attrs, breakout }; } function useStrengthenMeta(ship) { const data_strengthen = ShareCfg.ship_strengthen_meta[ship.id]; const repair_effect = data_strengthen.repair_effect.map(([per, key]) => { return { per, ...ShareCfg.ship_meta_repair_effect[key] }; }); const maxAttrs = createAttributes(); for (const attr of [ "cannon", "torpedo", "air", "reload" ]) { const repairList = data_strengthen[`repair_${attr}`]; for (const key of repairList) { const [attr$1, value] = ShareCfg.ship_meta_repair[key].effect_attr; maxAttrs[attr$1] += value; } } const adjustAttrs = ref({ ...maxAttrs }); const attrs = computed(() => { const res = createAttributes(adjustAttrs.value); let acc = 0; let total = 0; for (const [attr] of entries(res)) { acc += res[attr]; total += maxAttrs[attr]; } const rate = acc / total * 100; for (const effect of repair_effect) if (rate >= effect.per) for (const [attr, value] of effect.effect_attr) res[attr] += value; else break; return res; }); return { maxAttrs, adjustAttrs, attrs }; } function useStrengthenGeneral(ship) { const data_strengthen = ShareCfg.ship_data_strengthen[ship.id]; const maxAttrs = createAttributes({ cannon: data_strengthen.durability[0], torpedo: data_strengthen.durability[1], air: data_strengthen.durability[3], reload: data_strengthen.durability[4] }); const adjustAttrs = ref({ ...maxAttrs }); const attrs = computed(() => adjustAttrs.value); return { maxAttrs, adjustAttrs, attrs }; } function useTransform(ship) { const templates = {}; const matrix = ShareCfg.ship_data_trans[ship.id].transform_list.map((item) => { const column = [ [], [], [] ]; for (const [index, id] of item) { const template = { ...ShareCfg.transform_data_template[id], enable: ref(true), next_id: [] }; templates[id] = template; column[index - 2].push(template); } return column; }); for (const [key, template] of entries(templates)) { const stack = [[Number(key), template]]; while (stack.length) { const [id, { condition_id }] = stack.pop(); for (const prevId of condition_id) { const prev = templates[prevId]; if (prev.edit_trans.includes(id)) stack.push([id, prev]); else prev.next_id.push(id); } } } const isModernized = ref(false); const modernizedId = ref(null); for (const [, template] of entries(templates)) watch(template.enable, (value) => { if (value) { updateTemplates(template.condition_id, true); updateTemplates(template.edit_trans, false); } else if (!template.edit_trans.length) updateTemplates(template.next_id, false); else if (template.condition_id.every((id) => templates[id].enable.value)) updateTemplates(template.edit_trans, true); if (template.name === "近代化改造") isModernized.value = value; if (template.ship_id.length) { const [from, to] = template.ship_id[0]; modernizedId.value = value ? to : from; } }, { immediate: true }); function updateTemplates(ids, value) { for (const id of ids) templates[id].enable.value = value; } return { matrix, isModernized, modernizedId }; } function getFavorRate(favor) { switch (favor) { case 2: return .01; case 3: return .03; case 4: return .06; case 5: return .09; case 6: return .12; default: return 0; } } //#endregion //#region src/core/serialize/clone.ts function createClone(options) { const handlers = new Map(options.handlers); return clone; function clone(obj) { if (obj === null || obj === void 0) return obj; if (handlers.has(obj.constructor)) { const handler = handlers.get(obj.constructor); return handler(obj); } if (typeof obj !== "object") return obj; if (Array.isArray(obj)) return cloneArray(obj); return cloneObject(obj); } function cloneArray(arr) { const res = []; for (let i = 0; i < arr.length; i++) { const cur = arr[i]; res[i] = clone(cur); } return res; } function cloneObject(obj) { const res = {}; for (const key in obj) { const cur = Reflect.get(obj, key); res[key] = clone(cur); } return res; } } //#endregion //#region src/core/serialize/index.ts const registry = []; register("surface-fleet", SurfaceFleet, { paths: [ "name", "commander1", "commander2", "main1", "main2", "main3", "vanguard1", "vanguard2", "vanguard3" ], initialize(_, raw) { return createFleet("surface", raw.name); } }); register("submarine-fleet", SubmarineFleet, { paths: [ "name", "commander1", "commander2", "submarine1", "submarine2", "submarine3" ], initialize(_, raw) { return createFleet("submarine", raw.name); } }); register("ship", Ship, { paths: [ "id", "level", "favor", "breakout", "strengthen.adjustAttrs", "strengthen.blueprint", "transform.matrix[][][].enable", "equip1", "equip2", "equip3", "equip4", "equip5", "spweapon" ], initialize(options, raw) { return createShip(raw.id, { technology: options.technology }); } }); register("equip", Equip, { paths: ["id", "level"], initialize(_, raw) { return createEquip(raw.id); } }); register("spweapon", SPWeapon, { paths: ["id", "level"], initialize(_, raw) { return createSPWeapon(raw.id); } }); register("commander", Commander, { paths: [ "id", "level", "name", "abilities[]" ], initialize(_, raw) { return createCommander(raw.id); } }); register("commander-ability", CommanderAbility, { paths: ["id"], initialize(_, raw) { return createCommanderAbility(raw.id); } }); function register(name, structure, options) { const { paths, initialize } = options; const parsedPaths = paths.map((path) => path.split(/\.|(?=\[\])/)); function serialize(ctx, source) { const normalizedPaths = parsedPaths.flatMap((path) => [...normalizePath(source, path)]); const raw = {}; const key = ctx.track(name, source, raw); for (const path of normalizedPaths) { let srcObj = source; let rawObj = raw; for (let i = 0; i < path.length; i++) { const key$1 = path[i]; const nextKey = path[i + 1]; srcObj = srcObj[key$1]; if (nextKey !== void 0) rawObj = rawObj[key$1] ??= {}; else if (srcObj === void 0) break; else { const val = toRaw(toValue(srcObj)); rawObj[key$1] = ctx.resolve(val); } } } return key; } function deserialize(options$1, ctx, raw, id) { const source = initialize(options$1, raw); const normalizedPaths = parsedPaths.flatMap((path) => [...normalizePath(raw, path)]); ctx.track(id, name, source); for (const path of normalizedPaths) { let srcObj = source; let rawObj = raw; for (let i = 0; i < path.length; i++) { const key = path[i]; const nextKey = path[i + 1]; rawObj = rawObj[key]; if (nextKey === void 0) { const val = ctx.resolve(rawObj); if (isRef(srcObj[key])) srcObj[key].value = val; else srcObj[key] = val; } srcObj = srcObj[key]; } } return source; } registry.push({ name, structure, serialize, deserialize }); return { serialize, deserialize }; } function createSerializer(options) { const internalKeys = new WeakMap(); const mapping = options.mapping ?? {}; let sources = {}; let curId = 0; function serialize(source) { const serialized = new WeakSet(); const ctx = { resolve(source$1) { if (source$1 && serialized.has(source$1)) return internalKeys.get(source$1); for (const reg of registry) if (source$1 instanceof reg.structure) return reg.serialize(ctx, source$1); return source$1; }, track(name, source$1, raw) { serialized.add(source$1); let id; let key; if (!internalKeys.has(source$1)) { id = curId++; key = resolveInternalKey(id, name); internalKeys.set(source$1, key); } else { key = internalKeys.get(source$1); id = parseInternalKey(key).id; } mapping[id] = raw; return key; } }; const clone = createClone({ handlers: registry.map((reg) => [reg.structure, (obj) => reg.serialize(ctx, obj)]) }); curId = Number(Object.keys(mapping).at(-1) ?? -1) + 1; return clone(source); } function deserialize(raw) { const ctx = { resolve(raw$1) { if (typeof raw$1 !== "string") return raw$1; try { const { name, id } = parseInternalKey(raw$1); if (id in sources) return sources[id]; const obj = mapping[id]; const { deserialize: deserialize$1 } = registry.find((r) => r.name === name); return deserialize$1(options, ctx, obj, id); } catch { return raw$1; } }, track(id, name, source) { const key = resolveInternalKey(id, name); internalKeys.set(source, key); sources[id] = source; return source; } }; const clone = createClone({ handlers: [[String, (raw$1) => ctx.resolve(raw$1)]] }); return clone(raw); } function cleanup(raw) { sources = {}; const ids = new Set(Object.keys(mapping).map(Number)); for (const id of traverse(raw)) ids.delete(id); for (const id of ids) delete mapping[id]; function* traverse(raw$1) { if (typeof raw$1 === "string") try { const { id } = parseInternalKey(raw$1); yield id; yield* traverse(mapping[id]); } catch {} else if (Array.isArray(raw$1)) for (const item of raw$1) yield* traverse(item); else if (typeof raw$1 === "object" && raw$1 !== null) for (const value of Object.values(raw$1)) yield* traverse(value); } } return { mapping, serialize, deserialize, cleanup }; } function* normalizePath(obj, path) { const key = path[0]; if (obj === void 0 || !path.length) { if (key !== "[]") yield []; } else if (key === "[]") for (const [key$1, value] of Object.entries(obj)) for (const res of normalizePath(value, path.slice(1))) yield [key$1, ...res]; else for (const res of normalizePath(obj[key], path.slice(1))) yield [key, ...res]; } function resolveInternalKey(id, name) { return `id(${name}):${id}`; } function parseInternalKey(key) { const match = key.match(/^id\((?<name>[-\w]+)\):(?<id>\d+)$/); if (!match) throw 0; const { name, id } = match.groups; return { name, id: Number(id) }; } //#endregion //#region src/core/technology.ts function useTechnology() { const attrs = ref(createTechnologyAttributes()); function get(type, attr) { if (attr === "speed" || attr === "luck") return 0; return attrs.value[type]?.[attr] ?? 0; } return { attrs, get }; } function createTechnologyAttributes() { return { ...structuredClone(ShareCfg.fleet_tech_attributes), get 20() { return this[1]; }, get 21() { return this[1]; }, get 23() { return this[22]; }, get 24() { return this[22]; } }; } //#endregion export { Commander, CommanderAbility, Equip, Favor, Fleet, SPWeapon, Ship, StrengthenType, SubmarineFleet, SurfaceFleet, createAttributes, createCommander, createCommanderAbility, createEquip, createFleet, createSPWeapon, createSerializer, createShip, createTechnologyAttributes, useTechnology };