/// <summary>Persists all player data to the database. Thread safe. Call in a background thread if the save isn't needed immediately.</summary> /// <returns>True if successful, else false.</returns> internal override void Save() { lock (_saveLock) { using (EmuDataContext dbCtx = new EmuDataContext()) { DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<Character>(c => c.InventoryItems); dbCtx.LoadOptions = dlo; //dbCtx.Log = new Log4NetWriter(typeof(ZonePlayer)); Character toon = dbCtx.Characters.SingleOrDefault(c => c.Name == this.Name); toon.X = this.X; toon.Y = this.Y; toon.Z = this.Z; toon.Heading = this.Heading; toon.ZoneID = this.ZoneId; toon.LastSeenDate = DateTime.Now; toon.Platinum = this.Platinum; toon.Gold = this.Gold; toon.Silver = this.Silver; toon.Copper = this.Copper; toon.XP = _pp.XP; // Going direct to the pp eliminates a cast toon.CharLevel = this.Level; toon.HP = this.HP; // Convert skill values from the uint[] to a byte[] byte[] skills = new byte[toon.Skills.Length]; for (int i = 0; i < _pp.Skills.Length; i++) skills[i] = (byte)_pp.Skills[i]; toon.Skills = Encoding.ASCII.GetString(skills); // Clear and then re-add the inventory, spellbook, mem'd spells (got a better idea?) dbCtx.InventoryItems.DeleteAllOnSubmit(toon.InventoryItems); // TODO: this gens many DELETE statements... could be improved dbCtx.MemorizedSpells.DeleteAllOnSubmit(toon.MemorizedSpells); dbCtx.ScribedSpells.DeleteAllOnSubmit(toon.ScribedSpells); dbCtx.SubmitChanges(); foreach (InventoryItem invItem in this.InvMgr.AllItems()) { //_log.DebugFormat("During save found item {0} in slot {1}", invItem.Item.Name, invItem.SlotID); toon.InventoryItems.Add(invItem.ShallowCopy()); } // Save spellbook for (short i = 0; i < this.PlayerProfile.SpellBook.Length; i++) { if (this.PlayerProfile.SpellBook[i] != Spell.BLANK_SPELL) // Don't save blank spells toon.ScribedSpells.Add(new ScribedSpell() { SlotID = i, SpellID = (ushort)this.PlayerProfile.SpellBook[i] }); } // Save memorized spells for (byte i = 0; i < this.PlayerProfile.MemSpells.Length; i++) { if (this.PlayerProfile.MemSpells[i] != Spell.BLANK_SPELL) // Don't save blank spells toon.MemorizedSpells.Add(new MemorizedSpell() { SlotID = i, SpellID = (ushort)this.PlayerProfile.MemSpells[i] }); } dbCtx.SubmitChanges(); // TODO: save cursor items } } _log.DebugFormat("{0} Saved.", this.Name); }
internal static bool Delete(string charName) { using (EmuDataContext dbCtx = new EmuDataContext()) { Data.Character charToDel = dbCtx.Characters.SingleOrDefault(c => c.Name == charName); if (charToDel != null) { dbCtx.Characters.DeleteOnSubmit(charToDel); dbCtx.SubmitChanges(); return true; } } return false; }
internal static bool ReserveName(int acctId, string name) { using (EmuDataContext dbCtx = new EmuDataContext()) { if (dbCtx.Characters.Count(c => c.Name == name) > 0) return false; Character toon = new Character(); toon.AccountID = acctId; toon.Name = name; toon.CreatedDate = DateTime.Now; dbCtx.Characters.InsertOnSubmit(toon); dbCtx.SubmitChanges(); } return true; }
internal static void Create(string charName, CharacterCreate charCreateStruct) { // TODO: old emu does some in depth validation of race/class combinations and ability scores. Will add later if necessary using (EmuDataContext dbCtx = new EmuDataContext()) { DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<StartingItem>(si => si.Item); dbCtx.LoadOptions = dlo; Character toon = dbCtx.Characters.SingleOrDefault(c => c.Name == charName); toon.Race = (short)charCreateStruct.Race; toon.Class = (byte)charCreateStruct.Class; toon.Gender = (byte)charCreateStruct.Gender; toon.Deity = (int)charCreateStruct.Deity; toon.STR = (short)charCreateStruct.STR; toon.STA = (short)charCreateStruct.STA; toon.AGI = (short)charCreateStruct.AGI; toon.DEX = (short)charCreateStruct.DEX; toon.WIS = (short)charCreateStruct.WIS; toon.INT = (short)charCreateStruct.INT; toon.CHA = (short)charCreateStruct.CHA; toon.Face = (byte)charCreateStruct.Face; toon.EyeColor1 = (byte)charCreateStruct.EyeColor1; toon.EyeColor2 = (byte)charCreateStruct.EyeColor2; toon.HairStyle = (byte)charCreateStruct.HairStyle; toon.HairColor = (byte)charCreateStruct.HairColor; toon.Beard = (byte)charCreateStruct.Beard; toon.BeardColor = (byte)charCreateStruct.BeardColor; toon.LastSeenDate = DateTime.Now; toon.CharLevel = 1; toon.PracticePoints = 5; toon.HP = 1000; // just here for dev, later will be set elsewhere toon.HungerLevel = 6000; toon.ThirstLevel = 6000; toon.Platinum = (uint)EQEmulator.Servers.WorldServer.ServerConfig.StartingPlat; toon.Gold = (uint)EQEmulator.Servers.WorldServer.ServerConfig.StartingGold; SetRacialStartingAbilities(ref toon); // Sets languages and skills that are racially determined SetClassStartingAbilities(ref toon); // Sets skills determined by class // Get the character's start zone StartZone startZone = dbCtx.StartZones.SingleOrDefault(sz => sz.PlayerChoice == charCreateStruct.StartZone && sz.PlayerClass == charCreateStruct.Class && sz.PlayerDeity == charCreateStruct.Deity && sz.PlayerRace == charCreateStruct.Race); CharacterBind cb = new CharacterBind(); toon.X = toon.Y = toon.Z = 0.0F; cb.X = cb.Y = cb.Z = 0.0F; toon.Heading = 0.0F; if (startZone != null) // TODO: should heading for zone and bind be set to some default setting? { // Found a start zone in the db... load up the bind info from that toon.ZoneID = startZone.ZoneID; toon.ZoneName = startZone.Zone.ShortName; toon.X = startZone.X; toon.Y = startZone.Y; toon.Z = startZone.Z; if (startZone.BindZoneID != null) { cb.ZoneID = startZone.BindZoneID.Value; cb.X = startZone.BindX.Value; cb.Y = startZone.BindY.Value; cb.Z = startZone.BindZ.Value; } else cb.ZoneID = startZone.ZoneID; } else SetDefaultStartZone(charCreateStruct.StartZone, ref toon, ref cb); Zone zone = null; // Load safe points for start zone coords if necessary if (toon.X == 0.0F && toon.Y == 0.0F && toon.Z == 0.0F) { zone = dbCtx.Zones.SingleOrDefault(z => z.ZoneID == toon.ZoneID); toon.X = zone.SafeX; toon.Y = zone.SafeY; toon.Z = zone.SafeZ; } // Load safe points for start bind coords if necessary if (cb.X == 0.0F && cb.Y == 0.0F && cb.Z == 0.0F) { zone = dbCtx.Zones.SingleOrDefault(z => z.ZoneID == cb.ZoneID); if (zone != null) { cb.X = zone.SafeX; cb.Y = zone.SafeY; cb.Z = zone.SafeZ; } else _log.ErrorFormat("Unable to load safe points for bind zone {0}", cb.ZoneID); } cb.Heading = toon.Heading.Value; toon.CharacterBinds.Add(cb); // Get starting items var startingItems = from si in dbCtx.StartingItems where (si.Race == toon.Race.Value || si.Race == 0) && (si.Class == toon.Class.Value || si.Class == 0) && (si.DeityID == (toon.Deity ?? 0) || si.DeityID == 0) && (si.ZoneID == toon.ZoneID.Value || si.ZoneID == 0) select si; int siSlotId = 22; // for initial items with unspecified slots, just dump them to the personal inv slots foreach (StartingItem si in startingItems) { InventoryItem ii = new InventoryItem { ItemID = si.ItemID, Charges = si.ItemCharges, Color = si.Item.Color ?? 0, SlotID = si.Slot }; if (ii.SlotID < 0) { // for unspecified inventory slots, find an open slot ii.SlotID = siSlotId; siSlotId++; } toon.InventoryItems.Add(ii); } dbCtx.SubmitChanges(); } }