mirror of
https://github.com/motajs/template.git
synced 2026-10-17 03:10:17 +08:00
fix(07-09): keep hero attribute instance stable and clear generic variance
- HeroAttribute.loadState replaces its private base object; the HeroAttribute wrapper identity is preserved so equipment/combat references stay valid across load (#06-17-1/#06-17-2). - Clone the incoming base attribute in the constructor so the shared HERO_DEFAULT_ATTRIBUTE is no longer mutated across CoreState instances. - Use any for the hero position in combat handler/aura/enemy-view generics to clear the 45 new type errors introduced by HeroAttribute implementing ISaveableContent.
This commit is contained in:
parent
9a2f581c80
commit
b2626bd438
@ -66,7 +66,9 @@ export class HeroAttribute<THero> implements IHeroAttribute<THero> {
|
||||
/**
|
||||
* @param attribute 当前勇士的基础属性
|
||||
*/
|
||||
constructor(private readonly attribute: THero) {
|
||||
constructor(private attribute: THero) {
|
||||
// 克隆入参,避免调用方传入的共享基础属性对象被本实例改写
|
||||
this.attribute = structuredClone(attribute);
|
||||
this.finalAttribute = structuredClone(attribute);
|
||||
}
|
||||
|
||||
@ -337,17 +339,8 @@ export class HeroAttribute<THero> implements IHeroAttribute<THero> {
|
||||
state: IHeroAttributeSave<THero>,
|
||||
compression: SaveCompression
|
||||
): void {
|
||||
// 原地修改基础属性以保持同引用,使装备与战斗侧持有的属性引用跨读档始终有效
|
||||
for (const key in this.attribute) {
|
||||
if (Object.prototype.hasOwnProperty.call(state.values, key)) {
|
||||
continue;
|
||||
}
|
||||
delete this.attribute[key as keyof THero];
|
||||
}
|
||||
const values = structuredClone(state.values);
|
||||
for (const key in values) {
|
||||
this.attribute[key as keyof THero] = values[key as keyof THero];
|
||||
}
|
||||
// attribute 是内部对象,不必保证同引用,只要内部不会出现引用问题即可
|
||||
this.attribute = structuredClone(state.values);
|
||||
|
||||
this.modifier.clear();
|
||||
this.modifierName.clear();
|
||||
@ -363,7 +356,7 @@ export class HeroAttribute<THero> implements IHeroAttribute<THero> {
|
||||
}
|
||||
|
||||
// 逐键重算 final,清掉被移除修饰器留下的陈旧值
|
||||
for (const key in this.attribute) {
|
||||
for (const key of Object.keys(this.attribute as object)) {
|
||||
this.recalculateAttribute(key as keyof THero);
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ export class CommonAura implements IEnemyAuraView<
|
||||
}
|
||||
|
||||
apply(
|
||||
handler: IEnemyHandler<IEnemyAttr, unknown>,
|
||||
handler: IEnemyHandler<IEnemyAttr, any>,
|
||||
baseEnemy: IReadonlyEnemy<IEnemyAttr>
|
||||
): void {
|
||||
const { enemy } = handler;
|
||||
|
||||
@ -7,7 +7,7 @@ export class EnemyView<TAttr> implements IEnemyView<TAttr> {
|
||||
|
||||
constructor(
|
||||
readonly baseEnemy: IEnemy<TAttr>,
|
||||
readonly context: IEnemyContext<TAttr, unknown>
|
||||
readonly context: IEnemyContext<TAttr, any>
|
||||
) {
|
||||
this.computedEnemy = baseEnemy.clone();
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
} from '@motajs/common';
|
||||
import { type IEnemy, type IStateBase } from '@user/data-base';
|
||||
import {
|
||||
IMapDamage,
|
||||
type IEnemyContext,
|
||||
type IEnemyView,
|
||||
type IMapDamageConverter,
|
||||
@ -280,7 +281,7 @@ class FakeTypedView implements IMapDamageView<number> {
|
||||
|
||||
interface MapDamageFixture {
|
||||
/** 被测地图伤害对象 */
|
||||
damage: InstanceType<TestModules['MapDamage']>;
|
||||
damage: IMapDamage<TestEnemyAttr, TestHeroAttr>;
|
||||
/** 怪物上下文假对象 */
|
||||
context: IEnemyContext<TestEnemyAttr, TestHeroAttr>;
|
||||
/** 测试转换器 */
|
||||
|
||||
@ -42,7 +42,7 @@ export interface IReadonlyEnemyHandler<
|
||||
|
||||
export interface IEnemyView<TEnemy> {
|
||||
/** 怪物视图所属的上下文 */
|
||||
readonly context: IEnemyContext<TEnemy, unknown>;
|
||||
readonly context: IEnemyContext<TEnemy, any>;
|
||||
|
||||
/**
|
||||
* 重置此怪物视图的状态,将计算后怪物对象恢复至初始状态
|
||||
@ -80,13 +80,13 @@ export interface IEnemySpecialModifier<TEnemy> {
|
||||
* 获取要添加到指定怪物身上的特殊属性
|
||||
* @param handler 信息对象
|
||||
*/
|
||||
add(handler: IReadonlyEnemyHandler<TEnemy, unknown>): ISpecial<any>[];
|
||||
add(handler: IReadonlyEnemyHandler<TEnemy, any>): ISpecial<any>[];
|
||||
|
||||
/**
|
||||
* 获取制定怪物身上要删除的特殊属性
|
||||
* @param handler 信息对象
|
||||
*/
|
||||
delete(handler: IReadonlyEnemyHandler<TEnemy, unknown>): ISpecial<any>[];
|
||||
delete(handler: IReadonlyEnemyHandler<TEnemy, any>): ISpecial<any>[];
|
||||
|
||||
/**
|
||||
* 修改一个怪物的特殊属性,如果真正进行了修改则返回 true,否则返回 false
|
||||
@ -94,7 +94,7 @@ export interface IEnemySpecialModifier<TEnemy> {
|
||||
* @param special 要修改的怪物特殊属性
|
||||
*/
|
||||
modify(
|
||||
handler: IEnemyHandler<TEnemy, unknown>,
|
||||
handler: IEnemyHandler<TEnemy, any>,
|
||||
special: ISpecial<any>
|
||||
): boolean;
|
||||
}
|
||||
@ -121,7 +121,7 @@ export interface IAuraView<TEnemy, TRange = any> {
|
||||
* @param baseEnemy 原始怪物对象,即未进行任何修改的怪物对象
|
||||
*/
|
||||
apply(
|
||||
handler: IEnemyHandler<TEnemy, unknown>,
|
||||
handler: IEnemyHandler<TEnemy, any>,
|
||||
baseEnemy: IReadonlyEnemy<TEnemy>
|
||||
): void;
|
||||
|
||||
@ -131,7 +131,7 @@ export interface IAuraView<TEnemy, TRange = any> {
|
||||
* @param baseEnemy 原始怪物对象,即未进行任何修改的怪物对象
|
||||
*/
|
||||
applySpecial(
|
||||
handler: IEnemyHandler<TEnemy, unknown>,
|
||||
handler: IEnemyHandler<TEnemy, any>,
|
||||
baseEnemy: IReadonlyEnemy<TEnemy>
|
||||
): IEnemySpecialModifier<TEnemy> | null;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user