Search Unity

GC.Collect in GUIUtility.BeginGUI()

Discussion in 'Scripting' started by FeastSC2, Mar 10, 2019.

  1. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    I'm getting big performance spikes in GUIUtility.BeginGUI(). But I have no clue what that is and what contributes to it generating so much garbage.
    Info #1: I have a big gameobject with all my UI and I disabled it, so that's not the reason.
    Info #2: This also occurs in built game.

    What causes these lag spikes?

    Here's a screenshot of the Profiler:
    upload_2019-3-10_13-25-17.png
     

    Attached Files:

    Last edited: Mar 10, 2019
  2. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    Hi!

    There might be many sources of GC allocations. To identify those, you can try the following techniques:
    1) When profiling in the Editor you can enable allocation callstacks and watch in Timeline view for red bars - those are GC.Alloc samples which might happen on any thread.
    2) In a Player build deep profiler might help to resemble the callstack - you can enable it for mono scripting backend with -deepprofiling cmd line argument.
    3) Use Profiling.Recorder.sampleBlockCount API for GC.Alloc marker to see if you have any allocations in a frame (in Development Players).

    Also there is pretty comprehensive guide which explains how to minimize managed allocations in Unity.
     
  3. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    I found out what is the reason but it doesn't make any sense: I had a function OnGUI() in one of my scripts, it doesn't contain anything yet it creates garbage. It has to be a bug right?!

    EDIT: I have this bug on other components too it's not just the script I pasted. Removing the OnGUI() function entirely fixed it.


    Code (CSharp):
    1.     private void OnGUI()
    2.     {
    3.     }
    Here's the full script:

    Code (CSharp):
    1. using System;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using Sirenix.OdinInspector;
    5. using UnityEngine;
    6.  
    7. [RequireComponent(typeof(Collider2D)), DisallowMultipleComponent]
    8. public class Hurtbox : MonoBehaviour, IPausable
    9. {
    10. //    private void OnGUI()
    11. //    {
    12. //    }
    13.  
    14.     public Entity Entity { get; private set; }
    15.  
    16.     [DisableInEditorMode, DisableInPlayMode]
    17.     public Unit Owner;
    18.  
    19.     public Alliance StartType
    20.     {
    21.         get
    22.         {
    23.             if (Owner != null)
    24.                 return GetStartTypeFor(Owner.Name);
    25.             else
    26.             {
    27.                 //                Debug.LogError("doesn't have an owner! Alliance = not unit");
    28.                 return Alliance.NotUnit;
    29.             }
    30.         }
    31.     }
    32.  
    33.     public static Alliance GetStartTypeFor(ID _unit)
    34.     {
    35.         if (_unit == ID.Player)
    36.             return Alliance.Player;
    37.         else if (_unit == ID.Demon)
    38.             return Alliance.Ethereal;
    39.         //        else if (_unit == Entity.Crossbowman || _unit == Entity.Guardian)
    40.         //            return Alliance.Empire;
    41.         else return Alliance.Creatures;
    42.     }
    43.  
    44.     private Alliance AllianceOverwritten;
    45.     private bool IsAllianceOverwritten;
    46.  
    47.     public Alliance CurrentType
    48.     {
    49.         get
    50.         {
    51.             if (IsAllianceOverwritten)
    52.             {
    53.                 return AllianceOverwritten;
    54.             }
    55.  
    56.             return StartType;
    57.         }
    58.     }
    59.  
    60.     public void UseOverwriteAlliance(Alliance _newAlliance)
    61.     {
    62.         AllianceOverwritten = _newAlliance;
    63.         IsAllianceOverwritten = true;
    64.     }
    65.  
    66.     public void UseOverwriteAllianceStop()
    67.     {
    68.         IsAllianceOverwritten = false;
    69.     }
    70.  
    71.     public static bool DEBUG_PLAYER_INVINCIBLE = false;
    72.     public static bool DEBUG_ENEMIES_INVINCIBLE = false;
    73.     public static bool DEBUG_ONE_HIT_KILL = false;
    74.  
    75.     public SkinnedMeshRenderer AutoFit;
    76.  
    77.  
    78.     //    private Collider2D Col;
    79.  
    80.     public bool IsPaused { get; set; }
    81.  
    82.     private Controller Control;
    83.  
    84.     public void OnPaused()
    85.     {
    86.         enabled = false;
    87.     }
    88.  
    89.     public void OnUnpaused()
    90.     {
    91.         enabled = true;
    92.     }
    93.  
    94.     public bool IsUnit => Owner != null;
    95.  
    96.  
    97.     /// <summary>
    98.     /// OnGotHit's status can be null depending on what we were hit from.
    99.     /// </summary>
    100.     public Action<HurtboxHitInfo> OnPreHit;
    101.  
    102.     /// <summary>
    103.     /// OnGotHit's status can be null depending on what we were hit from.
    104.     /// </summary>
    105.     public Action<HurtboxHitInfo> OnPostHit;
    106.  
    107.     public struct HurtboxHitInfo
    108.     {
    109.         public HurtboxHitInfo(Damage _dmg, Hitbox _hit, Hurtbox _hurtbox, HitType _hitResult, float _damage)
    110.         {
    111.             Damage = _dmg;
    112.             Hitbox = _hit;
    113.             Hurtbox = _hurtbox;
    114.             HitType = _hitResult;
    115.             Expulsion = _hit.ComplexExpulsion;
    116.             DamageDealt = _damage;
    117.             IsEmpty = false;
    118.         }
    119.  
    120.         public HurtboxHitInfo(bool _isEmpty)
    121.         {
    122.             IsEmpty = true;
    123.             Damage = null;
    124.             Hitbox = null;
    125.             Hurtbox = null;
    126.             DamageDealt = 0;
    127.             HitType = HitType.Empty();
    128.             Expulsion = null;
    129.         }
    130.  
    131.         public static HurtboxHitInfo Empty()
    132.         {
    133.             return new HurtboxHitInfo(true);
    134.         }
    135.  
    136.         public float DamageDealt;
    137.         public bool IsEmpty;
    138.         public Damage Damage;
    139.         public Hitbox Hitbox;
    140.         public Hurtbox Hurtbox;
    141.         public HitType HitType;
    142.         public AdvancedExpulsion Expulsion;
    143.     }
    144.  
    145.     //    public Action<Hitbox, AdvancedExpulsion> OnHitboxHit;
    146.     //    public Action OnHit;
    147.  
    148.     public Action<Damage, Hitbox> OnDying;
    149.  
    150.     /// <summary>
    151.     /// When the character blocks the attack, with a bad timing.
    152.     /// </summary>
    153.     public Action<Hitbox> OnBlocked;
    154.  
    155.     /// <summary>
    156.     /// When the character blocked the attack at the right moment, with a perfect timing.
    157.     /// </summary>
    158.     public Action<Hitbox> OnPerfectBlock;
    159.  
    160.     /// <summary>
    161.     /// We got countered when during our attack
    162.     /// </summary>
    163.     public Action OnYouGotCountered;
    164.  
    165.     private static GameObject DamageIndicator;
    166.  
    167.     public SpriteRenderer SpriteToFlicker;
    168.  
    169.     //    private ColorAnimator DamageFlicker;
    170.     private Color DamagedFlickerColor = Color.red;
    171.  
    172.     /// <summary>
    173.     /// A status is not required to make Interactible work.
    174.     /// </summary>
    175.     [HideInInspector] public Status Status;
    176.  
    177.     //    [Tooltip("If you want the interactible to move when it's hit, you need a Controller2")]
    178.     //    public Controller2 Control;
    179.  
    180.     [Tooltip("Once you get hit, for how long are you invincible?")]
    181.     public float InvincibilityTimeAfterHit = -1f;
    182.  
    183.     public bool CantBeExpulsedByHit;
    184.  
    185.     public bool HasRecovered => DisabledTime <= 0f;
    186.  
    187.     /// <summary>
    188.     /// List of all the hitboxes that have hit us along with a timer that represent when these hitboxes can hit us again.
    189.     /// </summary>
    190.     private readonly List<HitboxHit> HitboxHits = new List<HitboxHit>();
    191.  
    192.     //private readonly List<ExpulsionData> ExpulsionDatas = new List<ExpulsionData>();
    193.  
    194.     //    [Header("Health Bar")] public bool ActivateHealthBar;
    195.     //    private HorizontalBar HealthBar;
    196.     //    public float HealthBarHeight = 5f;
    197.  
    198.     // HITBOX AVOIDANCE
    199.     public bool IsInvincible => InvincibilityTime > 0f;
    200.  
    201.     public float InvincibilityTime;
    202.  
    203.     public bool IsDefending { get; private set; }
    204.     public float DefendTime { get; private set; }
    205.  
    206.     public Vector2 DefendAngleMinMax;
    207.     public float DisabledTime;
    208.     private bool InvincibleDefense;
    209.     private bool OmniAngleDefense;
    210.  
    211.     public GameObject[] OnGotHitFx;
    212.  
    213.  
    214.     /// <summary>
    215.     /// from 0 to 360, with 0dgr and 360dgr == right
    216.     ///     90
    217.     ///  180   0
    218.     ///    270
    219.     /// </summary>
    220.     public void UpdateDefend(float _fromAngle, float _toAngle, bool _invicibleDefend = false)
    221.     {
    222.         IsDefending = true;
    223.         OmniAngleDefense = false;
    224.         DefendAngleMinMax.x = _fromAngle;
    225.         DefendAngleMinMax.y = _toAngle;
    226.         InvincibleDefense = _invicibleDefend;
    227.     }
    228.  
    229.     public void UpdateDefend(bool _invicibleDefend = false)
    230.     {
    231.         IsDefending = true;
    232.         OmniAngleDefense = true;
    233.         InvincibleDefense = _invicibleDefend;
    234.         DefendAngleMinMax.x = 0f;
    235.         DefendAngleMinMax.y = 0f;
    236.     }
    237.  
    238.     //    public void UpdateDefend(float _fromAngle, float _toAngle)
    239.     //    {
    240.     //        DefendTime += Time.deltaTime;
    241.     //        IsDefending = true;
    242.     //        DefendAngleMinMax.x = _fromAngle;
    243.     //        DefendAngleMinMax.y = _toAngle;
    244.     //    }
    245.  
    246.     public void StopDefend()
    247.     {
    248.         OmniAngleDefense = false;
    249.         DefendTime = 0f;
    250.         IsDefending = false;
    251.     }
    252.  
    253.     void Awake()
    254.     {
    255.         PauseManager.AddMe(this);
    256.  
    257.         Owner = GetComponentInParent<Unit>();
    258.         Entity = GetComponentInParent<Entity>();
    259.  
    260.         if (DamageIndicator == null)
    261.             DamageIndicator = Resources.Load<GameObject>(ResourcesPath.DAMAGE_CANVAS);
    262.         Status = GetComponent<Status>();
    263.         if (Status != null) Status.HurtboxInit(this);
    264.         Control = GetComponentInParent<Controller>();
    265.     }
    266.  
    267.     void OnDestroy()
    268.     {
    269.         PauseManager.RemoveMe(this);
    270.     }
    271.  
    272.  
    273. #if UNITY_EDITOR
    274.     private void OnValidate()
    275.     {
    276.         if (gameObject.layer != GConstants.Hurtbox_Layer)
    277.             gameObject.layer = GConstants.Hurtbox_Layer; // Hurtbox
    278.  
    279.         var owner = GetComponentInParent<Unit>();
    280.         if ( /*Owner != null && */Owner != owner)
    281.             Owner = owner;
    282.  
    283.         if (SpriteToFlicker == null)
    284.         {
    285.             var sr = GetComponentInChildren<SpriteRenderer>();
    286.             if (sr != null)
    287.                 SpriteToFlicker = sr;
    288.         }
    289.         //        if (Control == null) Control = GetComponentInParent<Controller2>();
    290.  
    291.         var rb2D = GetComponent<Rigidbody2D>();
    292.         if (rb2D == null)
    293.         {
    294.             rb2D = gameObject.AddComponent<Rigidbody2D>();
    295.         }
    296.  
    297.         if (rb2D != null)
    298.         {
    299.             if (rb2D.isKinematic == false) rb2D.isKinematic = true;
    300.             if (rb2D.collisionDetectionMode != CollisionDetectionMode2D.Continuous)
    301.                 rb2D.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
    302.         }
    303.  
    304.         var col2d = GetComponent<Collider2D>();
    305.         if (col2d.isTrigger == false)
    306.             col2d.isTrigger = true;
    307.     }
    308. #endif
    309.  
    310.     void Update()
    311.     {
    312.         if (IsPaused) return;
    313.  
    314.         if (IsDefending)
    315.             DefendTime += Time.deltaTime;
    316.  
    317.         if (AutoFit != null)
    318.         {
    319.             var scaleAdjBounds = AutoFit.bounds;
    320.             scaleAdjBounds.size /= transform.lossyScale.x;
    321.             Control.Col2D.FitToBounds(scaleAdjBounds, Collider2DExt.FitToBoundsTransformStyle.Center);
    322.  
    323.             transform.position = Control.Col2D.transform.position;
    324.         }
    325.  
    326.         if (Status)
    327.         {
    328.             // TODO: Not really being used...
    329.             DisabledTime -= Time.deltaTime * Status.Stats.HitRecoveryMult.Current;
    330.         }
    331.  
    332.         InvincibilityUpdate();
    333.         UpdateHitboxHits();
    334.     }
    335.  
    336.     private void UpdateHitboxHits()
    337.     {
    338.         for (var i = HitboxHits.Count - 1; i >= 0; i--)
    339.         {
    340.             var hh = HitboxHits[i];
    341.             hh.Timer -= Time.deltaTime;
    342.             //            HitboxHits[i] = new HitboxHit(hh.Id, hh.ActivatedCount, hh.Timer);
    343.  
    344.             // Remove when finished
    345.             if (hh.Timer <= 0f)
    346.             {
    347.                 HitboxHits.RemoveAt(i);
    348.             }
    349.         }
    350.     }
    351.  
    352.     public void SetLastHitboxThatHitMe(int _id, int _activatedCount, float _resetTime)
    353.     {
    354.         if (IsInvincible) return;
    355.  
    356.         HitboxHits.Add(new HitboxHit(_id, _activatedCount, _resetTime));
    357.     }
    358.  
    359.     public void SetDisabledTime(float _disabledTime)
    360.     {
    361.         if (DisabledTime < _disabledTime)
    362.             DisabledTime = _disabledTime;
    363.     }
    364.  
    365.     public bool HasBeenHitByHitboxId(int _id, int _activatedCount)
    366.     {
    367.         foreach (var hitboxHit in HitboxHits)
    368.         {
    369.             // Have I been hit by this hitbox's id + activatedCount before??
    370.             if (hitboxHit.Id == _id
    371.                 && hitboxHit.Timer > 0f
    372.                 && hitboxHit.ActivatedCount == _activatedCount)
    373.             {
    374.                 //Debug.Log("Not accepting new hitbox yet, timer left: " + hitboxHit.Timer);
    375.                 return true;
    376.             }
    377.         }
    378.  
    379.         return false;
    380.     }
    381.  
    382.     public int HasBeenHitByLinkedHitbox(int _mainId, int _mainIdActivatedCount, int[] _linkedIds)
    383.     {
    384.         foreach (var hitboxHit in HitboxHits)
    385.         {
    386.             // Have I been hit by this hitbox's id + activatedCount before??
    387.             if (hitboxHit.Id == _mainId
    388.                 && hitboxHit.Timer > 0f
    389.                 && hitboxHit.ActivatedCount == _mainIdActivatedCount)
    390.             {
    391.                 //Debug.Log("Not accepting new hitbox yet, timer left: " + hitboxHit.Timer);
    392.                 return 1;
    393.             }
    394.         }
    395.  
    396.         if (HitboxHits.Count > 0)
    397.         {
    398.             for (var i = 0; i < _linkedIds.Length; i++)
    399.             {
    400.                 var linkedId = _linkedIds[i];
    401.                 var lastId = HitboxHits.Count - 1;
    402.                 if (HitboxHits[lastId].Id == linkedId)
    403.                 {
    404.                     //                    Debug.Log("recently linked hitbox hit target, skipping");
    405.                     return 2;
    406.                 }
    407.             }
    408.         }
    409.  
    410.         return 0;
    411.     }
    412.  
    413.     public void ReceiveEnchantments(Damage _damage, Hitbox _hitbox, HitType _hitResult)
    414.     {
    415. //        var gotHit = _hitResult.HasHit == HitResult.TargetInvincible || _hitResult.HasHit == HitResult.TargetCountered;;
    416.         if (IsUnit == false) return;
    417.  
    418.         if (_hitbox.EnchantsOnHit != null)
    419.         {
    420.             foreach (var ench in _hitbox.EnchantsOnHit)
    421.             {
    422.                 if (ench.Prefab.GetEnchantmentName() == EnchantID.Frozen && Status.IsFrozen)
    423.                 {
    424.                     Status.EnchantmentManager.StopEnchantment(EnchantID.Frozen);
    425.                     continue;
    426.                 }
    427.  
    428.                 EnchantmentStock.InflictEnchantment(_hitbox.EnchantsOnHit, this.Owner);
    429.             }
    430.         }
    431.  
    432.         if (_hitbox.EnchantsOnHitInspector != null)
    433.         {
    434.             foreach (var ench in _hitbox.EnchantsOnHitInspector)
    435.             {
    436.                 if (ench.ID == EnchantID.Frozen && Status.IsFrozen)
    437.                 {
    438.                     Status.EnchantmentManager.StopEnchantment(EnchantID.Frozen);
    439.                     continue;
    440.                 }
    441.  
    442.                 EnchantmentStock.InflictEnchantment(ench.ID, null, this.Owner, ench.Time);
    443.             }
    444.         }
    445.     }
    446.  
    447.     public bool ReceiveDamage(Damage _damage, Hitbox _hitbox, AdvancedExpulsion _advancedExpulsion,
    448.         HitType _hitResult)
    449.     {
    450.         // IMPORTANT: We don't need the attacker status to calculate the dmg.
    451.         // The damage source is already calculated in the Damage object.
    452.         // Also the status can be null depending on if it's not a unit, but simply a trap...
    453.         // So we probably need to introduce pure dmg for traps and such...
    454.         var gotHit = _hitResult.HasHit == HitResult.TargetInvincible || _hitResult.HasHit == HitResult.TargetCountered;
    455.  
    456.         Status attackerStatus = null;
    457.         if (_hitbox != null)
    458.         {
    459.             if (_hitbox.Owner != null)
    460.                 attackerStatus = _hitbox.Owner.Status;
    461.         }
    462.  
    463.         //        Debug.Log("got hit");
    464.         //        Debug.Log("InvincibilityTime: " + InvincibilityTime );
    465.         //        Debug.Log("Status.IsDead: " + Status.IsDead);
    466.         //        Debug.Log("_hitResult: " + _hitResult);
    467.  
    468.         var damageDealt = CalculateDamage(_damage, _hitResult);
    469.  
    470.         var hitInfo = new HurtboxHitInfo(_damage, _hitbox, this, _hitResult, damageDealt);
    471.         if (OnPreHit != null)
    472.             OnPreHit.Invoke(hitInfo);
    473.  
    474.         if (_damage == null)
    475.         {
    476.             Debug.LogError("The attack was null!");
    477.             return gotHit;
    478.         }
    479.  
    480.         if (_hitResult.HasHit != HitResult.TargetCountered && IsInvincible == false)
    481.         {
    482.             //            // Freeze time to give a better impact.
    483.             //            // TODO: Might not be ok.
    484.             //            if (_damage.IsMelee && IsInvincible == false)
    485.             //                GameTime.FreezeTime(GameScriptable.CombatFeel.OnHitFreezeTime);
    486.  
    487.             if (this.Status == null)
    488.             {
    489.                 // For interactibles without status ( rocks ... )
    490.                 if (CantBeExpulsedByHit == false)
    491.                 {
    492.                     ExpulseBehaviour(_advancedExpulsion);
    493.                 }
    494.             }
    495.             else if (Status.IsDead == false)
    496.             {
    497.                 //            var shakePreset = _hitbox.OnHitPreset;
    498.                 //            if (shakePreset != null)
    499.                 //                ProCamera2DShake.Instance.Shake(shakePreset);
    500.  
    501.                 //            // Enemy regains stamina on hits
    502.                 //            if (_hitbox.Damage.IsMelee && attackerStatus)
    503.                 //            {
    504.                 //                attackerStatus.AddRage(-dmg * Status.CurrRageGainMult);
    505.                 //            }
    506.  
    507.                 if (CantBeExpulsedByHit == false)
    508.                 {
    509.                     //                Debug.Log("expulsing: " + (_advancedExpulsion.Magnitude) + " Angle: " +
    510.                     //                          _advancedExpulsion.ProcessedAngle + " for " + Owner.UnitName);
    511.                     ExpulseBehaviour(_advancedExpulsion);
    512.                 }
    513.  
    514.                 foreach (var fx in _hitbox.OnHitFx)
    515.                 {
    516.                     Instantiate(fx, transform.position, Quaternion.identity);
    517.                 }
    518.  
    519.                 foreach (var fx in OnGotHitFx)
    520.                 {
    521.                     Instantiate(fx, transform.position, Quaternion.identity);
    522.                 }
    523.  
    524.                 // Flicker to show damage has been dealt
    525.                 if (Owner != null)
    526.                 {
    527.                     Owner.Visuals.ShaderManager.SetHit(.15f);
    528.                 }
    529.  
    530.                 if (_damage.DealsDamage)
    531.                 {
    532.                     StartCoroutine(SpawnDamageIndicator(_damage, damageDealt,
    533.                         _advancedExpulsion.GetProcessedDirection(), transform,
    534.                         _hitResult.IsCritical));
    535.                 }
    536.  
    537.                 if (Status.ShieldHp > 0 && damageDealt < 0)
    538.                 {
    539.                     // We need to remove from the shield
    540.                     if (Status.ShieldHp >= damageDealt)
    541.                     {
    542.                         Status.SetShieldHp(Status.ShieldHp + damageDealt);
    543.                         damageDealt = 0;
    544.                     }
    545.                     else
    546.                     {
    547.                         Status.SetShieldHp(0);
    548.                         damageDealt += Status.ShieldHp;
    549.                     }
    550.                 }
    551.  
    552.                 if (Math.Abs(damageDealt) > 0.01f)
    553.                 {
    554.                     if (IfFrozenOnThisAttack(_damage) == false)
    555.                         //                    DamageFlicker.StartFadeInOutColor(DamagedFlickerColor,
    556.                         //                        GameScriptable.CombatFeel.OnHitWhiteFadeInTime,
    557.                         //                        GameScriptable.CombatFeel.OnHitWhiteFadeMaintainTime,
    558.                         //                        GameScriptable.CombatFeel.OnHitWhiteFadeOutTime, IsCharacterFlicker);
    559.  
    560.                         Status.ChangeHp(damageDealt, false);
    561.                 }
    562.  
    563.                 if (attackerStatus != null && _damage.IsVampirism)
    564.                 {
    565.                     var gainedHp = Mathf.Clamp(Mathf.Abs(damageDealt) * attackerStatus.Stats.RevengeDrainMult.Current,
    566.                         0,
    567.                         attackerStatus.Stats.CurrentLostHealth.Value);
    568.                     //                Debug.Log(attackerStatus.name + " just revenged " + gainedHp + " hp back! RevengeMult: " +
    569.                     //                          attackerStatus.Stats.RevengeDrainMult.Current * 100 + "%");
    570.                     attackerStatus.ChangeHp(gainedHp, false);
    571.  
    572.                     // TODO: think about mana regen
    573.                     var manaGained = Mathf.Clamp(
    574.                         Mathf.Abs(damageDealt) * attackerStatus.Stats.ManaRegenOnHitMult.Current, 0,
    575.                         attackerStatus.Stats.MaxMana.Current);
    576.                     manaGained += attackerStatus.Stats.ManaRegenOnHit.Current;
    577.                     attackerStatus.Stats.CurrentMana.Value += manaGained;
    578.                 }
    579.  
    580.                 if (Status.IsDead)
    581.                 {
    582.                     if (OnDying != null)
    583.                     {
    584.                         OnDying.Invoke(_damage, _hitbox);
    585.                     }
    586.  
    587.                     if (attackerStatus != null)
    588.                     {
    589.                         Status.EnchantmentManager.ActivateDeathEnchantmentsOn(_hitbox.Owner);
    590.  
    591.                         // Reduce Player's Shrine fate kill count
    592.                         if (attackerStatus.IsPlayer)
    593.                         {
    594.                             foreach (var f in attackerStatus.EnchantmentManager.Enchantments)
    595.                             {
    596.                                 if (f.Setup.Erase.HasAFlagOf(Enchantment.EraseType.EnemiesKilled))
    597.                                 {
    598.                                     f.NrEnemyLeftToKill--;
    599.                                 }
    600.                             }
    601.                         }
    602.                     }
    603.  
    604.                     if (Status.Owner != null)
    605.                     {
    606.                         if (Owner.Control.Expulsed)
    607.                         {
    608.                             //                        Debug.Log("died being expulsed");
    609.                             Status.Owner.Kill(Unit.KillingWays.Expulsed);
    610.                         }
    611.                         else
    612.                         {
    613.                             //                        Debug.Log("died not expulsed!");
    614.                             Status.Owner.Kill(Unit.KillingWays.Hit);
    615.                         }
    616.                     }
    617.                 }
    618.             }
    619.         }
    620.  
    621.         if (OnPostHit != null && IsInvincible == false)
    622.         {
    623.             var hitInfoPost = new HurtboxHitInfo(_damage, _hitbox, this, _hitResult, damageDealt);
    624.             OnPostHit.Invoke(hitInfoPost);
    625.         }
    626.  
    627.         if (InvincibilityTimeAfterHit > 0f && IsInvincible == false)
    628.         {
    629.             StartInvincibilityFor(InvincibilityTimeAfterHit);
    630.         }
    631.  
    632.         return gotHit;
    633.     }
    634.  
    635.     private bool IfFrozenOnThisAttack(Damage _attack)
    636.     {
    637.         bool freezeAttack = false;
    638.         //        foreach (var fate in _attack.Enchantments)
    639.         //        {
    640.         //            if (fate.Info.EnchName == EnchName.Frozen)
    641.         //            {
    642.         //                freezeAttack = true;
    643.         //            }
    644.         //        }
    645.  
    646.         return freezeAttack;
    647.     }
    648.  
    649.     private IEnumerator SpawnDamageIndicator(Damage _dmg, float _dmgDealt, Vector2 _direction,
    650.         Transform _targetToFollow, bool _isCriticalHit)
    651.     {
    652.         // Can spawn 2 damage indicators at the same time with an offset
    653.         // To spawn the 3rd damage indicator we must wait some time.
    654.  
    655.         //        var damageType = _dmg.GetMostDamagingType();
    656.         //        Color damageColor;
    657.         //        switch (damageType)
    658.         //        {
    659.         //            case DamageType.Physical:
    660.         //                damageColor = Color.grey;
    661.         //                break;
    662.         //            case DamageType.Fire:
    663.         //                damageColor = Color.red;
    664.         //                break;
    665.         //            case DamageType.Ice:
    666.         //                damageColor = Color.blue;
    667.         //                break;
    668.         //            case DamageType.Lightning:
    669.         //                damageColor = Color.white;
    670.         //                break;
    671.         //            case DamageType.Earth:
    672.         //                damageColor = new Color(0.71f, 0.34f, 0f);
    673.         //                break;
    674.         //            case DamageType.Magical:
    675.         //                damageColor = Color.magenta;
    676.         //                break;
    677.         //            default:
    678.         //                damageColor = Color.black;
    679.         //                break;
    680.         //        }
    681.  
    682.         var damageIndic = Instantiate(DamageIndicator, transform.position, Quaternion.identity);
    683.         damageIndic.GetComponent<RectTransform>().position = transform.position;
    684.         var indicator = damageIndic.GetComponent<DamageIndicator>();
    685.         indicator.Init(_targetToFollow);
    686.         indicator.DamageText.text = "";
    687.         if (_isCriticalHit) indicator.DamageText.text = "CRIT!\n";
    688.         indicator.DamageText.text += _dmgDealt.ToString("#");
    689.         indicator.Animator.SetBool("Left", !(_direction.x > 0));
    690.  
    691.         indicator.DamageText.color = _dmg.IdName == ID.Player ? Color.white : Color.red;
    692.  
    693.         yield return null;
    694.     }
    695.  
    696.     private float CalculateDamage(Damage _attack, HitType _hit)
    697.     {
    698.         //Debug.Log("dmg calc: " + _attack.CurrPhysDmg);
    699.         //Debug.Log(" Status.CurrPhysicalRes: " + Status.CurrPhysicalRes);
    700.  
    701.         float resultDamage = 0;
    702.  
    703.         if (Status == null || Status.IsDead || IsInvincible || _hit.HasHit == HitResult.TargetCountered)
    704.         {
    705.             return 0f;
    706.         }
    707.  
    708.         //        Debug.Log("_attack.CurrPhysDmg: " + _attack.CurrPhysDmg);
    709.         //        Debug.Log("_attack.CurrFireDmg: " + _attack.CurrFireDmg);
    710.         //        Debug.Log("_attack.CurrLightningDmg: " + _attack.CurrLightningDmg);
    711.         //        Debug.Log("_attack.CurrIceDmg: " + _attack.CurrIceDmg);
    712.         //        Debug.Log("_attack.CurrEarthDmg: " + _attack.CurrEarthDmg);
    713.         //        Debug.Log("_attack.CurrMagicDmg: " + _attack.CurrMagicDmg);
    714.         var stats = Status.Stats;
    715.  
    716.         resultDamage += _attack.PhysicalDamage.Current * (1 - stats.PhysicalResistance.Current);
    717.         resultDamage += _attack.FireDamage.Current * (1 - stats.FireResistance.Current);
    718.         resultDamage += _attack.LightningDamage.Current * (1 - stats.LightningResistance.Current);
    719.         resultDamage += _attack.IceDamage.Current * (1 - stats.IceResistance.Current);
    720.         resultDamage += _attack.EarthDamage.Current * (1 - stats.EarthResistance.Current);
    721.         resultDamage += _attack.MagicDamage.Current * (1 - stats.MagicResistance.Current);
    722.  
    723.         float totalDamage =
    724.             -resultDamage *
    725.             (_hit.IsCritical ? _attack.CritDamageMult.Current : 1f) /* * (_hit.IsBackstab ? 1.2f : 1f)*/;
    726.  
    727. //        if (_hit.HasHit == HitResult.TargetBlocked) totalDamage *= .5f; // only 50 % of dmg.
    728.         //        Debug.Log("totalDamage: " + totalDamage);
    729.  
    730.         //Debug.Log("totalDmg:  " + totalDamage);
    731.         //        Debug.Break();
    732.  
    733.         if (DEBUG_ONE_HIT_KILL)
    734.             totalDamage = -9999999999f;
    735.  
    736.         if (Owner != null)
    737.         {
    738.             if (Owner.Name == ID.Player && DEBUG_PLAYER_INVINCIBLE) totalDamage = 0;
    739.             if (Owner.Name != ID.Player && DEBUG_ENEMIES_INVINCIBLE) totalDamage = 0;
    740.         }
    741.  
    742.         return Mathf.RoundToInt(totalDamage);
    743.     }
    744.  
    745.     public void ExpulseBehaviour(AdvancedExpulsion _ae)
    746.     {
    747.         if (Control == null || _ae.Enabled == false)
    748.         {
    749.             return;
    750.         }
    751.  
    752.         if (Owner != null)
    753.         {
    754.             Owner.FlipMaster.BeforeHitFlipX = Owner.FlipMaster.IsFlippedX;
    755.             Owner.FlipMaster.BeforeHitFlipY = Owner.FlipMaster.IsFlippedY;
    756.             //            Debug.Log("Facing dir before hit: " + Owner.Control.FacingDirection);
    757.             //            Owner.FlipMaster.BeforeHitFaceDir = Owner.Control.FacingDirection;
    758.             Owner.FlipMaster.HitDirX = _ae.GetProcessedDirection().x < 0 ? false : true;
    759.             //            Owner.FlipMaster.StayFlippedLikeBeforeHit();
    760.         }
    761.  
    762.         Control.ExpulsionStart(_ae);
    763.     }
    764.  
    765.  
    766.     public const float PLAYER_PERFECT_BLOCK_TIMING_RANGE = .23f; //.18f
    767.  
    768.     // SHIELDING LOGIC
    769.     public HitType GetHitType(float _hitAngle, Hitbox _hitbox)
    770.     {
    771.         var result = new HitType {IsBackstab = false};
    772.  
    773.         // the angle right now it's like this:
    774.         //      90
    775.         // +-180    0
    776.         //     -90
    777.         var counterable = _hitbox.Definition.IsCounterable;
    778. //        Debug.Log("hit angle: " + _hitAngle);
    779. //        Debug.Log("counterable: " + counterable);
    780. //        Debug.Log("IsDefending: " + IsDefending);
    781.  
    782.         bool perfectBlock = false;
    783.         bool failedBlock = false;
    784.         if (IsDefending && counterable)
    785.         {
    786.             bool damaged = _hitAngle.IsAngleWithinMinMax(DefendAngleMinMax.x, DefendAngleMinMax.y) == false;
    787.             if (OmniAngleDefense) damaged = false;
    788. //            Debug.Log("damaged: " + damaged);
    789.  
    790.             if (damaged == false)
    791.             {
    792.                 //                Debug.Log("Blocked!");
    793.  
    794.                 var blockTimedRight = DefendTime < PLAYER_PERFECT_BLOCK_TIMING_RANGE;
    795. //                Debug.Log("blockTimedRight: " + blockTimedRight);
    796. //                Debug.Log("InvincibleDefense: " + InvincibleDefense);
    797.  
    798.                 if (blockTimedRight || InvincibleDefense)
    799.                 {
    800.                     //                    Debug.Log("Perfect block!");
    801.  
    802.                     if (OnPerfectBlock != null)
    803.                         OnPerfectBlock.Invoke(_hitbox);
    804.  
    805.                     if (_hitbox.Owner.Hurtbox.OnYouGotCountered != null)
    806.                         _hitbox.Owner.Hurtbox.OnYouGotCountered.Invoke();
    807.  
    808.                     perfectBlock = true;
    809.                 }
    810.                 else
    811.                 {
    812.                     if (OnBlocked != null)
    813.                         OnBlocked.Invoke(_hitbox);
    814.  
    815.                     failedBlock = true;
    816.                 }
    817.             }
    818.         }
    819.  
    820.         if (perfectBlock) result.HasHit = HitResult.TargetCountered;
    821.         else if (failedBlock) result.HasHit = HitResult.TargetBlocked;
    822.         else result.HasHit = HitResult.TouchesTarget;
    823.  
    824.         if (IsInvincible) result.HasHit = HitResult.TargetInvincible;
    825.  
    826.         result.IsCritical = _hitbox.Damage.TriggerCritChance();
    827.  
    828.         if (this.Owner != null && this.Owner.FlipMaster != null)
    829.         {
    830.             var flip = this.Owner.FlipMaster;
    831.             var looksToTheLeftBackstab = flip.IsFlippedX && _hitbox.transform.position.x > this.transform.position.x;
    832.             var looksToTheRightBackstab = !flip.IsFlippedX && _hitbox.transform.position.x < this.transform.position.x;
    833.             if (looksToTheLeftBackstab || looksToTheRightBackstab) // looks to the left
    834.             {
    835.                 result.IsBackstab = true;
    836.             }
    837.         }
    838.  
    839.         return result;
    840.     }
    841.  
    842.     // INVINCIBILITY LOGIC
    843.     public void StartInvincibilityFor(float _time)
    844.     {
    845.         //Debug.Log("Starting invincibility for : " + _time +  "s");
    846.         InvincibilityTime = _time;
    847.     }
    848.  
    849.     public void StopInvincibility()
    850.     {
    851.         InvincibilityTime = 0f;
    852.     }
    853.  
    854.     private void InvincibilityUpdate()
    855.     {
    856.         if (IsInvincible)
    857.         {
    858.             //            Debug.Log("Invincible " + " for: " + InvincibilityTime);
    859.             InvincibilityTime -= Time.deltaTime;
    860.             if (InvincibilityTime < 0)
    861.             {
    862.                 InvincibilityTime = 0;
    863.             }
    864.         }
    865.     }
    866.  
    867.     /// <summary>
    868.     /// Use this when someone died and that he must be reset.
    869.     /// </summary>
    870.     public void ResetEverything()
    871.     {
    872.         // Interactible stuff
    873.         InvincibilityTime = 0;
    874.         HitboxHits.Clear();
    875.         //        if (DamageFlicker != null)
    876.         //            DamageFlicker.StopFlicker();
    877.         DisabledTime = 0f;
    878.         if (Owner.Control != null && Owner.Control.Rb2D != null)
    879.             Owner.Control.Rb2D.velocity = Vector2.zero;
    880.  
    881.         if (Status != null)
    882.         {
    883.             // Status stuff
    884.             Status.EnchantmentManager.RemoveAllEnchantments();
    885.             Status.RejuvenateAll();
    886.         }
    887.     }
    888.  
    889.     public struct HitType
    890.     {
    891.         public HitResult HasHit;
    892.         public bool IsBackstab;
    893.         public bool IsCritical;
    894.  
    895.         public static HitType Empty()
    896.         {
    897.             return new HitType() {HasHit = HitResult.TargetBlocked, IsBackstab = false, IsCritical = false};
    898.         }
    899.     }
    900.  
    901.     public enum HitResult
    902.     {
    903.         TargetInvincible,
    904.         TouchesTarget,
    905.         TargetBlocked,
    906.         TargetCountered
    907.     }
    908. }
    909.  
    910. public class HitboxHit
    911. {
    912.     public HitboxHit(int _id, int _activatedCount, float _timer)
    913.     {
    914.         Id = _id;
    915.         ActivatedCount = _activatedCount;
    916.         Timer = _timer;
    917.         GameTimeAtCreation = Time.time;
    918.         //        Debug.Log("HitGameTime: " + GameTimeAtCreation);
    919.     }
    920.  
    921.     public int Id;
    922.     public int ActivatedCount;
    923.     public float Timer;
    924.     public float GameTimeAtCreation;
    925. }

    Here's a video to prove that the profiler stops detecting garbage as soon as I comment the function OnGUI() or that I disable the Hurtbox component:

     
    Last edited: Mar 11, 2019
  4. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Using OnGUI is the "old way" of creating in-game GUI. The replacement (Canvas-based UI elements) was released in November 2014. All the components supporting OnGUI have been deprecated at this point.

    In short, fixes for OnGUI allocating will probably not happen.
     
    ilmario, vilcans and xVergilx like this.
  5. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    978
    Oh I see, the Profiler could be maybe use a little more work anyway on that specific issue: so that people know in which script OnGUI() generates garbage.
    Anyway I still find it weird that when there is nothing being done in OnGUI it generates garbage. I think that's new because I don't recall having this garbage in previous versions

    Thanks for the information Baste
     
  6. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    With "Callstack" enabled you can get the callstack information for the GC.Alloc sample - which should give you information about the script. (Also works in players starting from 2019.3 - see this beta doc).
     
    jjbish, Climax_THodgson and Bunny83 like this.
  7. stonstad

    stonstad

    Joined:
    Jan 19, 2018
    Posts:
    660
    Does anyone know what the replacement is for OnGUI -- i.e. to get eventing detail re: mouse and keyboard?
     
  8. stonstad

    stonstad

    Joined:
    Jan 19, 2018
    Posts:
    660
    Just replying back to ask -- does anyone know what replaces OnGUI's Event class in the new UI system? I'm hoping to get event information from the new UI system without OnGUI, which allocates.
     
  9. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    I think what you're looking for are the various classes derived from BaseEventData? PointerEventData being the most common.
     
  10. stonstad

    stonstad

    Joined:
    Jan 19, 2018
    Posts:
    660
  11. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    A good rule of thumb that works for most things in Unity (at least right now): If it's in a namespace more specific than UnityEngine or UnityEditor, it's most likely current. Namespaces like UnityEngine.EventSystems, UnityEngine.UI, etc. Unity didn't get in the habit of making namespaces for specific systems until 2014-ish, and to my knowledge, so far none of the classes they've made since then have become deprecated.

    That doesn't mean that if it doesn't have a namespace it is outdated (not all pre-2014 code is or ever will be replaced/deprecated), so this only really works for determining which of two alternative systems is the current one.
     
    stonstad likes this.
  12. KeinZantezuken

    KeinZantezuken

    Joined:
    Mar 28, 2017
    Posts:
    53
  13. DJD1892

    DJD1892

    Joined:
    Dec 2, 2017
    Posts:
    2
    I was generating a constant 368B of GC with GUILayoutUtility.Begin and it only went away when I disabled the CinemachineBrain component on my MainCamera.

    Not sure if your CinemachineBrain is producing that much (or if you still care about it almost 2 years later) but hope this might point people in the right direction for their project
     
    longdhd and GuirieSanchez like this.
  14. lejean

    lejean

    Joined:
    Jul 4, 2013
    Posts:
    392
    If you're using cinemachine you can't really turn of the cinemachinebrain, but when searching through the code of cinemachine the OnGUI is only called in the editor.
     
    HofiOne likes this.
  15. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    4,004
    I have never used Cinemachine, but if it really uses OnGUI at runtime, you may be able to set useGUILayout of that MonoBehaviour to false. It disables the layout system for the IMGUI system for this MonoBehaviour. That means no layout events will be generated and all GUILayout controls can not be used. This is also true for GUI.Window calls. Though all other events should still work fine. I haven't tested it but if they disabled it properly, it should not generate any garbage. Of course if you actually draw things inside OnGUI, most likely there will still be some garbage generated