Exemplo n.º 1
0
        private static bool Prefix(PlayableScps.Scp096 __instance, PlayerStats.HitInfo info)
        {
            try
            {
                if (info == null || info.RHub == null)
                {
                    return(false);
                }

                var player = info.RHub.GetPlayer();

                if (player.Invisible || Server.Get.Configs.SynapseConfiguration.CantRage096.Contains(player.RoleID))
                {
                    return(false);
                }

                if (player.RealTeam == Team.SCP && !Server.Get.Configs.SynapseConfiguration.ScpTrigger096)
                {
                    return(false);
                }

                Server.Get.Events.Scp.Scp096.InvokeScpTargetEvent(player, __instance.GetPlayer(), __instance.PlayerState, out var allow);
                return(allow);
            }
            catch (Exception e)
            {
                Synapse.Api.Logger.Get.Error($"Synapse-Event: Scp096AddTargetEvent failed!!\n{e}");
                return(true);
            }
        }
Exemplo n.º 2
0
        public static bool Prefix(PlayableScps.Scp096 __instance, VisionInformation info)
        {
            PlayableScpsController playableScpsController;
            bool whitelisted = info.Source.GetComponent <AdditionalPlayerAbilities>() != null && info.Source.GetComponent <AdditionalPlayerAbilities>().scp096whitelisted;

            Exiled.API.Features.Log.Info("Патчим агр скромника, результат: " + whitelisted);
            if (!info.Looking || !info.RaycastHit || !info.RaycastResult.transform.gameObject.TryGetComponent <PlayableScpsController>(out playableScpsController) || playableScpsController.CurrentScp == null || playableScpsController.CurrentScp != __instance || whitelisted)
            {
                return(false);
            }
            float delay = (1f - info.DotProduct) / 0.25f * (Vector3.Distance(info.Source.transform.position, info.Target.transform.position) * 0.1f);

            if (!__instance.Calming)
            {
                __instance.AddTarget(info.Source);
            }
            if (__instance.CanEnrage && info.Source != null)
            {
                __instance.PreWindup(delay);
                if (NetworkServer.active)
                {
                    NetworkServer.SendToAll <Scp096TriggerMessage>(new Scp096TriggerMessage(info.Target, info.Source), 0);
                }
            }

            return(false);
        }
Exemplo n.º 3
0
        private static float GetRageTime(Scp096 scp096)
        {
            bool isValidTimeAddition = scp096.PlayerState == Scp096PlayerState.Docile ||
                                       scp096.PlayerState == Scp096PlayerState.TryNotToCry ||
                                       scp096.PlayerState == Scp096PlayerState.Enraging;

            return(isValidTimeAddition ? scp096.EnrageTimePerReset : 0f);
        }
Exemplo n.º 4
0
        private static bool Prefix(PlayableScps.Scp096 __instance, PryableDoor gate)
        {
            if (__instance.Charging && __instance.Enraged && (!gate.TargetState /* && gate.doorType == Door.DoorTypes.HeavyGate */))
            {
                var ev = new StartPryingGateEventArgs(API.Features.Player.Get(__instance.Hub.gameObject), gate);
                Exiled.Events.Handlers.Scp096.OnStartPryingGate(ev);
                return(ev.IsAllowed);
            }

            return(false);
        }
Exemplo n.º 5
0
        private static bool Prefix(PlayableScps.Scp096 __instance)
        {
            try
            {
                if (__instance._flash.Enabled)
                {
                    return(false);
                }
                var vector = __instance.Hub.transform.TransformPoint(PlayableScps.Scp096._headOffset);
                foreach (var player in Server.Get.Players)
                {
                    var characterClassManager = player.ClassManager;
                    if (characterClassManager.CurClass != RoleType.Spectator && !(player.Hub == __instance.Hub) && !characterClassManager.IsAnyScp() && Vector3.Dot((player.CameraReference.position - vector).normalized, __instance.Hub.PlayerCameraReference.forward) >= 0.1f)
                    {
                        var visionInformation = VisionInformation.GetVisionInformation(player.Hub, vector, -0.1f, 60f, true, true, __instance.Hub.localCurrentRoomEffects);
                        if (visionInformation.IsLooking)
                        {
                            float delay = visionInformation.LookingAmount / 0.25f * (visionInformation.Distance * 0.1f);
                            if (!__instance.Calming)
                            {
                                if (player.Invisible || Server.Get.Configs.SynapseConfiguration.CantRage096.Contains(player.RoleID))
                                {
                                    continue;
                                }

                                if (player.RealTeam == Team.SCP && !Server.Get.Configs.SynapseConfiguration.ScpTrigger096)
                                {
                                    continue;
                                }

                                Server.Get.Events.Scp.Scp096.InvokeScpTargetEvent(player, __instance.GetPlayer(), __instance.PlayerState, out var allow);
                                __instance.AddTarget(player.gameObject);
                                if (!allow)
                                {
                                    continue;
                                }
                            }
                            if (__instance.CanEnrage && player.gameObject != null)
                            {
                                __instance.PreWindup(delay);
                            }
                        }
                    }
                }
                return(false);
            }
            catch (Exception e)
            {
                Synapse.Api.Logger.Get.Error($"Synapse-Event: Scp096AddTargetEvent failed!!\n{e}\nStackTrace:\n{e.StackTrace}");
                return(true);
            }
        }
Exemplo n.º 6
0
        public void Postfix(PlayableScps.Scp096 __instance, VisionInformation __result, GameObject source)
        {
            VisionInformation visionInformation = new VisionInformation
            {
                Source     = source,
                Target     = __instance.Hub.gameObject,
                RaycastHit = false,
                Looking    = false
            };

            if (source == __instance.Hub.gameObject)
            {
                __result = visionInformation;
                return;
            }
            Transform playerCameraReference = ReferenceHub.GetHub(source).PlayerCameraReference;
            Vector3   position  = __instance.Hub.PlayerCameraReference.position;
            Vector3   position2 = playerCameraReference.position;

            visionInformation.Distance = Vector3.Distance(position2, position);
            float num  = -Vector3.Dot((position2 - position).normalized, playerCameraReference.forward);
            float num2 = -Vector3.Dot((position - position2).normalized, __instance.Hub.PlayerCameraReference.forward);

            visionInformation.DotProduct = num;
            visionInformation.Looking    = true;
            if (num < MoreConfig.singleton.Config.Scp096Config.triggerBounds1 || num2 < MoreConfig.singleton.Config.Scp096Config.triggerBounds2)
            {
                visionInformation.Looking = false;
                __result = visionInformation;
                return;
            }
            if (visionInformation.Distance > ((__instance.Hub.transform.position.y > 980f) ? MoreConfig.singleton.Config.Scp096Config.surfaceTriggerDistance : MoreConfig.singleton.Config.Scp096Config.triggerDistance))
            {
                __result = visionInformation;
                return;
            }
            RaycastHit raycastResult;

            if (!Physics.Raycast(visionInformation.Source.transform.position, (visionInformation.Target.transform.position - visionInformation.Source.transform.position).normalized, out raycastResult, MoreConfig.singleton.Config.Scp096Config.surfaceTriggerDistance, PlayableScps.Scp096.VisionLayerMask))
            {
                __result = visionInformation;
                return;
            }
            visionInformation.RaycastHit    = true;
            visionInformation.RaycastResult = raycastResult;
            __result = visionInformation;
        }
Exemplo n.º 7
0
        private static bool Damage(PlayableScps.Scp096 __instance, PlayerStatsSystem.DamageHandlerBase handler)
        {
            try
            {
                AttackerDamageHandler attackerDamageHandler = handler as AttackerDamageHandler;
                if (attackerDamageHandler == null || attackerDamageHandler.Attacker.Hub == null || !__instance.CanEnrage)
                {
                    return(false);
                }

                var player = attackerDamageHandler.Attacker.Hub.GetPlayer();

                if (player.Invisible || Server.Get.Configs.synapseConfiguration.CantRage096.Contains(player.RoleID))
                {
                    return(false);
                }

                if (player.RealTeam == Team.SCP && !Server.Get.Configs.synapseConfiguration.ScpTrigger096)
                {
                    return(false);
                }

                Server.Get.Events.Scp.Scp096.InvokeScpTargetEvent(player, __instance.GetPlayer(), __instance.PlayerState, out var allow);

                if (allow)
                {
                    __instance.AddTarget(attackerDamageHandler.Attacker.Hub.gameObject);
                    __instance.Windup(false);
                }
                return(allow);
            }
            catch (Exception e)
            {
                Synapse.Api.Logger.Get.Error($"Synapse-Event: Scp096AddTargetEvent failed!!\n{e}");
                return(true);
            }
        }
Exemplo n.º 8
0
 public static bool Prefix(PlayableScps.Scp096 __instance)
 {
     if (((PlayableScp)__instance).isLocalPlayer)
     {
         __instance._abilityManager.RunInputs();
         CursorManager.ChangeMouseVisibility(LockReason.Scp096, (__instance.Charging || (__instance.TryingNotToCry || __instance.PryingGate)) ? MouseVisibilityType.InvisibleButCantMove : MouseVisibilityType.Invisible, false);
         if (!__instance.PlayerState.IsOffensive() && !__instance._visionTargets.IsEmpty <TargetComponent>())
         {
             foreach (TargetComponent component in __instance._visionTargets)
             {
                 if (component != null)
                 {
                     component.IsTarget = false;
                 }
             }
             __instance._visionTargets.Clear();
         }
         if (__instance.TryingNotToCry && (__instance.Hub.fpc.PlySpeed != Vector2.zero))
         {
             Scp096InputMessage message = new Scp096InputMessage
             {
                 InputState = Scp096InputState.None
             };
             NetworkClient.Send <Scp096InputMessage>(message, 0);
         }
     }
     if (NetworkServer.active)
     {
         __instance.UpdateShield();
         __instance.UpdateEnrage();
         __instance.UpdateCharging();
         __instance.UpdatePry();
         foreach (GameObject obj2 in PlayerManager.players)
         {
             CharacterClassManager manager = obj2.GetComponent <CharacterClassManager>();
             if (manager == null || ((manager.CurClass != RoleType.Spectator) && !manager.IsAnyScp()))
             {
                 Player player = Player.Get(obj2);
                 if (player != null && Tracking.PlayersWithSubclasses.ContainsKey(player) &&
                     Tracking.PlayersWithSubclasses[player].Abilities.Contains(AbilityType.Disable096Trigger))
                 {
                     continue;
                 }
                 VisionInformation visionInformation = __instance.GetVisionInformation(obj2);
                 if (visionInformation.Looking)
                 {
                     __instance.ParseVisionInformation(visionInformation);
                 }
             }
         }
         foreach (KeyValuePair <GameObject, Door> pair in PlayableScps.Scp096.takenDoors)
         {
             if (pair.Value.isOpen)
             {
                 PlayableScps.Scp096 scp = PlayableScps.Scp096.Get096FromPlayerObject(pair.Key);
                 if (scp != null)
                 {
                     if (pair.Key == null)
                     {
                         PlayableScps.Scp096.takenDoors.Remove(pair.Key);
                     }
                     else
                     {
                         scp.ResetState();
                     }
                     break;
                 }
             }
         }
     }
     return(false);
 }
Exemplo n.º 9
0
        // Called every 1 second according to the player's Update function. This is way more efficient than the old way of doing a forloop for every player.
        // Also, since the gameObject for the player is deleted when they disconnect, we don't need to worry about cleaning any variables :)
        private void AFKChecker()
        {
            //Log.Info($"AFK Time: {this.AFKTime} AFK Count: {this.AFKCount}");
            if (this.ply.Team == Team.RIP || Player.List.Count() <= plugin.Config.MinPlayers || (plugin.Config.IgnoreTut && this.ply.Team == Team.TUT))
            {
                return;
            }

            bool isScp079          = (this.ply.Role == RoleType.Scp079) ? true : false;
            bool scp096TryNotToCry = false;

            // When SCP096 is in the state "TryNotToCry" he cannot move or it will cancel,
            // therefore, we don't want to AFK check 096 while he's in this state.
            if (this.ply.Role == RoleType.Scp096)
            {
                PlayableScps.Scp096 scp096 = this.ply.ReferenceHub.scpsController.CurrentScp as PlayableScps.Scp096;
                scp096TryNotToCry = (scp096.PlayerState == Scp096PlayerState.TryNotToCry) ? true : false;
            }

            Vector3 CurrentPos   = this.ply.Position;
            Vector3 CurrentAngle = (isScp079) ? this.ply.Camera.targetPosition.position : this.ply.Rotation;

            if (CurrentPos != this.AFKLastPosition || CurrentAngle != this.AFKLastAngle || scp096TryNotToCry)
            {
                this.AFKLastPosition = CurrentPos;
                this.AFKLastAngle    = CurrentAngle;
                this.AFKTime         = 0;
                PlayerToReplace      = null;
                return;
            }

            // The player hasn't moved past this point.
            this.AFKTime++;

            // If the player hasn't reached the time yet don't continue.
            if (this.AFKTime < plugin.Config.AfkTime)
            {
                return;
            }

            // Check if we're still in the "grace" period
            int secondsuntilspec = (plugin.Config.AfkTime + plugin.Config.GraceTime) - this.AFKTime;

            if (secondsuntilspec > 0)
            {
                string warning = plugin.Config.MsgGrace;
                warning = warning.Replace("%timeleft%", secondsuntilspec.ToString());

                this.ply.ClearBroadcasts();
                this.ply.Broadcast(1, $"{plugin.Config.MsgPrefix} {warning}");
                return;
            }

            // The player is AFK and action will be taken.
            Log.Info($"{this.ply.Nickname} ({this.ply.UserId}) was detected as AFK!");
            this.AFKTime = 0;

            // Let's make sure they are still alive before doing any replacement.
            if (this.ply.Team == Team.RIP)
            {
                return;
            }

            if (plugin.Config.TryReplace && !IsPastReplaceTime())
            {
                Assembly easyEvents = Loader.Plugins.FirstOrDefault(pl => pl.Name == "EasyEvents")?.Assembly;

                var roleEasyEvents = easyEvents?.GetType("EasyEvents.Util")?.GetMethod("GetRole")?.Invoke(null, new object[] { this.ply });

                // SCP035 Support (Credit DCReplace)
                bool is035 = false;
                try
                {
                    is035 = this.ply.Id == TryGet035()?.Id;
                }
                catch (Exception e)
                {
                    Log.Debug($"SCP-035 is not installed, skipping method call: {e}");
                }

                // Credit: DCReplace :)
                // I mean at this point 90% of this has been rewritten lol...
                var inventory = this.ply.Inventory.items.Select(x => x.id).ToList();

                RoleType role   = this.ply.Role;
                Vector3  pos    = this.ply.Position;
                float    health = this.ply.Health;

                // New strange ammo system because the old one was f****d.
                uint ammo1 = this.ply.Ammo[(int)AmmoType.Nato556];
                uint ammo2 = this.ply.Ammo[(int)AmmoType.Nato762];
                uint ammo3 = this.ply.Ammo[(int)AmmoType.Nato9];

                // Stuff for 079
                byte  Level079 = 0;
                float Exp079 = 0f, AP079 = 0f;
                if (isScp079)
                {
                    Level079 = this.ply.Level;
                    Exp079   = this.ply.Experience;
                    AP079    = this.ply.Energy;
                }

                PlayerToReplace = Player.List.FirstOrDefault(x => x.Role == RoleType.Spectator && x.UserId != string.Empty && !x.IsOverwatchEnabled && x != this.ply);
                if (PlayerToReplace != null)
                {
                    // Make the player a spectator first so other plugins can do things on player changing role with uAFK.
                    this.ply.Inventory.Clear(); // Clear their items to prevent dupes.
                    this.ply.SetRole(RoleType.Spectator);
                    this.ply.Broadcast(30, $"{plugin.Config.MsgPrefix} {plugin.Config.MsgFspec}");

                    PlayerToReplace.SetRole(role);

                    Timing.CallDelayed(0.3f, () =>
                    {
                        if (is035)
                        {
                            try
                            {
                                TrySpawn035(PlayerToReplace);
                            }
                            catch (Exception e)
                            {
                                Log.Debug($"SCP-035 is not installed, skipping method call: {e}");
                            }
                        }
                        PlayerToReplace.Position = pos;

                        PlayerToReplace.ClearInventory();
                        PlayerToReplace.ResetInventory(inventory);

                        PlayerToReplace.Health = health;

                        PlayerToReplace.Ammo[(int)AmmoType.Nato556] = ammo1;
                        PlayerToReplace.Ammo[(int)AmmoType.Nato762] = ammo2;
                        PlayerToReplace.Ammo[(int)AmmoType.Nato9]   = ammo3;

                        if (isScp079)
                        {
                            PlayerToReplace.Level      = Level079;
                            PlayerToReplace.Experience = Exp079;
                            PlayerToReplace.Energy     = AP079;
                        }

                        PlayerToReplace.Broadcast(10, $"{plugin.Config.MsgPrefix} {plugin.Config.MsgReplace}");
                        if (roleEasyEvents != null)
                        {
                            easyEvents?.GetType("EasyEvents.CustomRoles")?.GetMethod("ChangeRole")?.Invoke(null, new object[] { PlayerToReplace, roleEasyEvents });
                        }
                        PlayerToReplace = null;
                    });
                }
                else
                {
                    // Couldn't find a valid player to spawn, just ForceToSpec anyways.
                    ForceToSpec(this.ply);
                }
            }
            else
            {
                // Replacing is disabled, just ForceToSpec
                ForceToSpec(this.ply);
            }
            // If it's -1 we won't be kicking at all.
            if (plugin.Config.NumBeforeKick != -1)
            {
                // Increment AFK Count
                this.AFKCount++;
                if (this.AFKCount >= plugin.Config.NumBeforeKick)
                {
                    // Since this.AFKCount is greater than the config we're going to kick that player for being AFK too many times in one match.
                    ServerConsole.Disconnect(this.gameObject, plugin.Config.MsgKick);
                }
            }
        }
Exemplo n.º 10
0
        // Called every 1 second according to the player's Update function. This is way more efficient than the old way of doing a forloop for every player.
        // Also, since the gameObject for the player is deleted when they disconnect, we don't need to worry about cleaning any variables :)
        private void AFKChecker()
        {
            //Log.Info($"AFK Time: {this.AFKTime} AFK Count: {this.AFKCount}");
            if (this.ply.Team == Team.RIP)
            {
                return;
            }

            bool isScp079          = (this.ply.Role == RoleType.Scp079) ? true : false;
            bool scp096TryNotToCry = false;

            // When SCP096 is in the state "TryNotToCry" he cannot move or it will cancel,
            // therefore, we don't want to AFK check 096 while he's in this state.
            if (this.ply.Role == RoleType.Scp096)
            {
                PlayableScps.Scp096 scp096 = this.ply.ReferenceHub.scpsController.CurrentScp as PlayableScps.Scp096;
                scp096TryNotToCry = (scp096.PlayerState == Scp096PlayerState.TryNotToCry) ? true : false;
            }

            Vector3 CurrentPos   = this.ply.Position;
            Vector3 CurrentAngle = (isScp079) ? this.ply.Camera.targetPosition.position : this.ply.Rotation;

            if (CurrentPos != this.AFKLastPosition || CurrentAngle != this.AFKLastAngle || scp096TryNotToCry)
            {
                this.AFKLastPosition = CurrentPos;
                this.AFKLastAngle    = CurrentAngle;
                this.AFKTime         = 0;
                return;
            }

            // The player hasn't moved past this point.
            this.AFKTime++;

            // If the player hasn't reached the time yet don't continue.
            if (this.AFKTime < plugin.Config.AfkTime)
            {
                return;
            }

            // Check if we're still in the "grace" period
            int secondsuntilspec = (plugin.Config.AfkTime + plugin.Config.GraceTime) - this.AFKTime;

            if (secondsuntilspec > 0)
            {
                string warning = plugin.Config.MsgGrace;
                warning = warning.Replace("%timeleft%", secondsuntilspec.ToString());

                this.ply.ClearBroadcasts();
                this.ply.Broadcast(1, $"{plugin.Config.MsgPrefix} {warning}");
                return;
            }

            // The player is AFK and action will be taken.
            Log.Info($"{this.ply.Nickname} ({this.ply.UserId}) was detected as AFK!");
            this.AFKTime = 0;

            // Let's make sure they are still alive before doing any replacement.
            if (this.ply.Team == Team.RIP)
            {
                return;
            }

            if (plugin.Config.TryReplace && !this.IsPastReplaceTime())
            {
                var roleEasyEvents = Loader.Plugins.FirstOrDefault(pl => pl.Name == "EasyEvents")?.Assembly.GetType("EasyEvents.Util")?.GetMethod("GetRole")?.Invoke(null, new object[] { this.ply });

                // SCP035 Support (Credit DCReplace)
                bool is035 = false;
                try
                {
                    is035 = this.ply.Id == TryGet035()?.Id;
                }
                catch (Exception e)
                {
                    Log.Debug($"SCP-035 is not installed, skipping method call: {e}");
                }

                // Credit: DCReplace :)
                // I mean at this point 90% of this has been rewritten lol...
                Inventory.SyncListItemInfo items = this.ply.Inventory.items;

                RoleType role   = this.ply.Role;
                Vector3  pos    = this.ply.Position;
                float    health = this.ply.Health;

                // New strange ammo system because the old one was f****d.
                Dictionary <Exiled.API.Enums.AmmoType, uint> ammo = new Dictionary <Exiled.API.Enums.AmmoType, uint>();
                foreach (Exiled.API.Enums.AmmoType atype in (Exiled.API.Enums.AmmoType[])Enum.GetValues(typeof(Exiled.API.Enums.AmmoType)))
                {
                    ammo.Add(atype, this.ply.Ammo[(int)atype]);
                    this.ply.Ammo[(int)atype] = 0; // We remove the ammo so the player doesn't drop it (duplicate ammo)
                }

                // Stuff for 079
                byte  Level079 = 0;
                float Exp079 = 0f, AP079 = 0f;
                if (isScp079)
                {
                    Level079 = this.ply.Level;
                    Exp079   = this.ply.Experience;
                    AP079    = this.ply.Energy;
                }

                Player player = Player.List.FirstOrDefault(x => x.Role == RoleType.Spectator && x.UserId != string.Empty && !x.IsOverwatchEnabled && x != this.ply);
                if (player != null)
                {
                    player.SetRole(role);
                    Timing.CallDelayed(0.3f, () =>
                    {
                        if (is035)
                        {
                            try
                            {
                                TrySpawn035(player);
                            }
                            catch (Exception e)
                            {
                                Log.Debug($"SCP-035 is not installed, skipping method call: {e}");
                            }
                        }
                        player.Position = pos;
                        player.Inventory.Clear();

                        foreach (Inventory.SyncItemInfo item in items)
                        {
                            player.Inventory.AddNewItem(item.id, item.durability, item.modSight, item.modBarrel, item.modOther);
                        }

                        player.Health = health;

                        foreach (Exiled.API.Enums.AmmoType atype in (Exiled.API.Enums.AmmoType[])Enum.GetValues(typeof(Exiled.API.Enums.AmmoType)))
                        {
                            uint amount;
                            if (ammo.TryGetValue(atype, out amount))
                            {
                                this.ply.Ammo[(int)atype] = amount;
                            }
                            else
                            {
                                Log.Error($"[uAFK] ERROR: Tried to get a value from dict that did not exist! (Ammo)");
                            }
                        }

                        if (isScp079)
                        {
                            player.Level      = Level079;
                            player.Experience = Exp079;
                            player.Energy     = AP079;
                        }

                        player.Broadcast(10, $"{plugin.Config.MsgPrefix} {plugin.Config.MsgReplace}");
                        if (roleEasyEvents != null)
                        {
                            Loader.Plugins.FirstOrDefault(pl => pl.Name == "EasyEvents")?.Assembly.GetType("EasyEvents.CustomRoles")?.GetMethod("ChangeRole")?.Invoke(null, new object[] { player, roleEasyEvents });
                        }

                        this.ply.Inventory.Clear(); // Clear their items to prevent dupes.
                        this.ply.SetRole(RoleType.Spectator);
                        this.ply.Broadcast(30, $"{plugin.Config.MsgPrefix} {plugin.Config.MsgFspec}");
                    });
                }
                else
                {
                    // Couldn't find a valid player to spawn, just ForceToSpec anyways.
                    this.ForceToSpec(this.ply);
                }
            }
            else
            {
                // Replacing is disabled, just ForceToSpec
                this.ForceToSpec(this.ply);
            }
            // If it's -1 we won't be kicking at all.
            if (plugin.Config.NumBeforeKick != -1)
            {
                // Increment AFK Count
                this.AFKCount++;
                if (this.AFKCount >= plugin.Config.NumBeforeKick)
                {
                    // Since AFKCount is greater than the config we're going to kick that player for being AFK too many times in one match.
                    ServerConsole.Disconnect(this.gameObject, plugin.Config.MsgKick);
                }
            }
        }