Beispiel #1
0
 public MyGps(MyObjectBuilder_Gps.Entry builder)
 {
     Name = builder.name;
     Description = builder.description;
     Coords = builder.coords;
     ShowOnHud = builder.showOnHud;
     if (!builder.isFinal)
         SetDiscardAt();
     UpdateHash();
 }
        /// <summary>
        /// Gets a session snapshot customized for an individual player. Removes data that player does not need,
        /// which improves download times, and fixes some exploits.
        /// </summary>
        /// <param name="steamId"></param>
        /// <returns></returns>
        private static MyObjectBuilder_Checkpoint GetClientCheckpoint(ulong steamId)
        {
            Log.Info($"Saving checkpoint...");
            var cpid = new MyObjectBuilder_Checkpoint.PlayerId();

            cpid.ClientId = steamId;
            var ppid = new MyPlayer.PlayerId(steamId);

            if (_checkpoint == null)
            {
                _checkpoint     = MyObjectBuilderSerializer.CreateNewObject <MyObjectBuilder_Checkpoint>();
                _cameraSettings = new List <CameraControllerSettings>();
                var settings = MyObjectBuilderSerializer.Clone(MySession.Static.Settings) as MyObjectBuilder_SessionSettings;
                bGps         = MyObjectBuilderSerializer.CreateNewObject <MyObjectBuilder_Gps>();
                bGps.Entries = new List <MyObjectBuilder_Gps.Entry>();

                settings.ScenarioEditMode |= MySession.Static.PersistentEditMode;

                _checkpoint.SessionName   = MySession.Static.Name;
                _checkpoint.Description   = MySession.Static.Description;
                _checkpoint.PromotedUsers = new SerializableDictionary <ulong, MyPromoteLevel>(MySession.Static.PromotedUsers);
                _checkpoint.CreativeTools = new HashSet <ulong>();
                _checkpoint.Settings      = settings;
                //We're replacing the call to MySession.GetWorld, so Torch can't inject the torch mod. Do it here instead
                _checkpoint.Mods = MySession.Static.Mods.ToList();
                _checkpoint.Mods.AddRange(SessionManager.OverrideMods);
                _checkpoint.Scenario        = MySession.Static.Scenario.Id;
                _checkpoint.WorldBoundaries = MySession.Static.WorldBoundaries;
                _checkpoint.PreviousEnvironmentHostility = MySession.Static.PreviousEnvironmentHostility;
                _checkpoint.RequiresDX          = MySession.Static.RequiresDX;
                _checkpoint.CustomSkybox        = MySession.Static.CustomSkybox;
                _checkpoint.GameDefinition      = MySession.Static.GameDefinition.Id;
                _checkpoint.Gps                 = new SerializableDictionary <long, MyObjectBuilder_Gps>();
                _checkpoint.RespawnCooldowns    = new List <MyObjectBuilder_Checkpoint.RespawnCooldownItem>();
                _checkpoint.ControlledEntities  = new SerializableDictionary <long, MyObjectBuilder_Checkpoint.PlayerId>();
                _checkpoint.ChatHistory         = new List <MyObjectBuilder_ChatHistory>();
                _checkpoint.FactionChatHistory  = new List <MyObjectBuilder_FactionChatHistory>();
                _checkpoint.AppVersion          = MyFinalBuildConstants.APP_VERSION;
                _checkpoint.SessionComponents   = new List <MyObjectBuilder_SessionComponent>();
                _checkpoint.AllPlayersData      = new SerializableDictionary <MyObjectBuilder_Checkpoint.PlayerId, MyObjectBuilder_Player>();
                _checkpoint.AllPlayersColors    = new SerializableDictionary <MyObjectBuilder_Checkpoint.PlayerId, List <Vector3> >();
                _checkpoint.Identities          = new List <MyObjectBuilder_Identity>();
                _checkpoint.Clients             = new List <MyObjectBuilder_Client>();
                _checkpoint.NonPlayerIdentities = new List <long>();
                _checkpoint.CharacterToolbar    = null;
            }

            _checkpoint.CreativeTools.Clear();
            //Pool.DeallocateCollection(_checkpoint.Gps.Dictionary.Values);
            _checkpoint.Gps.Dictionary.Clear();
            //Pool.DeallocateAndClear(bGps.Entries);
            bGps.Entries.Clear();
            //Pool.DeallocateAndClear(_checkpoint.RespawnCooldowns);
            _checkpoint.RespawnCooldowns.Clear();
            Pool.DeallocateAndClear(_checkpoint.ChatHistory);
            _checkpoint.ControlledEntities.Dictionary.Clear();
            Pool.DeallocateAndClear(_checkpoint.FactionChatHistory);
            _checkpoint.SessionComponents.Clear();
            Pool.DeallocateCollection(_checkpoint.AllPlayersData.Dictionary.Values);
            _checkpoint.AllPlayersData.Dictionary.Clear();
            _checkpoint.AllPlayersColors.Dictionary.Clear();
            Pool.DeallocateAndClear(_checkpoint.Identities);
            Pool.DeallocateAndClear(_checkpoint.Clients);
            _checkpoint.NonPlayerIdentities.Clear();
            Pool.DeallocateAndClear(_cameraSettings);

            if (MySession.Static.CreativeToolsEnabled(steamId))
            {
                _checkpoint.CreativeTools.Add(steamId);
            }
            //checkpoint.Briefing = Briefing;
            //checkpoint.BriefingVideo = BriefingVideo;
            _checkpoint.LastSaveTime    = DateTime.Now;
            _checkpoint.WorkshopId      = MySession.Static.WorkshopId;
            _checkpoint.ElapsedGameTime = MySession.Static.ElapsedGameTime.Ticks;
            _checkpoint.InGameTime      = MySession.Static.InGameTime;
            //checkpoint.CharacterToolbar = MyToolbarComponent.CharacterToolbar.GetObjectBuilder();
            //TODO
            _checkpoint.CustomLoadingScreenImage = MySession.Static.CustomLoadingScreenImage;
            _checkpoint.CustomLoadingScreenText  = EssentialsPlugin.Instance.Config.LoadingText ?? MySession.Static.CustomLoadingScreenText;

            _checkpoint.SessionComponentDisabled = MySession.Static.SessionComponentDisabled;
            _checkpoint.SessionComponentEnabled  = MySession.Static.SessionComponentEnabled;

            //  checkpoint.PlayerToolbars = Toolbars.GetSerDictionary();

            //Sync.Players.SavePlayers(_checkpoint);
            ConcurrentDictionary <MyPlayer.PlayerId, MyPlayer> m_players           = Players_Getter(MySession.Static.Players);
            ConcurrentDictionary <MyPlayer.PlayerId, long>     m_playerIdentityIds = PlayerIdentities_Getter(MySession.Static.Players);

            foreach (MyPlayer p in m_players.Values)
            {
                var id = new MyObjectBuilder_Checkpoint.PlayerId {
                    ClientId = p.Id.SteamId, SerialId = p.Id.SerialId
                };
                var playerOb = Pool.AllocateOrCreate <MyObjectBuilder_Player>();

                playerOb.DisplayName     = p.DisplayName;
                playerOb.IdentityId      = p.Identity.IdentityId;
                playerOb.Connected       = true;
                playerOb.ForceRealPlayer = p.IsRealPlayer;

                if (playerOb.BuildColorSlots == null)
                {
                    playerOb.BuildColorSlots = new List <Vector3>();
                }
                else
                {
                    playerOb.BuildColorSlots.Clear();
                }

                foreach (Vector3 color in p.BuildColorSlots)
                {
                    playerOb.BuildColorSlots.Add(color);
                }

                _checkpoint.AllPlayersData.Dictionary.Add(id, playerOb);
            }

            foreach (KeyValuePair <MyPlayer.PlayerId, long> identityPair in m_playerIdentityIds)
            {
                if (m_players.ContainsKey(identityPair.Key))
                {
                    continue;
                }

                var id = new MyObjectBuilder_Checkpoint.PlayerId {
                    ClientId = identityPair.Key.SteamId, SerialId = identityPair.Key.SerialId
                };
                MyIdentity identity = MySession.Static.Players.TryGetIdentity(identityPair.Value);
                var        playerOb = Pool.AllocateOrCreate <MyObjectBuilder_Player>();

                playerOb.DisplayName = identity?.DisplayName;
                playerOb.IdentityId  = identityPair.Value;
                playerOb.Connected   = false;

                if (MyCubeBuilder.AllPlayersColors != null)
                {
                    MyCubeBuilder.AllPlayersColors.TryGetValue(identityPair.Key, out playerOb.BuildColorSlots);
                }

                _checkpoint.AllPlayersData.Dictionary.Add(id, playerOb);
            }

            if (MyCubeBuilder.AllPlayersColors != null)
            {
                foreach (KeyValuePair <MyPlayer.PlayerId, List <Vector3> > colorPair in MyCubeBuilder.AllPlayersColors)
                {
                    //TODO: check if the player exists in m_allIdentities
                    if (m_players.ContainsKey(colorPair.Key) || m_playerIdentityIds.ContainsKey(colorPair.Key))
                    {
                        continue;
                    }

                    var id = new MyObjectBuilder_Checkpoint.PlayerId {
                        ClientId = colorPair.Key.SteamId, SerialId = colorPair.Key.SerialId
                    };
                    _checkpoint.AllPlayersColors.Dictionary.Add(id, colorPair.Value);
                }
            }

            _checkpoint.AllPlayersData.Dictionary.TryGetValue(cpid, out MyObjectBuilder_Player player);

            if (player != null)
            {
                //Toolbars.SaveToolbars(checkpoint);
                MyToolbar toolbar = MySession.Static.Toolbars.TryGetPlayerToolbar(ppid);
                if (toolbar != null)
                {
                    player.Toolbar = toolbar.GetObjectBuilder();
                }
                else if (EssentialsPlugin.Instance.Config.EnableToolbarOverride)
                {
                    player.Toolbar = EssentialsPlugin.Instance.Config.DefaultToolbar;
                    _checkpoint.CharacterToolbar = EssentialsPlugin.Instance.Config.DefaultToolbar;
                }

                //MySession.Static.Cameras.SaveCameraCollection(checkpoint);
                player.EntityCameraData = _cameraSettings;
                Dictionary <MyPlayer.PlayerId, Dictionary <long, MyEntityCameraSettings> > d = EntityCameraSettings;
                if (d.TryGetValue(ppid, out Dictionary <long, MyEntityCameraSettings> camera))
                {
                    foreach (KeyValuePair <long, MyEntityCameraSettings> cameraSetting in camera)
                    {
                        var set = Pool.AllocateOrCreate <CameraControllerSettings>();
                        set.Distance      = cameraSetting.Value.Distance;
                        set.IsFirstPerson = cameraSetting.Value.IsFirstPerson;
                        set.HeadAngle     = cameraSetting.Value.HeadAngle;
                        set.EntityId      = cameraSetting.Key;

                        player.EntityCameraData.Add(set);
                    }
                }

                //Gpss.SaveGpss(checkpoint);

                foreach (IMyGps igps in MyAPIGateway.Session.GPS.GetGpsList(player.IdentityId))
                {
                    var gps = igps as MyGps;
                    if (!gps.IsLocal)
                    {
                        if (gps.EntityId == 0 || MyEntities.GetEntityById(gps.EntityId) != null)
                        {
                            var builder = new MyObjectBuilder_Gps.Entry
                            {
                                name          = gps.Name,
                                description   = gps.Description,
                                coords        = gps.Coords,
                                isFinal       = gps.DiscardAt == null,
                                showOnHud     = gps.ShowOnHud,
                                alwaysVisible = gps.AlwaysVisible,
                                color         = gps.GPSColor,
                                entityId      = gps.EntityId,
                                DisplayName   = gps.DisplayName
                            };
                            bGps.Entries.Add(builder);
                        }
                    }
                }

                _checkpoint.Gps.Dictionary.Add(player.IdentityId, bGps);
            }

            //bunch of allocations in here, but can't replace the logic easily because private types
            _checkpoint.Factions = MySession.Static.Factions.GetObjectBuilder();

            //ok for now, clients need to know about dead identities. Might filter out those that own no blocks.
            //amount of data per ID is low, and admins usually clean them, so meh
            //_checkpoint.Identities = Sync.Players.SaveIdentities();
            foreach (MyIdentity identity in MySession.Static.Players.GetAllIdentities())
            {
                if (MySession.Static.Players.TryGetPlayerId(identity.IdentityId, out MyPlayer.PlayerId id))
                {
                    MyPlayer p = MySession.Static.Players.GetPlayerById(id);
                    if (p != null)
                    {
                        identity.LastLogoutTime = DateTime.Now;
                    }
                }

                var objectBuilder = Pool.AllocateOrCreate <MyObjectBuilder_Identity>();
                objectBuilder.IdentityId         = identity.IdentityId;
                objectBuilder.DisplayName        = identity.DisplayName;
                objectBuilder.CharacterEntityId  = identity.Character?.EntityId ?? 0;
                objectBuilder.Model              = identity.Model;
                objectBuilder.ColorMask          = identity.ColorMask;
                objectBuilder.BlockLimitModifier = identity.BlockLimits.BlockLimitModifier;
                objectBuilder.LastLoginTime      = identity.LastLoginTime;
                objectBuilder.LastLogoutTime     = identity.LastLogoutTime;
                objectBuilder.SavedCharacters    = identity.SavedCharacters;
                objectBuilder.RespawnShips       = identity.RespawnShips;
                objectBuilder.LastDeathPosition  = identity.LastDeathPosition;

                _checkpoint.Identities.Add(objectBuilder);
            }

            Sync.Players.RespawnComponent.SaveToCheckpoint(_checkpoint);
            //count for these is low, and the store is internal, so removing unnecessary entries is cheaper than reflection (probably?)
            _checkpoint.RespawnCooldowns.RemoveAll(i => i.PlayerSteamId != steamId);

            //checkpoint.ControlledEntities = Sync.Players.SerializeControlledEntities();
            foreach (KeyValuePair <long, MyPlayer.PlayerId> entry in MySession.Static.Players.ControlledEntities)
            {
                if (entry.Value.SteamId == steamId)
                {
                    _checkpoint.ControlledEntities.Dictionary.Add(entry.Key, cpid);
                }
            }

            //checkpoint.SpectatorPosition = new MyPositionAndOrientation(ref spectatorMatrix);
            //checkpoint.SpectatorIsLightOn = MySpectatorCameraController.Static.IsLightOn;
            //checkpoint.SpectatorCameraMovement = MySpectator.Static.SpectatorCameraMovement;
            //checkpoint.SpectatorDistance = (float)MyThirdPersonSpectator.Static.GetViewerDistance();
            //checkpoint.CameraController = cameraControllerEnum;
            //if (cameraControllerEnum == MyCameraControllerEnum.Entity)
            //    checkpoint.CameraEntity = ((MyEntity)CameraController).EntityId;
            //if (ControlledEntity != null)
            //{
            //    checkpoint.ControlledObject = ControlledEntity.Entity.EntityId;

            //    if (ControlledEntity is MyCharacter)
            //    {
            //        Debug.Assert(LocalCharacter == null || !(LocalCharacter.IsUsing is MyCockpit), "Character in cockpit cannot be controlled entity");
            //    }
            //}
            //else
            _checkpoint.ControlledObject = -1;

            //SaveChatHistory(checkpoint);

            /*
             * if (player != null && MySession.Static.ChatHistory.TryGetValue(player.IdentityId, out MyChatHistory playerChat))
             * {
             *  var builder = Pool.AllocateOrCreate<MyObjectBuilder_ChatHistory>();
             *  builder.IdentityId = playerChat.IdentityId;
             *  if (builder.PlayerChatHistory != null)
             *      Pool.DeallocateAndClear(builder.PlayerChatHistory);
             *  else
             *      builder.PlayerChatHistory = new List<MyObjectBuilder_PlayerChatHistory>();
             *  foreach (MyPlayerChatHistory chat in playerChat.PlayerChatHistory.Values)
             *  {
             *      var cb = Pool.AllocateOrCreate<MyObjectBuilder_PlayerChatHistory>();
             *      if (cb.Chat != null)
             *          Pool.DeallocateAndClear(cb.Chat);
             *      else
             *          cb.Chat = new List<MyObjectBuilder_PlayerChatItem>();
             *      cb.IdentityId = chat.IdentityId;
             *      foreach (MyPlayerChatItem m in chat.Chat)
             *      {
             *          var mb = Pool.AllocateOrCreate<MyObjectBuilder_PlayerChatItem>();
             *          mb.Text = m.Text;
             *          mb.IdentityIdUniqueNumber = MyEntityIdentifier.GetIdUniqueNumber(m.IdentityId);
             *          mb.TimestampMs = (long)m.Timestamp.TotalMilliseconds;
             *          mb.Sent = m.Sent;
             *          cb.Chat.Add(mb);
             *      }
             *      builder.PlayerChatHistory.Add(cb);
             *  }
             *
             *  if (builder.GlobalChatHistory == null)
             *      builder.GlobalChatHistory = Pool.AllocateOrCreate<MyObjectBuilder_GlobalChatHistory>();
             *  if (builder.GlobalChatHistory.Chat != null)
             *      Pool.DeallocateAndClear(builder.GlobalChatHistory.Chat);
             *  else
             *      builder.GlobalChatHistory.Chat = new List<MyObjectBuilder_GlobalChatItem>();
             *
             *  foreach (MyGlobalChatItem g in playerChat.GlobalChatHistory.Chat)
             *  {
             *      var gb = Pool.AllocateOrCreate<MyObjectBuilder_GlobalChatItem>();
             *      gb.Text = g.Text;
             *      gb.Font = g.AuthorFont;
             *      if (g.IdentityId == 0)
             *      {
             *          gb.IdentityIdUniqueNumber = 0;
             *          gb.Author = g.Author;
             *      }
             *      else
             *      {
             *          gb.IdentityIdUniqueNumber = MyEntityIdentifier.GetIdUniqueNumber(g.IdentityId);
             *          gb.Author = string.Empty;
             *      }
             *      builder.GlobalChatHistory.Chat.Add(gb);
             *  }
             *
             *  _checkpoint.ChatHistory.Add(builder);
             * }
             *
             * if (player != null)
             * {
             *  IMyFaction pfac = MySession.Static.Factions.TryGetPlayerFaction(player.IdentityId);
             *  if (pfac != null)
             *  {
             *      foreach (MyFactionChatHistory history in MySession.Static.FactionChatHistory)
             *      {
             *          if (history.FactionId1 == pfac.FactionId || history.FactionId2 == pfac.FactionId)
             *          {
             *              var builder = Pool.AllocateOrCreate<MyObjectBuilder_FactionChatHistory>();
             *              if (builder.Chat != null)
             *                  Pool.DeallocateAndClear(builder.Chat);
             *              else
             *                  builder.Chat = new List<MyObjectBuilder_FactionChatItem>();
             *
             *              builder.FactionId1 = history.FactionId1;
             *              builder.FactionId2 = history.FactionId2;
             *
             *              foreach (MyFactionChatItem fc in history.Chat)
             *              {
             *                  if (fc.PlayersToSendTo != null && fc.PlayersToSendTo.Count > 0)
             *                  {
             *                      var fb = Pool.AllocateOrCreate<MyObjectBuilder_FactionChatItem>();
             *                      fb.Text = fc.Text;
             *                      fb.IdentityIdUniqueNumber = MyEntityIdentifier.GetIdUniqueNumber(fc.IdentityId);
             *                      fb.TimestampMs = (long)fc.Timestamp.TotalMilliseconds;
             *                      if (fb.PlayersToSendToUniqueNumber != null)
             *                          fb.PlayersToSendToUniqueNumber.Clear();
             *                      else
             *                          fb.PlayersToSendToUniqueNumber = new List<long>();
             *                      if (fb.IsAlreadySentTo != null)
             *                          fb.IsAlreadySentTo.Clear();
             *                      else
             *                          fb.IsAlreadySentTo = new List<bool>();
             *                      foreach (KeyValuePair<long, bool> pair in fc.PlayersToSendTo)
             *                      {
             *                          fb.PlayersToSendToUniqueNumber.Add(MyEntityIdentifier.GetIdUniqueNumber(pair.Key));
             *                          fb.IsAlreadySentTo.Add(pair.Value);
             *                      }
             *                      builder.Chat.Add(fb);
             *                  }
             *              }
             *          }
             *      }
             *  }
             * }
             */

            //_checkpoint.Clients = SaveMembers_Imp(MySession.Static, false);
            if (MyMultiplayer.Static.Members.Count() > 1)
            {
                foreach (ulong member in MyMultiplayer.Static.Members)
                {
                    var ob = Pool.AllocateOrCreate <MyObjectBuilder_Client>();
                    ob.SteamId = member;
                    ob.Name    = MyMultiplayer.Static.GetMemberName(member);
                    ob.IsAdmin = MySession.Static.IsUserAdmin(member);
                    _checkpoint.Clients.Add(ob);
                }
            }

            //_checkpoint.NonPlayerIdentities = Sync.Players.SaveNpcIdentities();
            foreach (long npc in MySession.Static.Players.GetNPCIdentities())
            {
                _checkpoint.NonPlayerIdentities.Add(npc);
            }

            //SaveSessionComponentObjectBuilders(checkpoint);
            CachingDictionary <Type, MySessionComponentBase> compDic = SessionComponents_Getter(MySession.Static);

            foreach (KeyValuePair <Type, MySessionComponentBase> entry in compDic)
            {
                //literally dozens of MB of duplicated garbage. Ignore all of it.
                //TODO: Keen fixed the duplication but this shouldn't exist at all. Rexxar has a plan
                //if (entry.Value is MyProceduralWorldGenerator)
                //    continue;

                MyObjectBuilder_SessionComponent ob = entry.Value.GetObjectBuilder();
                if (ob != null)
                {
                    _checkpoint.SessionComponents.Add(ob);
                }
            }

            _checkpoint.ScriptManagerData = MySession.Static.ScriptManager.GetObjectBuilder();

            //skipped on DS
            //GatherVicinityInformation(checkpoint);

            //if (OnSavingCheckpoint != null)
            //    OnSavingCheckpoint(checkpoint);
            Log.Info("Done.");
            return(_checkpoint);
        }