partial void DeleteZone(Zone instance);
 partial void UpdateZone(Zone instance);
 partial void InsertZone(Zone instance);
        /// <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;
        }
        /// <summary>Called when the client is allowed to zone.  Handles all which must happen when a client zones out.</summary>
        internal void ZoneClient(ZoneChange zc, Zone targetZone, float destX, float destY, float destZ, float destH, byte ignoreRestrictions, Client client)
        {
            this.SendLogoutPackets(client);

            _mobMgr.RemoveFromAllHateLists(client.ZonePlayer);

            // TODO: clear aggro for pet, if present

            _log.DebugFormat("{0} is ATTEMPTING to zone to {1} ({2}) {3}x {4}y {5}z", client.ZonePlayer.Name, targetZone.ShortName, targetZone.ZoneID,
                destX, destY, destZ);

            ZoneChange zcOut = new ZoneChange();
            if (targetZone.ZoneID == this.Zone.ZoneID)
            {
                // Zoning to same zone (maybe a bind point, etc.)
                zcOut.ZoneID = this.Zone.ZoneID;
                zcOut.Success = (int)ZoneError.Success;

                client.ZonePlayer.X = destX;
                client.ZonePlayer.Y = destY;
                client.ZonePlayer.Z = destZ;
                client.ZonePlayer.Heading = destH;

                _log.InfoFormat("{0} is zoning to same zone {1}x {2}y {3}z (no error)", client.ZonePlayer.Name, destX, destY, destZ);
                AddClientAuth(client.IPEndPoint.Address.ToString(), true);   // add to expected clients list
            }
            else
            {
                // Send a ZTZ to World
                ZoneToZone ztz = new ZoneToZone();
                ztz.CharName = client.ZonePlayer.Name;
                ztz.CharId = client.ZonePlayer.ID;
                ztz.ClientIp = client.IPEndPoint.Address.ToString();
                ztz.CurrentZoneId = this.Zone.ZoneID;
                ztz.RequestedZoneId = targetZone.ZoneID;
                ztz.AccountStatus = client.ZonePlayer.AccountStatus;
                ztz.IgnoreRestrictions = ignoreRestrictions;
                int ztzResult = WorldSvc.ZoneToZone(ztz);

                if (ztzResult > 0)
                {
                    // problems
                    zcOut.Success = (int)ZoneError.NotReady;
                    client.ZonePlayer.ZoneId = this.Zone.ZoneID;    // client isn't zoning after all, so set the id back to this zone

                    _log.InfoFormat("{0} is zoning to same zone {1}x {2}y {3}z due to error code {4} when asking world to zone",
                        client.ZonePlayer.Name, destX, destY, destZ, ztzResult);

                    client.ZonePlayer.MsgMgr.SendSpecialMessage(MessageType.Default, string.Format("There was a problem zoning.  Code {0}.", ztzResult));
                }
                else
                {
                    zcOut.Init();
                    Buffer.BlockCopy(Encoding.ASCII.GetBytes(client.ZonePlayer.Name), 0, zcOut.CharName, 0, client.ZonePlayer.Name.Length);
                    zcOut.ZoneID = targetZone.ZoneID;
                    zcOut.Success = (int)ZoneError.Success;

                    client.ZonePlayer.X = destX;
                    client.ZonePlayer.Y = destY;
                    client.ZonePlayer.Z = destZ;
                    client.ZonePlayer.Heading = destH;
                    client.ZonePlayer.ZoneId = targetZone.ZoneID;

                    _log.InfoFormat("{0} is zoning to {1} ({2}) {3}x {4}y {5}z", client.ZonePlayer.Name, targetZone.ShortName, targetZone.ZoneID,
                        destX, destY, destZ);

                    // TODO: for ignoreRestrictions of 3, get safe coords for target zone
                }
            }

            client.ZonePlayer.ZoneMode = ZoneMode.Unsolicited;  // reset the zoneMode
            client.ZonePlayer.Save();   // this forced save ensures the correct zone info is available to world when zoning the client

            EQApplicationPacket<ZoneChange> zcPack = new EQApplicationPacket<ZoneChange>(AppOpCode.ZoneChange, zcOut);
            client.SendApplicationPacket(zcPack);
        }
        /// <summary>Unloads all data associated with the zone. Used when dynamic zone is shut down.</summary>
        private void Unload()
        {
            _staleAuthRemovalTimer.Change(Timeout.Infinite, Timeout.Infinite);
            _shutdownTimer.Change(Timeout.Infinite, Timeout.Infinite);
            _spawnTimer.Change(Timeout.Infinite, Timeout.Infinite);
            _spawnQueueTimer.Change(Timeout.Infinite, Timeout.Infinite);
            _weatherTimer.Change(Timeout.Infinite, Timeout.Infinite);
            _doorTimer.Change(Timeout.Infinite, Timeout.Infinite);

            _zone = null;
            _map = null;
            _waterMap = null;
            _mobMgr.Clear();
        }