You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

登出重登后Hero角色新增武器被覆盖,求技术排查方案

问题:角色重登后战利品武器丢失,默认武器覆盖问题

现象

玩家登出后重新登入角色,游戏过程中添加的战利品武器会被Hero类默认初始化的武器覆盖。战利品系统能成功添加武器,登出前可正常使用,但重登后消失;生命值、经验值等属性修改后可正常保存,武器虽已关联UserId存入数据库,但无法显示在Hero的武器列表中,形成无法访问的孤立数据。

关键代码片段

Hero类中WeaponSack的初始化

public virtual User User { get; set; }

public override List<Weapon> WeaponSack { get; set; } = new() { Weapon.ElectricityWand, Weapon.ElementalStaff };

战利品添加代码

{
    var CurrentCharacter = SelectCharacter.CurrentHero;
    // 扣除玩家70%生命值
    var damage = CurrentCharacter.Health - (CurrentCharacter.Health * 0.70);
    context.User.Update(user);
    CurrentCharacter.LoseHealth(CurrentCharacter, CurrentCharacter.Health, (int)damage);
    context.SaveChanges();
    Console.WriteLine($"You have lost {damage} health.");
    Console.WriteLine($"You have {CurrentCharacter.Health} health left.");
    Console.WriteLine("Press any key to collect your loot!");
    Console.ReadKey();
    // 生成随机武器
    Random random = new Random();
    var weapon = new Weapon();
    var weaponName = new List<string> { "Sword", "Axe", "Mace", "Dagger", "Bow", "Staff", "Spear", "Wand", "Hammer", "Sickle" };
    var weaponType = new List<string> { "Heavy", "Defensive", "Offensive", "Light", "Damaged", "Reinforced", "Magic", "Wooden", "Metallic", "Colorful" };
    var weaponLevel = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    var weaponDamage = new List<int> { 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 };
    var weaponRarity = new List<string> { "Common", "Uncommon", "Rare", "Epic", "Legendary" };
    var weaponRarityChance = new List<int> { 70, 15, 10, 4, 1 };
    var weaponRarityChanceTotal = weaponRarityChance.Sum();
    var weaponRarityChanceRandom = random.Next(1, weaponRarityChanceTotal + 1);
    var weaponRarityChanceIndex = 0;
    for (var i = 0; i < weaponRarityChance.Count; i++)
    {
        weaponRarityChanceIndex += weaponRarityChance[i];
        if (weaponRarityChanceRandom <= weaponRarityChanceIndex)
        {
            weapon.Rarity = weaponRarity[i];
            break;
        }
    }
    weapon.Name = weaponName[random.Next(0, weaponName.Count)];
    weapon.Degradation = random.Next(1, 15);
    weapon.Type = weaponType[random.Next(0, weaponType.Count)];
    weapon.Damage = weaponDamage[random.Next(0, weaponDamage.Count)];
    weapon.Level = weaponLevel[random.Next(0, weaponLevel.Count)];
    context.Hero.Update(CurrentCharacter);
    CurrentCharacter.WeaponSack.Add(weapon);
    context.SaveChanges();
    Console.WriteLine($"You have found a [level {weapon.Level}] [{weapon.Rarity}] ({weapon.Type} {weapon.Name})! It has {weapon.Degradation} uses left.");
    Console.WriteLine("Press any key to continue your adventure!");
    Console.ReadKey();
    Adventure.AdventureStart(user, hero);
    break;
}

Weapon类完整代码

namespace HeroModels
{
    public class Weapon
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Damage { get; set; }
        public int Level { get; set; }
        public string Rarity { get; set; }
        public string Type { get; set; }
        public int Degradation { get; set; }

        public Weapon(string name, int damage, int level, string rarity, string type, int degradation)
        {
            Name = name;
            Damage = damage;
            Level = level;
            Rarity = rarity;
            Type = type;
            Degradation = 10;
        }

        public Weapon()
        {
        }

        /* 魔法武器 */
        public static Weapon ElectricityWand =
            new(name: "Electricity Wand", damage: 5, level: 1, rarity: "Common", type: "Magic", degradation: 10);

        public static Weapon ElementalStaff =
            new(name: "Elemental Staff", damage: 30, level: 5, rarity: "Common", type: "Magic", degradation: 10);

        public int CalculateDamage(Weapon weapon)
        {
            Random random = new();
            var damage = random.Next(weapon.Damage);
            return damage;
        }
    }
}

Hero类完整代码

using HeroModels;
using SolutionItems;
using System.ComponentModel.DataAnnotations;

namespace UserRegistration
{
    public class Hero : IHero
    {
        public Hero()
        {
        }
        [Key]
        public new int Id { get; set; }
        public override string? Name { get; set; } = "Harry Potter";
        public override string Class { get; set; } = "Mage";

        public override int Health { get; set; } = 100;

        public override int Damage { get; set; } = 10;

        public override int Armor
        { get; set; } = 5;

        public override int Level
        { get; set; } = 1;

        public override int Experience
        { get; set; } = 0;

        public override int Gold
        { get; set; } = 0;

        public override int Strength
        { get; set; } = 10;

        public virtual User User { get; set; }

        public virtual List<Weapon> WeaponSack { get; set; } = new() { Weapon.ElectricityWand, Weapon.ElementalStaff };
        public override List<Food> FoodSack { get; set; } = new() { Food.trout, Food.salmon };

        public override string Attack(IHero hero)
        {
            return "";
        }

        public override int GainExperience(IHero hero, int experience)
        {
            return hero.Experience += experience;
        }

        public override int GainGold(IHero hero, int gold)
        {
            return hero.Gold += gold;
        }

        public override string GainHealth(IHero hero, int health)
        {
            hero.Health += health;
            if (hero.Health >= 100)
            {
                hero.Health = 100;
            }
            return $"Your health is now at {hero.Health}!";
        }
        public override string LoseHealth(IHero hero, int health, int damage)
        {
            hero.Health -= damage;
            if (hero.Health <= 0)
            {
                Environment.Exit(1);
                return "You have died.";
            }
            return $"You have taken {damage} damage. Your health is now at {hero.Health}!";
        }

        public override string LevelUp(IHero hero)
        {
            hero.Level += 1;
            var level = hero.Level;
            return $"Congratulations! You are now level {Level}";
        }
    }
}

角色登录加载代码

private DbContext LogIn()
{
    Console.WriteLine("Please enter your username");
    string username = Console.ReadLine();
    Console.WriteLine("Please enter your password");
    string password = Console.ReadLine();
    using var context = new HeroesDBContext(_optionsBuilder.Options);
    var usercompare = new HeroesDBContext().User.Where(u => u.Username == username && u.Password == password);

    if (!usercompare.Any())
    {
        Console.WriteLine("User not found");
        WelcomeScreen();
    }
    CurrentHero = context.Hero.FirstOrDefault(h => h.User.Username == username);
    CurrentUser = context.User.Where(u => u.Username == username && u.Password == password).FirstOrDefault();
    context.SaveChanges();
    Adventure.AdventureStart(CurrentUser, CurrentHero);

    return context;
}

疑问

是否是Hero类中WeaponSack的重写初始化方式导致的问题?尝试关联加载用户绑定的武器但未成功,求解决方案。


解决方案

1. 修复WeaponSack的初始化逻辑

问题核心是字段初始化器会在EF Core从数据库加载实体前执行,每次加载Hero时都会创建包含默认武器的新列表,覆盖数据库中保存的武器数据。修改Hero类,仅在创建新角色时初始化默认武器:

public virtual List<Weapon> WeaponSack { get; set; }

public Hero()
{
    // 仅当是新创建的Hero(主键Id为0,根据你的主键策略调整)时初始化默认武器
    if (Id == 0)
    {
        WeaponSack = new List<Weapon> { Weapon.ElectricityWand, Weapon.ElementalStaff };
    }
}

2. 登录时显式加载关联武器

登录代码中没有加载Hero的WeaponSack关联数据,导致武器列表为空或被默认值覆盖。修改加载逻辑,使用Include显式加载关联:

CurrentHero = context.Hero
    .Include(h => h.WeaponSack)
    .FirstOrDefault(h => h.User.Username == username);

3. 确认EF Core关系配置

确保DbContext中正确配置Hero与Weapon的一对多关系:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Hero>()
        .HasMany(h => h.WeaponSack)
        .WithOne() // 如果Weapon没有反向导航属性,使用WithOne()
        .OnDelete(DeleteBehavior.Cascade); // 根据业务需求设置删除行为
}

4. 优化战利品添加代码

不需要调用context.Hero.Update(CurrentCharacter),因为CurrentCharacter已是上下文跟踪的实体,直接添加武器后保存即可:

// 移除该行:context.Hero.Update(CurrentCharacter);
CurrentCharacter.WeaponSack.Add(weapon);
context.SaveChanges();

内容的提问来源于stack exchange,提问作者The_Rico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 09:10:53