登出重登后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
相关产品推荐
相关产品推荐

