context: using System;
  
  using ACE.Common;
  using ACE.Database.Models.Shard;
  using ACE.Entity;
  using ACE.Entity.Enum;
  using ACE.Entity.Enum.Properties;
  using ACE.Server.Entity;
  using ACE.Server.Entity.Actions;
  using ACE.Server.Managers;
  using ACE.Server.Network.Enum;
  using ACE.Server.Network.GameEvent.Events;
  using ACE.Server.Network.GameMessages.Messages;
  using ACE.Server.Network.Sequence;
  using ACE.Server.Network.Structure;
  
  namespace ACE.Server.WorldObjects
  {
      partial class Player
      {
          public void PlayerEnterWorld()
          {
              PlayerManager.SwitchPlayerFromOfflineToOnline(this);
              Teleporting = true;
  
              // Save the the LoginTimestamp
              var lastLoginTimestamp = Time.GetUnixTime();
  
              LoginTimestamp = lastLoginTimestamp;
              LastTeleportStartTimestamp = lastLoginTimestamp;
  
              Character.LastLoginTimestamp = lastLoginTimestamp;
              Character.TotalLogins++;
              CharacterChangesDetected = true;
  
              Sequences.SetSequence(SequenceType.ObjectInstance, new UShortSequence((ushort)Character.TotalLogins));
  
              if (BarberActive)
                  BarberActive = false;
  
              if (AllegianceNode != null)
                  AllegianceRank = (int)AllegianceNode.Rank;
              else
                  AllegianceRank = null;
  
              if (!Account15Days)
              {
                  var accountAge = DateTime.UtcNow - Account.CreateTime;
  
                  if (accountAge.TotalDays >= 15)
                      Account15Days = true;
  
                  ManageAccount15Days_HousePurchaseTimestamp();
              }
  
              if (PlayerKillerStatus == PlayerKillerStatus.PKLite && !PropertyManager.GetBool("pkl_server").Item)
              {
                  PlayerKillerStatus = PlayerKillerStatus.NPK;
  
                  var actionChain = new ActionChain();
                  actionChain.AddDelaySeconds(3.0f);
                  actionChain.AddAction(this, () =>
                  {
                      Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.YouAreNonPKAgain));
                  });
                  actionChain.EnqueueChain();
              }
  
              // SendSelf will trigger the entrance into portal space
              SendSelf();
  
              // Update or override certain properties sent to client.
  
              // bugged: do not send this here, or else a freshly loaded acclient will overrwrite the values
              // wait until first enter world is completed
  
              //SendPropertyUpdatesAndOverrides();
  
              if (PropertyManager.GetBool("use_turbine_chat").Item)
              {
                  // Init the client with the chat channel ID's, and then notify the player that they've joined the associated channels.
                  Session.Network.EnqueueSend(new GameEventWeenieError(Session, WeenieError.TurbineChatIsEnabled));
  
                  if (GetCharacterOption(CharacterOption.ListenToAllegianceChat) && Allegiance != null)
                      JoinTurbineChatChannel("Allegiance");
                  if (GetCharacterOption(CharacterOption.ListenToGeneralChat))
                      JoinTurbineChatChannel("General");
                  if (GetCharacterOption(CharacterOption.ListenToTradeChat))
                      JoinTurbineChatChannel("Trade");
                  if (GetCharacterOption(CharacterOption.ListenToLFGChat))
                      JoinTurbineChatChannel("LFG");
                  if (GetCharacterOption(CharacterOption.ListenToRoleplayChat))
                      JoinTurbineChatChannel("Roleplay");
                  if (GetCharacterOption(CharacterOption.ListenToSocietyChat) && Society != FactionBits.None)
                      JoinTurbineChatChannel("Society");
              }
  
              // check if vassals earned XP while offline
              HandleAllegianceOnLogin();
              HandleHouseOnLogin();
  
              // retail appeared to send the squelch list very early,
              // even before the CreatePlayer, but doing it here
              if (SquelchManager.HasSquelches)
                  SquelchManager.SendSquelchDB();
  
              AuditItemSpells();
              AuditEquippedItems();
  
              HandleMissingXp();
              HandleSkillCreditRefund();
              HandleSkillTemplesReset();
              HandleSkillSpecCreditRefund();
              HandleFreeSkillResetRenewal();
              HandleFreeAttributeResetRenewal();
  
              HandleDBUpdates();
  
              if (ServerManager.ShutdownInitiated)
              {
                  var actionChain = new ActionChain();
                  actionChain.AddDelaySeconds(10.0f);
                  actionChain.AddAction(this, () =>
                  {
                      SendMessage(ServerManager.ShutdownNoticeText(), ChatMessageType.WorldBroadcast);
                  });
                  actionChain.EnqueueChain();
              }
          }
  
          public void SendTurbineChatChannels(bool breakAllegiance = false)
          {
              var allegianceChannel = Allegiance != null && !breakAllegiance ? Allegiance.Biota.Id : 0u;
  
              var societyChannel = Society switch
              {
                  FactionBits.CelestialHand => TurbineChatChannel.SocietyCelestialHand,
                  FactionBits.EldrytchWeb => TurbineChatChannel.SocietyEldrytchWeb,
                  FactionBits.RadiantBlood => TurbineChatChannel.SocietyRadiantBlood,
                  _ => 0u
              };
  
              Session.Network.EnqueueSend(new GameEventSetTurbineChatChannels(Session, allegianceChannel, societyChannel));
          }
  
          public void JoinTurbineChatChannel(string channelName)
          {
              if (channelName == "Allegiance" && Allegiance == null)
                  return;
              else if (channelName == "Society")
              {
                  if (Society == FactionBits.None)
                      return;
  
                  channelName = Society switch
                  {
                      FactionBits.CelestialHand => "Celestial Hand",
                      FactionBits.EldrytchWeb => "Eldrytch Web",
                      FactionBits.RadiantBlood => "Radiant Blood",
                      _ => channelName
                  };
              }
              else if (channelName == "Olthoi") //todo: olthoi play
                  return;
  
              Session.Network.EnqueueSend(new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveEnteredThe_Channel, channelName));
  
              SendTurbineChatChannels();
          }
  
          public void LeaveTurbineChatChannel(string channelName, bool breakAllegiance = false)
          {
              if (channelName == "Allegiance" && !breakAllegiance && Allegiance == null)
                  return;
              else if (channelName == "Society")
              {
                  if (Society == FactionBits.None)
                      return;
  
                  channelName = Society switch
                  {
                      FactionBits.CelestialHand => "Celestial Hand",
                      FactionBits.EldrytchWeb => "Eldrytch Web",
                      FactionBits.RadiantBlood => "Radiant Blood",
                      _ => channelName
                  };
              }
              else if (channelName == "Olthoi") //todo: olthoi play
                  return;
  
              Session.Network.EnqueueSend(new GameEventWeenieErrorWithString(Session, WeenieErrorWithString.YouHaveLeftThe_Channel, channelName));
  
              SendTurbineChatChannels(breakAllegiance);
          }
  
          private void SendSelf()
          {
              var player = new GameEventPlayerDescription(Session);
              var title = new GameEventCharacterTitle(Session);
              var friends = new GameEventFriendsListUpdate(Session);
  
              Session.Network.EnqueueSend(player, title, friends);
  
              // Player objects don't get a placement
              Placement = null;
              Session.Network.EnqueueSend(new GameMessagePlayerCreate(Guid), new GameMessageCreateObject(this));
  
              SendInventoryAndWieldedItems();
  
              SendContractTrackerTable();
          }
  
          public void SendPropertyUpdatesAndOverrides()
          {
              if (!PropertyManager.GetBool("require_spell_comps").Item)
                  Session.Network.EnqueueSend(new GameMessagePrivateUpdatePropertyBool(this, PropertyBool.SpellComponentsRequired, false));
          }
  
          /// <summary>
          /// This method iterates through your main pack, any packs and finds all the items contained
          /// It also iterates over your wielded items - it sends create object messages needed by the login process
          /// it is called from SendSelf as part of the login message traffic.   Og II
          /// </summary>
          public void SendInventoryAndWieldedItems()
          {
              foreach (var item in Inventory.Values)
              {
                  Session.Network.EnqueueSend(new GameMessageCreateObject(item));
  
                  // Was the item I just send a container? If so, we need to send the items in the container as well. Og II
                  if (item is Container container)
                  {
                      Session.Network.EnqueueSend(new GameEventViewContents(Session, container));
  
                      foreach (var itemsInContainer in container.Inventory.Values)
                          Session.Network.EnqueueSend(new GameMessageCreateObject(itemsInContainer));
                  }
              }
  
              foreach (var item in EquippedObjects.Values)
              {
                  item.Wielder = this;
                  Session.Network.EnqueueSend(new GameMessageCreateObject(item));                
              }
          }
  
          public void SendContractTrackerTable()
          {
  
gt:             if (Character.GetContractsCount(CharacterDatabaseLock) > 0)