//[TestMethod()] public void Command_Should_Parse_Correctly() { // ARRANGE Character toon = null; InventoryItem invItem = new InventoryItem(); // Get the client's character info string charName = "Badass"; DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<Character>(c => c.Account); dlo.LoadWith<Character>(c => c.Zone); dlo.LoadWith<Character>(c => c.InventoryItems); dlo.LoadWith<InventoryItem>(ii => ii.Item); using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; dbCtx.LoadOptions = dlo; toon = dbCtx.Characters.SingleOrDefault(c => c.Name == charName); } ZonePlayer zp = new ZonePlayer(1, toon, 1, new Client(new System.Net.IPEndPoint(0x2414188f, 123))); // ACT //zp.MsgMgr.ReceiveChannelMessage("someTarget", "!damage /amount:200 /type:3", 8, 0, 100); zp.MsgMgr.ReceiveChannelMessage("someTarget", "!damage", 8, 0, 100); // ASSERT }
internal void DispatchServerCommand(ZonePlayer zp, ServerCommand cmd, Dictionary<string, string> args) { switch (cmd) { case ServerCommand.Zone: Zone zone; using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; zone = dbCtx.Zones.SingleOrDefault(z => z.ShortName == args["name"]); } if (zone != null) MovePlayer(zp, zone.ZoneID, 0u, zone.SafeX, zone.SafeY, zone.SafeZ, 0.0f, ZoneMode.ZoneToSafeCoords); else zp.MsgMgr.SendSpecialMessage(MessageType.Default, "Unable to locate zone " + args["name"]); break; case ServerCommand.GoTo: break; default: break; } }
internal override void ServerStarted() { // Connect to World (really just setting up proxy) _worldEA = new EndpointAddress("net.tcp://localhost:8000/WorldService"); // TODO: change to pick up an endpoint in the config file _worldSvcClientChannel = new ChannelFactory<IWorldService>(new NetTcpBinding(), _worldEA); //_worldSvcClient = new WorldService.WorldServiceClient(new NetTcpBinding(), worldEA); using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; _worldServer = dbCtx.WorldServers.Single(p => p.WorldConfigID == 1); } base.ServerStarted(); }
private void ProcessApplicationPacket(EQRawApplicationPacket packet, Client client) { switch (packet.OpCode) { case AppOpCode.None: _log.Error("Application OpCode found not set during packet processing... please fix."); break; case AppOpCode.SessionReady: //_log.Debug("Received SessionReady OPCode"); // Send a chat message - why? I have no idea EQRawApplicationPacket chatPacket = new EQRawApplicationPacket(AppOpCode.ChatMessage, packet.ClientIPE, CHAT_MSG); lock (client.syncRoot) client.SendApplicationPacket(chatPacket); break; case AppOpCode.Login: //_log.Debug("Received Login OPCode"); // Authenticate - either with IPAddress or netbios name (if local) string hostName = null; if (Utility.IsIpInNetwork(IPAddress.Parse(_worldServer.IPAddress), client.IPEndPoint.Address, IPAddress.Parse("255.255.255.0"))) hostName = Dns.GetHostEntry(client.IPEndPoint.Address).HostName; else hostName = client.IPEndPoint.Address.ToString(); LoginAccount logAcct = null; using (EmuDataContext dbCtx = new EmuDataContext()) { logAcct = dbCtx.LoginAccounts.SingleOrDefault(la => la.IPAddress == hostName); } if (logAcct == null) { _log.InfoFormat("Client ({0}) attempted login but no matching Login Account was found.", hostName); client.Close(); return; } _log.InfoFormat("Client ({0}) login successful.", hostName); // TODO: set last login date? // Send a login accepted EQRawApplicationPacket laPacket = new EQRawApplicationPacket(AppOpCode.LoginAccepted, packet.ClientIPE, LOGIN_ACCEPTED_MSG); lock (client.syncRoot) client.SendApplicationPacket(laPacket); break; case AppOpCode.ServerListRequest: //_log.Debug("Received ServerListRequest OPCode"); SendServerList(client); break; case AppOpCode.PlayEverquestRequest: //_log.Debug("Received PlayEverquestRequest OPCode"); // TODO: check for locked and admin level // TODO: check for max players and admin level SendPlayResponse(client); break; case AppOpCode.EnterChat: case AppOpCode.ChatMessage: case AppOpCode.Poll: default: _log.Warn("Received Unexpected Application OPCode: " + packet.OpCode); break; } }
//[TestMethod()] public void Weapon_Should_Equip_Correctly() { // ARRANGE Character toon = null; InventoryItem invItem = new InventoryItem(); Item item = null; // Get the client's character info string charName = "Badass"; DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<Character>(c => c.Account); dlo.LoadWith<Character>(c => c.Zone); dlo.LoadWith<Character>(c => c.InventoryItems); dlo.LoadWith<InventoryItem>(ii => ii.Item); using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; dbCtx.LoadOptions = dlo; toon = dbCtx.Characters.SingleOrDefault(c => c.Name == charName); } ZonePlayer zp = new ZonePlayer(1, toon, 1, new Client(new System.Net.IPEndPoint(0x2414188f, 123))); // Get the inventory item we're giving to the char using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; item = dbCtx.Items.SingleOrDefault(i => i.ItemID == 5023); } invItem.Item = item; // ACT zp.AutoGiveItem(ref invItem); // ASSERT }
/// <summary>Processes the (re)spawning of entities in the zone. Iterates the spawns for this zone and then adds a corresponding /// NPC to the mob list if various spawn conditions are met.</summary> private void SpawnTimerCallback(object state) { NpcMob npcMob = null; using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; List<SkillCap> skillCaps = dbCtx.SkillCaps.OrderBy(sc => sc.SkillID).ThenBy(sc => sc.Class).ThenBy(sc => sc.Level).ToList(); foreach (Internals.Data.Spawn s in this.Zone.Spawns) { // TODO: Handle timeleft on spawn entity (may be able to wait until persistant zone state is in) // TODO: Process spawn conditions if (!s.ReadyForRespawn()) continue; try { Npc npc = s.SpawnGroup.PickNPC(); // Get an Npc if (npc != null) { npcMob = new NpcMob(GetNewEntityId(), npc, s.PathGrid, s.X, s.Y, s.Z, s.Heading); // Clean up the npc's name and make it unique (def. before we add to list) npcMob.Name = npcMob.Name.RemoveDigits(); npcMob.Name = GetUniqueMobName(npcMob.Name); var npcSkillCaps = skillCaps.Where(sc => sc.Class == npcMob.Class && sc.Level == npcMob.Level); foreach (SkillCap cap in npcSkillCaps) npcMob.SetSkillLevel((Skill)cap.SkillID, cap.Level); //_log.DebugFormat("Trying to add npc with entity id of {0}", npcMob.ID); AddNpc(npcMob, true, false); // TODO: add to npc limit list s.LastSpawned = DateTime.Now; // TODO: set roambox? npcMob.LoadGrid(this.Zone.ZoneID, dbCtx); } else { s.LastSpawned = DateTime.MaxValue; // better than tracking a separate list of deletes and delete routine? _log.DebugFormat("Spawn {0} removed due to lack of NPCs, spawn groups or cumulative spawn chance of zero.", s.SpawnID); } } catch (Exception ex) { _log.Error("Error in SpawnTimerCallback", ex); } } } }
public void Item_Should_Stack_Correctly_In_A_Container() { // ARRANGE Character toon = null; InventoryItem invItem = new InventoryItem(); Item item = null; // Get the client's character info string charName = "Badass"; DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<Character>(c => c.Account); dlo.LoadWith<Character>(c => c.Zone); dlo.LoadWith<Character>(c => c.InventoryItems); dlo.LoadWith<InventoryItem>(ii => ii.Item); using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; dbCtx.LoadOptions = dlo; toon = dbCtx.Characters.SingleOrDefault(c => c.Name == charName); } ZonePlayer zp = new ZonePlayer(1, toon, 1, new Client(new System.Net.IPEndPoint(0x2414188f, 123))); // Get the inventory item (bone chips) we're giving to the char using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; item = dbCtx.Items.SingleOrDefault(i => i.ItemID == 13073); } invItem.Item = item; invItem.Charges = 1; // Giving one bone chip // ACT if (!zp.AutoGiveItem(ref invItem)) zp.GiveItem(invItem, (int)InventorySlot.Cursor); }
partial void OnZoneIDChanged() { if (this.ZoneID == 0) this.ZoneName = string.Empty; else using (EmuDataContext dbCtx = new EmuDataContext()) this.ZoneName = dbCtx.Zones.Single(z => z.ZoneID == this.ZoneID).ShortName; }
internal void CmdSummonItem(Dictionary<string, string> arguments) { string itemIdStr = "0"; int itemId; if (arguments != null) arguments.TryGetValue("id", out itemIdStr); itemId = int.Parse(itemIdStr); // Get the inventory item we're summoning InventoryItem invItem = new InventoryItem(); invItem.Charges = 1; Item item = null; using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; item = dbCtx.Items.SingleOrDefault(i => i.ItemID == itemId); } if (item == null) { SendSpecialMessage(MessageType.Default, "No item found with that Id."); return; } invItem.Item = item; if (_zp.TargetMob == null) _zp.GiveItem(invItem, (int)InventorySlot.Cursor); else { if (_zp.TargetMob is NpcMob) ((NpcMob)_zp.TargetMob).GiveItem(invItem); else if (_zp.TargetMob is ZonePlayer) ((ZonePlayer)_zp.TargetMob).GiveItem(invItem, (int)InventorySlot.Cursor); SendSpecialMessage(MessageType.Default, "Gave {0} to {1}.", item.Name, _zp.TargetMob.Name); } }
internal static CharacterSelect GetCharSelectData(int acctId) { CharacterSelect charSel = new CharacterSelect(); byte[] noneBuf = Encoding.ASCII.GetBytes("<none>"); for (int i = 0; i < 10; i++) Buffer.BlockCopy(noneBuf, 0, charSel.Name, i * 64, 6); using (EmuDataContext dbCtx = new EmuDataContext()) { DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<Character>(c => c.InventoryItems); dlo.LoadWith<InventoryItem>(ii => ii.Item); dbCtx.LoadOptions = dlo; var characters = from c in dbCtx.Characters where c.AccountID == acctId select c; int charIdx = 0; foreach (Character c in characters) { // character info if (c.Name.Length < 6) Buffer.BlockCopy(Encoding.ASCII.GetBytes(c.Name + "\0\0"), 0, charSel.Name, charIdx * 64, c.Name.Length + 2); else Buffer.BlockCopy(Encoding.ASCII.GetBytes(c.Name), 0, charSel.Name, charIdx * 64, c.Name.Length); charSel.Level[charIdx] = (byte)c.CharLevel; charSel.Class[charIdx] = (byte)c.Class; charSel.Race[charIdx] = (int)c.Race; charSel.Gender[charIdx] = (byte)c.Gender; charSel.Deity[charIdx] = (int)c.Deity; charSel.Zone[charIdx] = (int)c.ZoneID; charSel.HairColor[charIdx] = (byte)c.HairColor; charSel.BeardColor[charIdx] = (byte)c.BeardColor; charSel.EyeColor1[charIdx] = (byte)c.EyeColor1; charSel.EyeColor2[charIdx] = (byte)c.EyeColor2; charSel.Hair[charIdx] = (byte)c.HairStyle; charSel.Beard[charIdx] = (byte)c.Beard; // Get equiped items if (c.InventoryItems.Count > 0) { InventoryManager invMgr = new InventoryManager(c.InventoryItems); for (int equipType = 0; equipType < MAX_EQUIPABLES; equipType++) { InventoryItem ii = invMgr[(int)InventoryManager.GetEquipableSlot((EquipableType)equipType)]; if (ii == null) continue; charSel.Equip[charIdx * equipType] = ii.Item.Material; charSel.EquipColors[charIdx * equipType] = ii.Item.Color ?? 0; // TODO: tints (LoY era) // Held items (set the idfile) if (equipType == (int)EquipableType.Primary || equipType == (int)EquipableType.Secondary) { if (ii.Item.IDFile.Length > 2) { int idFile = int.Parse(ii.Item.IDFile.Substring(2)); if (equipType == (int)EquipableType.Primary) charSel.Primary[charIdx] = idFile; else charSel.Secondary[charIdx] = idFile; } } } } charIdx++; } } return charSel; }
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 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 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(); } }
internal static bool CheckNameFilter(string name) { if (!Regex.IsMatch(name, @"^[a-zA-Z\'\s]{4,64}")) // all alpha, between 4 and 64 in len return false; using (EmuDataContext dbCtx = new EmuDataContext()) if (dbCtx.NameFilters.Count(nf => SqlMethods.Like(name, nf.Filter)) > 0) return false; return true; }
internal void LoadGrid(int zoneId, EmuDataContext dbCtx) { if (_gridId < 1) return; //_log.DebugFormat("Loading grid {0} for {1}", _gridId, _name); Grid grid = dbCtx.Grids.SingleOrDefault(g => g.GridID == _gridId && g.ZoneID == zoneId); if (grid == null) { _log.WarnFormat("Unable to locate grid {0} in db for {1}... why does it have a non-zero grid id?", _gridId, this.Name); return; } _wanderType = grid.WanderType; _pauseType = grid.PauseType; var ges = from ge in dbCtx.GridEntries where ge.GridID == _gridId && ge.ZoneID == zoneId orderby ge.Ordinal select new { Ordinal = ge.Ordinal, X = ge.X, Y = ge.Y, Z = ge.Z, Pause = ge.Pause }; //_log.DebugFormat("Found {0} grid entries - creating that many waypoints.", ges.Count()); _waypoints = new SortedList<int, Waypoint>(ges.Count()); foreach (var ge in ges) // TODO: may need some code for sending midair waypoints to the ground _waypoints.Add(ge.Ordinal, new Waypoint(ge.X, ge.Y, ge.Z, ge.Pause)); if (_waypoints.Count > 1) { //_log.Debug("Minimum waypoint found was " + _waypoints.Keys.Min()); UpdateWaypoint(_waypoints.Keys.Min()); PauseAtWaypoint(); SendTo(_curWaypoint.X, _curWaypoint.Y, _curWaypoint.Z); if (_wanderType == 1 || _wanderType == 2) CalculateNewWaypoint(); } }
//[TestMethod()] public void Inventory_Should_Have_Item_In_Correct_Spot_After_Moving_A_Container() { // ARRANGE // Get the client's character info string charName = "Littlebadwiz"; Character toon = null; DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<Character>(c => c.Account); dlo.LoadWith<Character>(c => c.Zone); dlo.LoadWith<Character>(c => c.InventoryItems); dlo.LoadWith<InventoryItem>(ii => ii.Item); using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; dbCtx.LoadOptions = dlo; toon = dbCtx.Characters.SingleOrDefault(c => c.Name == charName); } ZonePlayer zp = new ZonePlayer(1, toon, 1, new Client(new System.Net.IPEndPoint(0x2414188f, 123))); List<uint?> itemsBefore = new List<uint?> { null, null, null, null, null, null, null, null, null, null }; List<uint?> itemsAfter = new List<uint?> { null, null, null, null, null, null, null, null, null, null }; for (int i = 321; i < 331; i++) { // track the original item ids if (zp.InvMgr[i] != null) itemsBefore[i - 321] = zp.InvMgr[i].ItemID; } // ACT zp.InvMgr.SwapItem(29, 30, (byte)0); // swap a container in the 8th inv slot to the cursor zp.InvMgr.SwapItem(30, 26, (byte)0); // then swap the container from the cursor to the 5th inv slot for (int i = 291; i < 301; i++) { // now track the current item ids if (zp.InvMgr[i] != null) itemsAfter[i - 291] = zp.InvMgr[i].ItemID; } // ASSERT for (int i = 0; i < 10; i++) Assert.IsTrue(itemsBefore[i] == itemsAfter[i]); }
/// <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); }
/// <summary>Initializes all data for a zone - spawns, zone points, AA, etc.</summary> private bool Init(ushort zoneId, ZoneInstanceType ziType) { // Load the zone along with associated zone points, spawns, spawn groups, spawn group entries and NPCs. // TODO: Probably will want to load this differently when zone state persistance is in (join to a state table for spawns?) DataLoadOptions dlo = new DataLoadOptions(); dlo.LoadWith<Zone>(z => z.ZonePoints); dlo.LoadWith<Zone>(z => z.Doors); dlo.LoadWith<Zone>(z => z.Spawns); dlo.LoadWith<Internals.Data.Spawn>(s => s.SpawnGroup); dlo.LoadWith<SpawnGroup>(sg => sg.SpawnGroupEntries); dlo.AssociateWith<SpawnGroup>(sg => sg.SpawnGroupEntries.OrderBy(sge => sge.Chance)); // sort the spawnGroupEntries by chance dlo.LoadWith<SpawnGroupEntry>(sge => sge.Npc); dlo.LoadWith<Npc>(npc => npc.Loot); dlo.LoadWith<Loot>(l => l.LootEntries); dlo.LoadWith<LootEntry>(le => le.LootDrops); dlo.LoadWith<LootDrop>(ld => ld.Item); // TODO: can we trim how much of an item comes back? using (EmuDataContext dbCtx = new EmuDataContext()) { dbCtx.ObjectTrackingEnabled = false; // only loading referential data dbCtx.LoadOptions = dlo; // TODO: use profiler to make sure we get it all in one call //dbCtx.Log = new Log4NetWriter(typeof(ZoneServer)); _zone = dbCtx.Zones.Single(z => z.ZoneID == zoneId); } this.Zone.InitNewZoneStruct(); _instanceType = ziType; // Load map & water map _map = new Map(); _waterMap = new WaterMap(); try { if (!_map.LoadMapFromFile(_zone.ShortName)) return false; if (!_waterMap.LoadMapFromFile(_zone.ShortName)) _waterMap = null; } catch (Exception e) { _log.Error("Error during map loading", e); } _mobMgr.Init(); // Must be done prior to any doors, mobs or player init if (_zone.Doors.Count > 0) { foreach (Door d in _zone.Doors) d.EntityId = GetNewEntityId(); // Assign each door an entity Id _log.InfoFormat("Loaded {0} doors", _zone.Doors.Count); } else _log.Warn("No doors loaded"); // TODO: Load Spawn Conditions SpawnTimerCallback(null); // Load spawns NOW _log.InfoFormat("Loaded {0} Spawn", _mobMgr.MobCount); // TODO: Implement zone state persistance // TODO: Load corpses // TODO: Load traps // TODO: Load ground spawns // TODO: Load objects (tradeskill containers, maybe books, etc.) _maxSpellId = WorldSvc.GetMaxSpellId(); if (_maxSpellId == 0) _log.Error("Max SpellId equals zero. Problem with spell loading in world?"); // TODO: Load blocked spells // TODO: Load guilds, factions, titles, AA, Tributes, corpse timers? // TODO: Load merchant data // TODO: Load petition data // TODO: Load graveyard // TODO: Load timezone data // TODO: Implement server time keeping in world and then sync up here (see end of orig Init and bootup routines) // Just before we finish, start up the various timers _spawnTimer.Change(30000, SPAWN_TIMER_INTERVAL); // We've already populated the spawn list, so wait a bit _spawnQueueTimer.Change(5000, SPAWN_QUEUE_TIMER_INTERVAL); // wait 5 sec before worrying about queued spawn packets _doorTimer.Change(10000, DOOR_TIMER_INTERVAL); // wait 10 sec before worrying about doors // Initialize weather timer if (_zone.Weather <= 3 && _zone.Weather > 0) { Random rand = new Random(); _weatherTimer.Change(0, (rand.Next(1800, 7200) + 30) * 2000); } return true; }