Skip to content

Commit

Permalink
Merge pull request #95 from cs-util-com/fix/getComponentFixes
Browse files Browse the repository at this point in the history
Fix/gameobject.getComponent() fixes
  • Loading branch information
cs-util authored Mar 1, 2023
2 parents d29b21f + 84942f6 commit f4c80d9
Show file tree
Hide file tree
Showing 43 changed files with 168 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ private static GameObject AddViewToMainViewStack(Func<GameObject> viewInViewStac
/// <summary> Returns the current selected element in a canvas or a view in a view stack </summary>
private static GameObject GetSelectedCanvasChild() {
GameObject selectedGo = Selection.activeGameObject;
if (selectedGo?.GetComponent<RectTransform>() != null) { return selectedGo; }
if (selectedGo?.GetComponentV2<RectTransform>() != null) { return selectedGo; }
if (GetLastActiveView() == null) { AddViewInViewStack(); }
return GetLastActiveView();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,26 @@ public static GameObject GetOrAddChild(this GameObject parentGo, string childNam
/// <summary> Unity returns a comp that pretents to be null so return actual null </summary>
public static T GetComponentV2<T>(this GameObject self) {
var existingComp = self.GetComponent<T>();
return existingComp == null ? default : existingComp;
return IsComponentNull(existingComp) ? default : existingComp;
}

private static bool IsComponentNull(object existingComp) {
var isNull = existingComp == null;
// Check if the component is really accessible:
if (!isNull && existingComp is Component c) {
try {
isNull = c.gameObject == null; // This access will cause an exception if the component is null
} catch (Exception) {
isNull = true;
}
}
return isNull;
}

/// <summary> Unity returns a comp that pretents to be null so return actual null </summary>
public static T GetComponentV2<T>(this Component self) {
var existingComp = self.GetComponent<T>();
return existingComp == null ? default : existingComp;
return IsComponentNull(existingComp) ? default : existingComp;
}

/// <summary> Used for lazy-initialization of a Mono, combine with go.GetOrAddChild </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public static class PointerEventDataExtensions {
public static Vector3 localPosition(this PointerEventData e, bool ignoreGlobalScale = false) {
var go = e.pointerEnter;
if (go == null) { go = e.pointerPress; }
var rt = go.GetComponent<RectTransform>();
var rt = go.GetComponentV2<RectTransform>();
if (rt != null) {
var cam = e.pressEventCamera;
// Check if cam should be used (see https://docs.unity3d.com/ScriptReference/RectTransformUtility.ScreenPointToLocalPointInRectangle.html ):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ public static Texture2D ToTexture2D(this ImageResult self) {

public static async Task<Texture2D> LoadFromUrl(this Image self, string imageUrl) {
if (imageUrl.IsNullOrEmpty()) { throw new ArgumentNullException("The passed imageUrl cant be null"); }
self.GetComponent<LoadTexture2dTaskMono>().Destroy(); // Cancel previous task if possible
self.GetComponentV2<LoadTexture2dTaskMono>().Destroy(); // Cancel previous task if possible
var textureLoader = self.gameObject.GetOrAddComponent<LoadTexture2dTaskMono>();
Texture2D texture2d = await textureLoader.LoadFromUrl(imageUrl);
var downloadedTextureStillNeededByImage = self.GetComponent<LoadTexture2dTaskMono>().imageUrlCurrentlyLoadingFrom == imageUrl;
var downloadedTextureStillNeededByImage = self.GetComponentV2<LoadTexture2dTaskMono>().imageUrlCurrentlyLoadingFrom == imageUrl;
if (downloadedTextureStillNeededByImage) {
self.sprite = texture2d.ToSprite();
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public static T Get<T>(this Dictionary<string, Link> self, string id) {

public static T Get<T>(this Link self) {
if (typeof(T) == typeof(GameObject)) { return (T)(object)self.gameObject; }
var comp = self.GetComponent<T>();
var comp = self.GetComponentV2<T>();
return comp == null ? (T)(object)null : comp;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ protected override void OnEnable() {
private void InitMap() {
var c = gameObject.GetComponentInParents<Canvas>();
AssertV2.IsNotNull(c, "Canvas in LogConsoleUi parent");
if (c == null) { c = gameObject.GetParent().GetComponent<Canvas>(); }
if (c == null) { c = gameObject.GetParent().GetComponentV2<Canvas>(); }
map = c.gameObject.GetLinkMap();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public static IEnumerator RunTest<T>(GameObject parent) where T : UnitTestMono {
public void SimulateButtonClickOn(string buttonName) {
if (simulateUserInput) {
Log.d("Now simulating the user clicking the button=" + buttonName);
GetLink(buttonName).GetComponent<Button>().onClick.Invoke();
GetLink(buttonName).GetComponentV2<Button>().onClick.Invoke();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ namespace com.csutil {
public static class ActionMenuExtensions {

public static async Task<ActionMenu.Entry> ShowActionMenu(this ViewStack self, ActionMenu menu, string menuPrefabName = ActionMenu.DEFAULT_MENU) {
self.ThrowErrorIfNull("ViewStack");
var eventName = "ShowActionMenu " + menu.menuId;
var timing = Log.MethodEntered(eventName);
var menuUiGo = self.ShowView(menuPrefabName);
Expand All @@ -32,6 +33,11 @@ public static class ActionMenuExtensions {
return null;
}
}

public static ActionMenu.Entry AddEntry(this ActionMenu self, ActionMenu.Entry entryToAdd) {
self.entries.Add(entryToAdd);
return entryToAdd;
}

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class GridLayoutGroupCalcMinHeight : MonoBehaviour {

private bool UpdateHeight() {
if (!enabled) { return false; }
var grid = GetComponent<GridLayoutGroup>();
var grid = gameObject.GetComponentV2<GridLayoutGroup>();
if (grid.constraint == GridLayoutGroup.Constraint.Flexible) {
var activeChildCount = grid.gameObject.GetChildrenIEnumerable().Filter(c => c.activeSelf).Count();

Expand All @@ -23,7 +23,7 @@ private bool UpdateHeight() {
int cellCountX = Mathf.Max(1, Mathf.FloorToInt((width - grid.padding.horizontal + grid.spacing.x + 0.001f) / (grid.cellSize.x + grid.spacing.x)));
var minRows = Mathf.CeilToInt(activeChildCount / (float)cellCountX);
var calculatedMinRequiredHeight = grid.padding.vertical + (grid.cellSize.y + grid.spacing.y) * minRows - grid.spacing.y;
var ele = GetComponent<LayoutElement>();
var ele = gameObject.GetComponentV2<LayoutElement>();
if (calculatedMinRequiredHeight != ele.minHeight) { ele.minHeight = calculatedMinRequiredHeight; }
} else {
Log.e("GridLayoutGroupAutoHeight only works with GridLayoutGroup.Constraint.Flexible for now");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ class ImageAspectRatioFitter : MonoBehaviour {
private Sprite lastSprite;

private void OnEnable() {
img = GetComponent<Image>();
aspectRatioFitter = GetComponent<AspectRatioFitter>();
rt = GetComponent<RectTransform>();
img = gameObject.GetComponentV2<Image>();
aspectRatioFitter = gameObject.GetComponentV2<AspectRatioFitter>();
rt = gameObject.GetComponentV2<RectTransform>();
parentRt = transform.parent as RectTransform;
this.ExecuteRepeated(Refresh, delayInMsBetweenIterations: 5);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ private void OnEnable() {
}

private void Start() {
AssertV2.IsFalse(GetComponent<Canvas>().isRootCanvasV2(), $"{nameof(SafeAreaResizer)} should NOT be added on the root canvas level!", gameObject);
AssertV2.IsFalse(gameObject.GetComponentV2<Canvas>().isRootCanvasV2(), $"{nameof(SafeAreaResizer)} should NOT be added on the root canvas level!", gameObject);
}

private void OnRectTransformDimensionsChange() { Recalc(); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class RadioButton : MonoBehaviour {

private void OnEnable() {
var group = GetToggleGroup();
GetComponent<Toggle>().group = group;
gameObject.GetComponentV2<Toggle>().group = group;
}

public ToggleGroup GetToggleGroup() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected virtual void OnEnable() {

[Conditional("DEBUG"), Conditional("ENFORCE_ASSERTIONS")]
private void AssertChildrenHaveCorrectMonosAttached() {
foreach (var t in GetComponent<ToggleGroup>().ActiveToggles()) {
foreach (var t in gameObject.GetComponentV2<ToggleGroup>().ActiveToggles()) {
AssertV2.IsTrue(t.GetComponentV2<ToggleListener>() != null, "Missing ToggleListener MonoBehaviour for child of ToggleGroup", t.gameObject);
AssertV2.IsTrue(t.GetComponentV2<RadioButton>() != null, "Missing RadioButton MonoBehaviour for child of ToggleGroup", t.gameObject);
}
Expand All @@ -42,7 +42,7 @@ public void OnActiveToggleInGroupChanged() {

private void OnActiveToggleInGroupChangedDelayed() {
AssertChildrenHaveCorrectMonosAttached();
var newActiveToggles = GetComponent<ToggleGroup>().ActiveToggles();
var newActiveToggles = gameObject.GetComponentV2<ToggleGroup>().ActiveToggles();
if (!newActiveToggles.SequenceReferencesEqual(activeToggles)) {
activeToggles = new List<Toggle>(newActiveToggles);
OnActiveToggleInGroupChanged(activeToggles);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ public abstract class ToggleListener : MonoBehaviour {
private UnityAction<bool> listener;

private void OnEnable() {
listener = GetComponent<Toggle>().AddOnValueChangedAction(toggleIsOn => {
listener = gameObject.GetComponentV2<Toggle>().AddOnValueChangedAction(toggleIsOn => {
OnToggleStateChanged(toggleIsOn);
InformParentToggleGroupListenerIfFound();
return true;
}, skipChangesByLogic: false);
OnToggleStateChanged(GetComponent<Toggle>().isOn);
OnToggleStateChanged(gameObject.GetComponentV2<Toggle>().isOn);
InformParentToggleGroupListenerIfFound();
}

Expand All @@ -25,7 +25,7 @@ protected virtual void InformParentToggleGroupListenerIfFound() {
}

private void OnDisable() {
GetComponent<Toggle>().onValueChanged.RemoveListener(listener);
gameObject.GetComponentV2<Toggle>().onValueChanged.RemoveListener(listener);
}

protected abstract void OnToggleStateChanged(bool toggleIsOn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private void OnEnable() {

public CanvasGroup GetCanvasGroup() {
if (canvasGroup == null) {
canvasGroup = GetComponent<CanvasGroup>();
canvasGroup = gameObject.GetComponentV2<CanvasGroup>();
initialAlpha = canvasGroup.alpha;
targetAlpha = initialAlpha;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class CanvasOrderOnTop : MonoBehaviour {
private void Start() { SetCanvasSortingOrderOnTop(); }

private void SetCanvasSortingOrderOnTop() {
var canvas = GetComponent<Canvas>();
var canvas = gameObject.GetComponentV2<Canvas>();
var maxOrderOfAnyCanvasFound = canvas.CalcCurrentMaxSortingOrderInLayer();
// If overrideSorting is already active the sorting order must be at least 1 higher, equal does not work in that case:
if (canvas.overrideSorting) { maxOrderOfAnyCanvasFound++; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class CanvasScalerV2 : MonoBehaviour {
private void OnValidate() { UpdateScaler(); } // Called in editor

public void Start() {
AssertV2.IsTrue(GetComponent<Canvas>().isRootCanvasV2(), $"{nameof(CanvasScalerV2)} should be added on the root canvas level!", gameObject);
AssertV2.IsTrue(gameObject.GetComponentV2<Canvas>().isRootCanvasV2(), $"{nameof(CanvasScalerV2)} should be added on the root canvas level!", gameObject);
this.ExecuteRepeated(UpdateScaler, 100);
}

Expand All @@ -26,7 +26,7 @@ public bool UpdateScaler() {
}

private void LazyInitCanvasScaler() {
canvasScaler = GetComponent<CanvasScaler>();
canvasScaler = gameObject.GetComponentV2<CanvasScaler>();
if (canvasScaler.uiScaleMode != CanvasScaler.ScaleMode.ScaleWithScreenSize) {
Log.w("Fixed that CanvasScaler not set to ScaleWithScreenSize! Old scaleMode=" + canvasScaler.uiScaleMode);
canvasScaler.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ public class FlyStick : MonoBehaviour {
private float moveSpeed;

private void OnEnable() {
if (target == null) { target = Camera.main?.GetComponent<Rigidbody>(); }
GetComponent<JoystickUi>().onJoystickChanged.AddListener(OnForceChange);
if (target == null) { target = Camera.main?.GetComponentV2<Rigidbody>(); }
gameObject.GetComponentV2<JoystickUi>().onJoystickChanged.AddListener(OnForceChange);
}

private void OnDisable() {
GetComponent<JoystickUi>().onJoystickChanged.RemoveListener(OnForceChange);
gameObject.GetComponentV2<JoystickUi>().onJoystickChanged.RemoveListener(OnForceChange);
}

private void OnForceChange(bool isNowDragging, Vector2 newForce) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ public class SideMoveStick : MonoBehaviour {
private Vector2 delta;

private void OnEnable() {
if (target == null) { target = Camera.main?.GetComponent<Rigidbody>(); }
GetComponent<JoystickUi>().onJoystickChanged.AddListener(OnForceChange);
if (target == null) { target = Camera.main?.GetComponentV2<Rigidbody>(); }
gameObject.GetComponentV2<JoystickUi>().onJoystickChanged.AddListener(OnForceChange);
}

private void OnDisable() {
GetComponent<JoystickUi>().onJoystickChanged.RemoveListener(OnForceChange);
gameObject.GetComponentV2<JoystickUi>().onJoystickChanged.RemoveListener(OnForceChange);
}

private void OnForceChange(bool isNowDragging, Vector2 newForce) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class ScaleCanvasViaZoom : MonoBehaviour {
public float speed = 0.15f;

private void OnEnable() {
if (scaler == null) { scaler = GetComponent<CanvasScalerV2>(); }
if (scaler == null) { scaler = gameObject.GetComponentV2<CanvasScalerV2>(); }
if (es == null) { es = EventSystem.current; }
AssertV2.IsNotNull(scaler, "No CanvasScalerV2 assigned");
AssertV2.IsNotNull(es, "No event system found in scene");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class IgnoreRootCanvas : MonoBehaviour {

#if DEBUG
private void Start() {
AssertV2.IsTrue(GetComponent<Canvas>().isRootCanvasV2(), "IgnoreRootCanvas can only be used on a root canvas");
AssertV2.IsTrue(gameObject.GetComponentV2<Canvas>().isRootCanvasV2(), "IgnoreRootCanvas can only be used on a root canvas");
}
#endif

Expand Down
44 changes: 41 additions & 3 deletions CsCore/CsCoreUnity/Plugins/CsCoreUnity/com/csutil/ui/RootCanvas.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static Canvas GetOrAddRootCanvas() {
var roots = GetAllRootCanvases();
if (roots.IsNullOrEmpty()) { return CreateNewRootCanvas(); }
// Check if there is a root canvas that has a ViewStack attached:
var rootCanvasesWithViewStack = roots.Filter(x => x.GetComponent<ViewStack>() != null);
var rootCanvasesWithViewStack = roots.Filter(x => x.GetComponentV2<ViewStack>() != null);
if (!rootCanvasesWithViewStack.IsNullOrEmpty()) {
AssertV2.AreEqual(1, rootCanvasesWithViewStack.Count(), "rootCanvasesWithViewStack");
return rootCanvasesWithViewStack.First();
Expand All @@ -51,7 +51,7 @@ private static Canvas FilterForBestRootCanvas(IOrderedEnumerable<Canvas> roots)

/// <summary> Returns a list of root canvases where the first one is the visually most top canvas </summary>
public static IOrderedEnumerable<Canvas> GetAllRootCanvases() {
return ResourcesV2.FindAllInScene<Canvas>().Map(x => x.rootCanvas).ToHashSet().Filter(x => !x.HasComponent<IgnoreRootCanvas>(out var _)).OrderByDescending(x => x.sortingOrder);
return ResourcesV2.FindAllInScene<Canvas>().Map(x => x.rootCanvasV2()).ToHashSet().Filter(x => !x.HasComponent<IgnoreRootCanvas>(out var _)).OrderByDescending(x => x.sortingOrder);
}

public static Canvas CreateNewRootCanvas(string rootCanvasPrefab = "Canvas/DefaultRootCanvas") {
Expand All @@ -66,14 +66,52 @@ public static void InitEventSystemIfNeeded() {
/// <summary> Assert that none of the root canvases has a viewstack directly attached to the same level </summary>
[Conditional("DEBUG"), Conditional("ENFORCE_ASSERTIONS")]
private static void AssertNoViewStacksOnRootCanvasLevel(IOrderedEnumerable<Canvas> roots) {
var rootCanvasesWithViewStack = roots.Filter(x => x.GetComponent<ViewStack>() != null);
var rootCanvasesWithViewStack = roots.Filter(x => x.GetComponentV2<ViewStack>() != null);
if (!rootCanvasesWithViewStack.IsNullOrEmpty()) {
foreach (var c in rootCanvasesWithViewStack) {
Log.e("Found root canvas which had a ViewStack directly attached to it, consider moving the ViewStack to a direct child of the root canvas instead", c.gameObject);
}
}
}

public static Canvas rootCanvasV2(this Canvas self) {
var rootCanvas = self.rootCanvas;
if (self == rootCanvas) {
if (!rootCanvas.isRootCanvasV2()) {
var realRootCanvas = SearchForParentCanvas(rootCanvas);
return realRootCanvas;
}
}
return rootCanvas;
}

public static bool isRootCanvasV2(this Canvas self) {
if (self == null) { return false; }
if (!self.isRootCanvas) return false;

// There is a bug that during the onEnable phase of a MonoBehavior a canvas thinks it is a
// root canvas even though it is not, so additionally all parent canvases need to be collected up
// to the root of the GameObject tree to ensure there are no other canvases on the way up.

// If a canvas is found in any grandparent the current canvas who thinks its a root canvas cant be one:
var parentCanvas = SearchForParentCanvas(self);
if (parentCanvas != null) {
LogWarningNotToDoUiOperationsDuringOnEnable(self);
return false;
}
return true;
}

private static Canvas SearchForParentCanvas(Canvas self) {
var parent = self.gameObject.GetParent();
return parent?.GetComponentInParents<Canvas>();
}

[Conditional("DEBUG")]
private static void LogWarningNotToDoUiOperationsDuringOnEnable(Canvas self) {
Log.w("Using operations on canvas such as .isRootCanvas during onEnable can result in incorrect UI results! If possible delay such operations until the UI is initialized", self.gameObject);
}

}

}
Loading

0 comments on commit f4c80d9

Please sign in to comment.