From 06f27068911d7eb58d3c5427929c5c725368d247 Mon Sep 17 00:00:00 2001 From: Krzysztof Rudnicki Date: Sun, 21 Dec 2025 17:58:05 +0100 Subject: [PATCH] feat: unity project static code linter --- games/unity/.unity-analyzers/UnityStubs.cs | 266 +++++ .../.unity-analyzers/analysis-results.sarif | 1000 +++++++++++++++++ games/unity/.unity-analyzers/build-output.txt | 7 + .../UnityAnalyzer.csproj.nuget.dgspec.json | 75 ++ .../obj/UnityAnalyzer.csproj.nuget.g.props | 18 + .../obj/UnityAnalyzer.csproj.nuget.g.targets | 2 + .../.unity-analyzers/obj/project.assets.json | 102 ++ .../.unity-analyzers/obj/project.nuget.cache | 10 + games/unity/analyze_unity_project.sh | 518 +++++++++ .../unity/magisterka_1/Directory.Build.props | 8 + games/unity/magisterka_1/omnisharp.json | 8 + magisterka_2/Assets/Scripts/Bullet.cs | 5 +- magisterka_2/Assets/Scripts/EffectManager.cs | 10 +- magisterka_2/Assets/Scripts/EffectPulse.cs | 5 +- .../Assets/Scripts/EnemyController.cs | 30 +- magisterka_2/Directory.Build.props | 8 + magisterka_2/omnisharp.json | 8 + 17 files changed, 2070 insertions(+), 10 deletions(-) create mode 100644 games/unity/.unity-analyzers/UnityStubs.cs create mode 100644 games/unity/.unity-analyzers/analysis-results.sarif create mode 100644 games/unity/.unity-analyzers/build-output.txt create mode 100644 games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.dgspec.json create mode 100644 games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.g.props create mode 100644 games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.g.targets create mode 100644 games/unity/.unity-analyzers/obj/project.assets.json create mode 100644 games/unity/.unity-analyzers/obj/project.nuget.cache create mode 100755 games/unity/analyze_unity_project.sh create mode 100644 games/unity/magisterka_1/Directory.Build.props create mode 100644 games/unity/magisterka_1/omnisharp.json create mode 100644 magisterka_2/Directory.Build.props create mode 100644 magisterka_2/omnisharp.json diff --git a/games/unity/.unity-analyzers/UnityStubs.cs b/games/unity/.unity-analyzers/UnityStubs.cs new file mode 100644 index 0000000..ce32928 --- /dev/null +++ b/games/unity/.unity-analyzers/UnityStubs.cs @@ -0,0 +1,266 @@ +// Unity API Stubs for static analysis +// These provide minimal type definitions so the analyzer can check code +// without needing actual Unity assemblies + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEngine +{ + public class Object { + public string name; + public static void Destroy(Object obj) { } + public static void DontDestroyOnLoad(Object target) { } + public static T FindObjectOfType() where T : Object => default; + public static T[] FindObjectsOfType() where T : Object => default; + public static T Instantiate(T original) where T : Object => default; + public static T Instantiate(T original, Vector3 position, Quaternion rotation) where T : Object => default; + } + + public class Component : Object { + public GameObject gameObject; + public Transform transform; + public T GetComponent() => default; + public T[] GetComponents() => default; + public T GetComponentInChildren() => default; + public T GetComponentInParent() => default; + } + + public class Behaviour : Component { public bool enabled; public bool isActiveAndEnabled; } + public class MonoBehaviour : Behaviour { + protected void Invoke(string methodName, float time) { } + protected void CancelInvoke() { } + protected void CancelInvoke(string methodName) { } + protected Coroutine StartCoroutine(IEnumerator routine) => null; + protected Coroutine StartCoroutine(string methodName) => null; + protected void StopCoroutine(Coroutine routine) { } + protected void StopAllCoroutines() { } + } + public class ScriptableObject : Object { } + + public class GameObject : Object { + public Transform transform; + public bool activeSelf; + public bool activeInHierarchy; + public GameObject() { } + public GameObject(string name) { } + public T GetComponent() => default; + public T AddComponent() where T : Component => default; + public void SetActive(bool value) { } + } + + public class Transform : Component, IEnumerable { + public Vector3 position; + public Vector3 localPosition; + public Quaternion rotation; + public Quaternion localRotation; + public Vector3 localScale; + public Transform parent; + public int childCount; + public void SetParent(Transform parent) { } + public Transform GetChild(int index) => default; + public IEnumerator GetEnumerator() => null; + } + + public struct Vector2 { + public float x, y; + public Vector2(float x, float y) { this.x = x; this.y = y; } + public static Vector2 up => new Vector2(0, 1); + public static Vector2 down => new Vector2(0, -1); + public static Vector2 left => new Vector2(-1, 0); + public static Vector2 right => new Vector2(1, 0); + public static Vector2 zero => new Vector2(0, 0); + public static Vector2 one => new Vector2(1, 1); + public Vector2 normalized => this; + public float magnitude => 0; + public float sqrMagnitude => 0; + public static Vector2 operator +(Vector2 a, Vector2 b) => default; + public static Vector2 operator -(Vector2 a, Vector2 b) => default; + public static Vector2 operator *(Vector2 a, float d) => default; + public static Vector2 operator *(float d, Vector2 a) => default; + public static implicit operator Vector3(Vector2 v) => default; + } + + public struct Vector3 { + public float x, y, z; + public Vector3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } + public static Vector3 up => new Vector3(0, 1, 0); + public static Vector3 down => new Vector3(0, -1, 0); + public static Vector3 forward => new Vector3(0, 0, 1); + public static Vector3 back => new Vector3(0, 0, -1); + public static Vector3 left => new Vector3(-1, 0, 0); + public static Vector3 right => new Vector3(1, 0, 0); + public static Vector3 zero => new Vector3(0, 0, 0); + public static Vector3 one => new Vector3(1, 1, 1); + public Vector3 normalized => this; + public static Vector3 operator +(Vector3 a, Vector3 b) => default; + public static Vector3 operator -(Vector3 a, Vector3 b) => default; + public static Vector3 operator *(Vector3 a, float d) => default; + public static Vector3 operator *(float d, Vector3 a) => default; + public static implicit operator Vector2(Vector3 v) => default; + } + + public struct Quaternion { + public float x, y, z, w; + public static Quaternion identity => default; + public static Quaternion Euler(float x, float y, float z) => default; + public static Vector3 operator *(Quaternion rotation, Vector3 point) => default; + } + + public struct Color { + public float r, g, b, a; + public Color(float r, float g, float b, float a = 1f) { this.r = r; this.g = g; this.b = b; this.a = a; } + public static Color white => new Color(1, 1, 1); + public static Color black => new Color(0, 0, 0); + public static Color red => new Color(1, 0, 0); + public static Color green => new Color(0, 1, 0); + public static Color blue => new Color(0, 0, 1); + } + + public struct Rect { public float x, y, width, height; } + + public class Collider : Component { } + public class Collider2D : Component { public new T GetComponent() => default; } + public class BoxCollider2D : Collider2D { } + public class CircleCollider2D : Collider2D { } + public class Rigidbody : Component { } + public class Rigidbody2D : Component { } + + public class SpriteRenderer : Component { public Sprite sprite; public Color color; } + public class Sprite : Object { } + + public static class Time { + public static float time => 0; + public static float deltaTime => 0; + public static float fixedDeltaTime => 0; + public static float unscaledDeltaTime => 0; + public static float timeScale { get; set; } + } + + public static class Input { + public static float GetAxis(string axisName) => 0; + public static float GetAxisRaw(string axisName) => 0; + public static bool GetKey(KeyCode key) => false; + public static bool GetKeyDown(KeyCode key) => false; + public static bool GetKeyUp(KeyCode key) => false; + public static bool GetMouseButton(int button) => false; + public static bool GetMouseButtonDown(int button) => false; + public static bool GetMouseButtonUp(int button) => false; + public static Vector3 mousePosition => default; + } + + public enum KeyCode { + None, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + Alpha0, Alpha1, Alpha2, Alpha3, Alpha4, Alpha5, Alpha6, Alpha7, Alpha8, Alpha9, + Space, Return, Escape, Tab, LeftShift, RightShift, LeftControl, RightControl, + UpArrow, DownArrow, LeftArrow, RightArrow + } + + public static class Mathf { + public const float PI = 3.14159265f; + public static float Abs(float f) => f < 0 ? -f : f; + public static float Sin(float f) => 0; + public static float Cos(float f) => 0; + public static float Sqrt(float f) => 0; + public static float Clamp(float value, float min, float max) => value; + public static float Clamp01(float value) => value; + public static int Clamp(int value, int min, int max) => value; + public static float Max(float a, float b) => a > b ? a : b; + public static float Min(float a, float b) => a < b ? a : b; + public static int Max(int a, int b) => a > b ? a : b; + public static int Min(int a, int b) => a < b ? a : b; + public static int FloorToInt(float f) => (int)f; + public static int RoundToInt(float f) => (int)f; + public static float Repeat(float t, float length) => t; + } + + public static class Random { + public static float Range(float min, float max) => min; + public static int Range(int min, int max) => min; + public static float value => 0; + } + + public static class Debug { + public static void Log(object message) { } + public static void LogWarning(object message) { } + public static void LogError(object message) { } + } + + public static class Resources { + public static T Load(string path) where T : Object => default; + public static T GetBuiltinResource(string path) where T : Object => default; + } + + public class WaitForSeconds : YieldInstruction { + public WaitForSeconds(float seconds) { } + } + public class YieldInstruction { } + public class Coroutine : YieldInstruction { } + + public class AnimationCurve { + public float Evaluate(float time) => 0; + public static AnimationCurve Linear(float timeStart, float valueStart, float timeEnd, float valueEnd) => new AnimationCurve(); + } + + [AttributeUsage(AttributeTargets.Field)] + public class SerializeField : Attribute { } + [AttributeUsage(AttributeTargets.Field)] + public class HideInInspector : Attribute { } + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Class)] + public class HeaderAttribute : Attribute { public HeaderAttribute(string header) { } } + [AttributeUsage(AttributeTargets.Field)] + public class RangeAttribute : Attribute { public RangeAttribute(float min, float max) { } } + [AttributeUsage(AttributeTargets.Class)] + public class RequireComponent : Attribute { public RequireComponent(Type type) { } } + [AttributeUsage(AttributeTargets.Method)] + public class RuntimeInitializeOnLoadMethodAttribute : Attribute { + public RuntimeInitializeOnLoadMethodAttribute() { } + public RuntimeInitializeOnLoadMethodAttribute(RuntimeInitializeLoadType loadType) { } + } + public enum RuntimeInitializeLoadType { AfterSceneLoad, BeforeSceneLoad, AfterAssembliesLoaded, BeforeSplashScreen, SubsystemRegistration } + + public class Camera : Behaviour { + public static Camera main => null; + public float orthographicSize; + public float fieldOfView; + public float aspect; + public Vector3 ScreenToWorldPoint(Vector3 position) => default; + public Vector3 WorldToScreenPoint(Vector3 position) => default; + public Ray ScreenPointToRay(Vector3 pos) => default; + } + public struct Ray { public Vector3 origin; public Vector3 direction; } + + public class Canvas : Behaviour { + public RenderMode renderMode; + } + public enum RenderMode { ScreenSpaceOverlay, ScreenSpaceCamera, WorldSpace } + public class CanvasScaler : Component { } + public class GraphicRaycaster : Component { } + public class RectTransform : Transform { + public Vector2 anchorMin; + public Vector2 anchorMax; + public Vector2 pivot; + public Vector2 anchoredPosition; + public Vector2 sizeDelta; + } + + public class Font : Object { } +} + +namespace UnityEngine.UI +{ + public class Text : UnityEngine.Behaviour { + public string text; + public UnityEngine.Font font; + public int fontSize; + public UnityEngine.Color color; + public TextAnchor alignment; + public HorizontalWrapMode horizontalOverflow; + } + public enum TextAnchor { UpperLeft, UpperCenter, UpperRight, MiddleLeft, MiddleCenter, MiddleRight, LowerLeft, LowerCenter, LowerRight } + public enum HorizontalWrapMode { Wrap, Overflow } + public class Image : UnityEngine.Behaviour { } + public class Button : UnityEngine.Behaviour { } + public class Graphic : UnityEngine.Behaviour { } +} diff --git a/games/unity/.unity-analyzers/analysis-results.sarif b/games/unity/.unity-analyzers/analysis-results.sarif new file mode 100644 index 0000000..79846ae --- /dev/null +++ b/games/unity/.unity-analyzers/analysis-results.sarif @@ -0,0 +1,1000 @@ +{ + "$schema": "http://json.schemastore.org/sarif-2.1.0", + "version": "2.1.0", + "runs": [ + { + "results": [ + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/Enemy.cs" + }, + "region": { + "startLine": 137, + "startColumn": 9, + "endLine": 137, + "endColumn": 52 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/GameDirector.cs" + }, + "region": { + "startLine": 40, + "startColumn": 9, + "endLine": 40, + "endColumn": 105 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/GameDirector.cs" + }, + "region": { + "startLine": 49, + "startColumn": 9, + "endLine": 49, + "endColumn": 54 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/GameDirector.cs" + }, + "region": { + "startLine": 54, + "startColumn": 13, + "endLine": 54, + "endColumn": 41 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/GameDirector.cs" + }, + "region": { + "startLine": 55, + "startColumn": 13, + "endLine": 55, + "endColumn": 53 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0024", + "ruleIndex": 23, + "level": "note", + "message": { + "text": "Re-order operands for better performance." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/PlayerController.cs" + }, + "region": { + "startLine": 51, + "startColumn": 28, + "endLine": 51, + "endColumn": 73 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/GameDirector.cs" + }, + "region": { + "startLine": 64, + "startColumn": 9, + "endLine": 64, + "endColumn": 37 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/GameDirector.cs" + }, + "region": { + "startLine": 65, + "startColumn": 9, + "endLine": 65, + "endColumn": 48 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/PlayerController.cs" + }, + "region": { + "startLine": 117, + "startColumn": 9, + "endLine": 117, + "endColumn": 49 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/PlayerController.cs" + }, + "region": { + "startLine": 140, + "startColumn": 9, + "endLine": 140, + "endColumn": 54 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/PlayerController.cs" + }, + "region": { + "startLine": 130, + "startColumn": 9, + "endLine": 130, + "endColumn": 54 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + }, + { + "ruleId": "UNT0008", + "ruleIndex": 7, + "level": "note", + "message": { + "text": "Unity objects should not use null propagation." + }, + "locations": [ + { + "physicalLocation": { + "artifactLocation": { + "uri": "file:///home/kuchy/praca_magisterska/games/unity/magisterka_1/Assets/PlayerController.cs" + }, + "region": { + "startLine": 151, + "startColumn": 9, + "endLine": 151, + "endColumn": 51 + } + } + } + ], + "properties": { + "warningLevel": 1 + } + } + ], + "properties": { + "analyzerExecutionTime": "0.110" + }, + "tool": { + "driver": { + "name": "Microsoft (R) Visual C# Compiler", + "version": "5.0.0-dev ()", + "dottedQuadFileVersion": "42.42.42.42", + "semanticVersion": "42.42.42", + "language": "en-US", + "rules": [ + { + "id": "UNT0001", + "shortDescription": { + "text": "Empty Unity message" + }, + "fullDescription": { + "text": "Unity messages are called by the runtime even if they're empty. Remove them to avoid unnecessary processing." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0001.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0002", + "shortDescription": { + "text": "Inefficient tag comparison" + }, + "fullDescription": { + "text": "Comparing tags using == is slower than using the built-in CompareTag method." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0002.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "0.001", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0003", + "shortDescription": { + "text": "Usage of non generic GetComponent" + }, + "fullDescription": { + "text": "Usage of the generic form of GetComponent is preferred for type safety." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0003.md", + "properties": { + "category": "TypeSafety", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0004", + "shortDescription": { + "text": "Time.fixedDeltaTime used with Update" + }, + "fullDescription": { + "text": "Update is dependent on the frame rate. Use Time.deltaTime instead of Time.fixedDeltaTime." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0004.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.006", + "executionTimeInPercentage": "5" + } + }, + { + "id": "UNT0005", + "shortDescription": { + "text": "Time.deltaTime used with FixedUpdate" + }, + "fullDescription": { + "text": "FixedUpdate is independent of the frame rate. Use Time.fixedDeltaTime instead of Time.deltaTime." + }, + "defaultConfiguration": { + "level": "note", + "enabled": false + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0005.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.006", + "executionTimeInPercentage": "5" + } + }, + { + "id": "UNT0006", + "shortDescription": { + "text": "Incorrect message signature" + }, + "fullDescription": { + "text": "This Unity message uses an incorrect method signature." + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0006.md", + "properties": { + "category": "TypeSafety", + "executionTimeInSeconds": "0.002", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0007", + "shortDescription": { + "text": "Null coalescing on Unity objects" + }, + "fullDescription": { + "text": "Unity overrides the null comparison operator for Unity objects, which is incompatible with null coalescing." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0007.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.002", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0008", + "shortDescription": { + "text": "Null propagation on Unity objects" + }, + "fullDescription": { + "text": "Unity overrides the null comparison operator for Unity objects, which is incompatible with null propagation." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0008.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.002", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0009", + "shortDescription": { + "text": "Missing static constructor with InitializeOnLoad" + }, + "fullDescription": { + "text": "Provide a static constructor when applying the InitializeOnLoad attribute to a class. This will call it when the editor launches." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0009.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0010", + "shortDescription": { + "text": "Component instance creation" + }, + "fullDescription": { + "text": "Use AddComponent() to create MonoBehaviours. A MonoBehaviour component needs to be attached to a GameObject." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0010.md", + "properties": { + "category": "TypeSafety", + "executionTimeInSeconds": "0.005", + "executionTimeInPercentage": "4" + } + }, + { + "id": "UNT0011", + "shortDescription": { + "text": "ScriptableObject instance creation" + }, + "fullDescription": { + "text": "Use CreateInstance() to create a ScriptableObject. To handle Unity message methods, the Unity engine needs to create the ScriptableObject." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0011.md", + "properties": { + "category": "TypeSafety", + "executionTimeInSeconds": "0.005", + "executionTimeInPercentage": "4" + } + }, + { + "id": "UNT0012", + "shortDescription": { + "text": "Unused Unity Coroutine" + }, + "fullDescription": { + "text": "Use StartCoroutine() to start a coroutine. Calling the coroutine method directly will result in the coroutine never being executed." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0012.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.002", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0013", + "shortDescription": { + "text": "Remove invalid SerializeField attribute" + }, + "fullDescription": { + "text": "SerializeField attribute does not work on properties, and are unnecessary for public fields." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0013.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.003", + "executionTimeInPercentage": "2" + } + }, + { + "id": "UNT0014", + "shortDescription": { + "text": "Invalid type for call to GetComponent" + }, + "fullDescription": { + "text": "GetComponent only supports arguments that are a Unity Component or an interface type." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0014.md", + "properties": { + "category": "TypeSafety", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0015", + "shortDescription": { + "text": "Use a static and parameterless method" + }, + "fullDescription": { + "text": "Unity needs a method decorated with InitializeOnLoadMethod, RuntimeInitializeOnLoadMethod or DidReloadScripts attribute to be static and parameterless. Else either Unity won't call it or will throw NullReferenceException." + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0015.md", + "properties": { + "category": "TypeSafety", + "executionTimeInSeconds": "0.001", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0016", + "shortDescription": { + "text": "Unsafe way to get the method name" + }, + "fullDescription": { + "text": "Usage of nameof or direct call is preferred for type safety." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0016.md", + "properties": { + "category": "TypeSafety", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0017", + "shortDescription": { + "text": "SetPixels invocation is slow" + }, + "fullDescription": { + "text": "Compared to SetPixels, SetPixels32 is much faster and uses less memory." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0017.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "0.016", + "executionTimeInPercentage": "14" + } + }, + { + "id": "UNT0018", + "shortDescription": { + "text": "System.Reflection features in performance critical messages" + }, + "fullDescription": { + "text": "You should not use System.Reflection features in performance critical messages." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0018.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "0.007", + "executionTimeInPercentage": "5" + } + }, + { + "id": "UNT0019", + "shortDescription": { + "text": "Indirection call" + }, + "fullDescription": { + "text": "Do not use unnecessary indirection." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0019.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0020", + "shortDescription": { + "text": "Make method static" + }, + "fullDescription": { + "text": "MenuItem can only be used on static methods." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0020.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.002", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0021", + "shortDescription": { + "text": "Prefer protected Unity Message." + }, + "fullDescription": { + "text": "Unity message should be protected." + }, + "defaultConfiguration": { + "level": "note", + "enabled": false + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0021.md", + "properties": { + "category": "Correctness", + "isEverSuppressed": "true", + "suppressionKinds": [ + "external" + ], + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0022", + "shortDescription": { + "text": "Inefficient position/rotation assignment" + }, + "fullDescription": { + "text": "Prefer using SetPositionAndRotation() method." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0022.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0023", + "shortDescription": { + "text": "Coalescing assignment on Unity objects" + }, + "fullDescription": { + "text": "Unity overrides the null comparison operator for Unity objects, which is incompatible with coalescing assignment." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0023.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.002", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0024", + "shortDescription": { + "text": "Give priority to scalar calculations over vector calculations" + }, + "fullDescription": { + "text": "Scalar calculations are faster than vector calculations." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0024.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "0.003", + "executionTimeInPercentage": "2" + } + }, + { + "id": "UNT0025", + "shortDescription": { + "text": "Input.GetKey overloads with KeyCode argument" + }, + "fullDescription": { + "text": "Usage of the method overload with KeyCode argument is preferred." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0025.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0026", + "shortDescription": { + "text": "GetComponent always allocates" + }, + "fullDescription": { + "text": "TryGetComponent will not allocate memory in case it fails." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0026.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0027", + "shortDescription": { + "text": "Do not call PropertyDrawer.OnGUI()" + }, + "fullDescription": { + "text": "Default implementation for PropertyDrawer.OnGUI() will display \"no GUI implemented\" in the inspector." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0027.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0028", + "shortDescription": { + "text": "Use non-allocating physics APIs" + }, + "fullDescription": { + "text": "Avoid using allocating versions of Physics functions." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0028.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "0.041", + "executionTimeInPercentage": "37" + } + }, + { + "id": "UNT0029", + "shortDescription": { + "text": "Pattern matching with null on Unity objects" + }, + "fullDescription": { + "text": "Unity overrides the null comparison operator for Unity objects, which is incompatible with pattern matching with null." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0029.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.002", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0030", + "shortDescription": { + "text": "Calling Destroy or DestroyImmediate on a Transform" + }, + "fullDescription": { + "text": "You cannot destroy a Transform component of a GameObject, but you can destroy the whole GameObject." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0030.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.002", + "executionTimeInPercentage": "1" + } + }, + { + "id": "UNT0031", + "shortDescription": { + "text": "Asset operations in LoadAttribute method" + }, + "fullDescription": { + "text": "Asset operations such as asset loading should be avoided in LoadAttribute method." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0031.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0032", + "shortDescription": { + "text": "Inefficient localPosition/localRotation assignment" + }, + "fullDescription": { + "text": "Prefer using SetLocalPositionAndRotation() method." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0032.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0033", + "shortDescription": { + "text": "Incorrect message case" + }, + "fullDescription": { + "text": "This Unity message uses an incorrect method case" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0033.md", + "properties": { + "category": "Correctness", + "executionTimeInSeconds": "0.004", + "executionTimeInPercentage": "4" + } + }, + { + "id": "UNT0034", + "shortDescription": { + "text": "A Vector3 can be converted into a Vector2." + }, + "fullDescription": { + "text": "A Vector3 can be converted into a Vector2. (The z is discarded)." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0034.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + }, + { + "id": "UNT0035", + "shortDescription": { + "text": "A Vector3 can be converted into a Vector2." + }, + "fullDescription": { + "text": "A Vector3 can be converted into a Vector2. (The z is discarded)." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0035.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "0.003", + "executionTimeInPercentage": "2" + } + }, + { + "id": "UNT0036", + "shortDescription": { + "text": "Inefficient position/rotation read" + }, + "fullDescription": { + "text": "Prefer using GetPositionAndRotation() method." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0036.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "0.004", + "executionTimeInPercentage": "3" + } + }, + { + "id": "UNT0037", + "shortDescription": { + "text": "Inefficient localPosition/localRotation read" + }, + "fullDescription": { + "text": "Prefer using GetLocalPositionAndRotation() method." + }, + "defaultConfiguration": { + "level": "note" + }, + "helpUri": "https://github.com/microsoft/Microsoft.Unity.Analyzers/blob/main/doc/UNT0037.md", + "properties": { + "category": "Performance", + "executionTimeInSeconds": "<0.001", + "executionTimeInPercentage": "<1" + } + } + ] + } + }, + "columnKind": "utf16CodeUnits" + } + ] +} \ No newline at end of file diff --git a/games/unity/.unity-analyzers/build-output.txt b/games/unity/.unity-analyzers/build-output.txt new file mode 100644 index 0000000..85fac0e --- /dev/null +++ b/games/unity/.unity-analyzers/build-output.txt @@ -0,0 +1,7 @@ + UnityAnalyzer -> /home/kuchy/praca_magisterska/games/unity/.unity-analyzers/bin/Debug/netstandard2.1/UnityAnalyzer.dll + +Build succeeded. + 0 Warning(s) + 0 Error(s) + +Time Elapsed 00:00:01.94 diff --git a/games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.dgspec.json b/games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.dgspec.json new file mode 100644 index 0000000..5ab8f82 --- /dev/null +++ b/games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.dgspec.json @@ -0,0 +1,75 @@ +{ + "format": 1, + "restore": { + "/home/kuchy/praca_magisterska/games/unity/.unity-analyzers/UnityAnalyzer.csproj": {} + }, + "projects": { + "/home/kuchy/praca_magisterska/games/unity/.unity-analyzers/UnityAnalyzer.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/home/kuchy/praca_magisterska/games/unity/.unity-analyzers/UnityAnalyzer.csproj", + "projectName": "UnityAnalyzer", + "projectPath": "/home/kuchy/praca_magisterska/games/unity/.unity-analyzers/UnityAnalyzer.csproj", + "packagesPath": "/home/kuchy/.nuget/packages/", + "outputPath": "/home/kuchy/praca_magisterska/games/unity/.unity-analyzers/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/home/kuchy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "netstandard2.1" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "netstandard2.1": { + "targetAlias": "netstandard2.1", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "netstandard2.1": { + "targetAlias": "netstandard2.1", + "dependencies": { + "Microsoft.Unity.Analyzers": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers", + "suppressParent": "All", + "target": "Package", + "version": "[1.19.0, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "NETStandard.Library": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/10.0.100/RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.g.props b/games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.g.props new file mode 100644 index 0000000..05caa03 --- /dev/null +++ b/games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.g.props @@ -0,0 +1,18 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /home/kuchy/.nuget/packages/ + /home/kuchy/.nuget/packages/ + PackageReference + 7.0.0 + + + + + + /home/kuchy/.nuget/packages/microsoft.unity.analyzers/1.19.0 + + \ No newline at end of file diff --git a/games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.g.targets b/games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/games/unity/.unity-analyzers/obj/UnityAnalyzer.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/games/unity/.unity-analyzers/obj/project.assets.json b/games/unity/.unity-analyzers/obj/project.assets.json new file mode 100644 index 0000000..80de9af --- /dev/null +++ b/games/unity/.unity-analyzers/obj/project.assets.json @@ -0,0 +1,102 @@ +{ + "version": 3, + "targets": { + ".NETStandard,Version=v2.1": { + "Microsoft.Unity.Analyzers/1.19.0": { + "type": "package" + } + } + }, + "libraries": { + "Microsoft.Unity.Analyzers/1.19.0": { + "sha512": "QpHY0CSN7Aw/E4DAXgr8zqSnC7CTS+ikuUT2C/ynOnkZg4ZsOGEz1m2i4Wpfcp6axYBZji6hF/0bdnaTLp2qTg==", + "type": "package", + "path": "microsoft.unity.analyzers/1.19.0", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "analyzers/dotnet/cs/Microsoft.Unity.Analyzers.dll", + "microsoft.unity.analyzers.1.19.0.nupkg.sha512", + "microsoft.unity.analyzers.nuspec", + "tools/install.ps1", + "tools/uninstall.ps1" + ] + } + }, + "projectFileDependencyGroups": { + ".NETStandard,Version=v2.1": [ + "Microsoft.Unity.Analyzers >= 1.19.0" + ] + }, + "packageFolders": { + "/home/kuchy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/home/kuchy/praca_magisterska/games/unity/.unity-analyzers/UnityAnalyzer.csproj", + "projectName": "UnityAnalyzer", + "projectPath": "/home/kuchy/praca_magisterska/games/unity/.unity-analyzers/UnityAnalyzer.csproj", + "packagesPath": "/home/kuchy/.nuget/packages/", + "outputPath": "/home/kuchy/praca_magisterska/games/unity/.unity-analyzers/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/home/kuchy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "netstandard2.1" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "netstandard2.1": { + "targetAlias": "netstandard2.1", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.100" + }, + "frameworks": { + "netstandard2.1": { + "targetAlias": "netstandard2.1", + "dependencies": { + "Microsoft.Unity.Analyzers": { + "include": "Runtime, Build, Native, ContentFiles, Analyzers", + "suppressParent": "All", + "target": "Package", + "version": "[1.19.0, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "NETStandard.Library": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/10.0.100/RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/games/unity/.unity-analyzers/obj/project.nuget.cache b/games/unity/.unity-analyzers/obj/project.nuget.cache new file mode 100644 index 0000000..b6f7f37 --- /dev/null +++ b/games/unity/.unity-analyzers/obj/project.nuget.cache @@ -0,0 +1,10 @@ +{ + "version": 2, + "dgSpecHash": "67thBlp2R2E=", + "success": true, + "projectFilePath": "/home/kuchy/praca_magisterska/games/unity/.unity-analyzers/UnityAnalyzer.csproj", + "expectedPackageFiles": [ + "/home/kuchy/.nuget/packages/microsoft.unity.analyzers/1.19.0/microsoft.unity.analyzers.1.19.0.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/games/unity/analyze_unity_project.sh b/games/unity/analyze_unity_project.sh new file mode 100755 index 0000000..3415e04 --- /dev/null +++ b/games/unity/analyze_unity_project.sh @@ -0,0 +1,518 @@ +#!/bin/bash +# +# Unity Project Static Code Analyzer +# Uses Microsoft.Unity.Analyzers for Unity-specific checks +# +# Usage: ./analyze_unity_project.sh [path_to_unity_project] +# + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_PATH="${1:-$SCRIPT_DIR/magisterka_1}" +ANALYZER_VERSION="1.19.0" +TOOLS_DIR="$SCRIPT_DIR/.unity-analyzers" + +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE} Unity Project Static Code Analyzer${NC}" +echo -e "${BLUE}========================================${NC}" +echo "" + +# ============================================ +# Step 1: Check prerequisites +# ============================================ +echo -e "${YELLOW}[1/5] Checking prerequisites...${NC}" + +# Check if .NET SDK is installed +if ! command -v dotnet &> /dev/null; then + echo -e "${RED}ERROR: .NET SDK is not installed.${NC}" + echo "" + echo "Install .NET SDK using one of these methods:" + echo "" + echo " Ubuntu/Debian:" + echo " sudo apt-get update && sudo apt-get install -y dotnet-sdk-8.0" + echo "" + echo " Fedora:" + echo " sudo dnf install dotnet-sdk-8.0" + echo "" + echo " Arch Linux:" + echo " sudo pacman -S dotnet-sdk" + echo "" + echo " Or download from: https://dotnet.microsoft.com/download" + exit 1 +fi + +DOTNET_VERSION=$(dotnet --version) +echo -e " ${GREEN}✓${NC} .NET SDK found: $DOTNET_VERSION" + +# Check if project path exists +if [ ! -d "$PROJECT_PATH" ]; then + echo -e "${RED}ERROR: Unity project not found at: $PROJECT_PATH${NC}" + echo "Usage: $0 [path_to_unity_project]" + exit 1 +fi + +# Check if it's a Unity project (has Assets folder) +if [ ! -d "$PROJECT_PATH/Assets" ]; then + echo -e "${RED}ERROR: Not a valid Unity project (no Assets folder found)${NC}" + exit 1 +fi + +# Get absolute path +PROJECT_PATH=$(cd "$PROJECT_PATH" && pwd) +echo -e " ${GREEN}✓${NC} Unity project found: $PROJECT_PATH" + +# ============================================ +# Step 2: Create analyzer project with Unity stubs +# ============================================ +echo "" +echo -e "${YELLOW}[2/5] Setting up analyzer environment...${NC}" + +mkdir -p "$TOOLS_DIR" + +# Create Unity stub file that provides minimal definitions for compilation +cat > "$TOOLS_DIR/UnityStubs.cs" << 'STUBEOF' +// Unity API Stubs for static analysis +// These provide minimal type definitions so the analyzer can check code +// without needing actual Unity assemblies + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace UnityEngine +{ + public class Object { + public string name; + public static void Destroy(Object obj) { } + public static void DontDestroyOnLoad(Object target) { } + public static T FindObjectOfType() where T : Object => default; + public static T[] FindObjectsOfType() where T : Object => default; + public static T Instantiate(T original) where T : Object => default; + public static T Instantiate(T original, Vector3 position, Quaternion rotation) where T : Object => default; + } + + public class Component : Object { + public GameObject gameObject; + public Transform transform; + public T GetComponent() => default; + public T[] GetComponents() => default; + public T GetComponentInChildren() => default; + public T GetComponentInParent() => default; + } + + public class Behaviour : Component { public bool enabled; public bool isActiveAndEnabled; } + public class MonoBehaviour : Behaviour { + protected void Invoke(string methodName, float time) { } + protected void CancelInvoke() { } + protected void CancelInvoke(string methodName) { } + protected Coroutine StartCoroutine(IEnumerator routine) => null; + protected Coroutine StartCoroutine(string methodName) => null; + protected void StopCoroutine(Coroutine routine) { } + protected void StopAllCoroutines() { } + } + public class ScriptableObject : Object { } + + public class GameObject : Object { + public Transform transform; + public bool activeSelf; + public bool activeInHierarchy; + public GameObject() { } + public GameObject(string name) { } + public T GetComponent() => default; + public T AddComponent() where T : Component => default; + public void SetActive(bool value) { } + } + + public class Transform : Component, IEnumerable { + public Vector3 position; + public Vector3 localPosition; + public Quaternion rotation; + public Quaternion localRotation; + public Vector3 localScale; + public Transform parent; + public int childCount; + public void SetParent(Transform parent) { } + public Transform GetChild(int index) => default; + public IEnumerator GetEnumerator() => null; + } + + public struct Vector2 { + public float x, y; + public Vector2(float x, float y) { this.x = x; this.y = y; } + public static Vector2 up => new Vector2(0, 1); + public static Vector2 down => new Vector2(0, -1); + public static Vector2 left => new Vector2(-1, 0); + public static Vector2 right => new Vector2(1, 0); + public static Vector2 zero => new Vector2(0, 0); + public static Vector2 one => new Vector2(1, 1); + public Vector2 normalized => this; + public float magnitude => 0; + public float sqrMagnitude => 0; + public static Vector2 operator +(Vector2 a, Vector2 b) => default; + public static Vector2 operator -(Vector2 a, Vector2 b) => default; + public static Vector2 operator *(Vector2 a, float d) => default; + public static Vector2 operator *(float d, Vector2 a) => default; + public static implicit operator Vector3(Vector2 v) => default; + } + + public struct Vector3 { + public float x, y, z; + public Vector3(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } + public static Vector3 up => new Vector3(0, 1, 0); + public static Vector3 down => new Vector3(0, -1, 0); + public static Vector3 forward => new Vector3(0, 0, 1); + public static Vector3 back => new Vector3(0, 0, -1); + public static Vector3 left => new Vector3(-1, 0, 0); + public static Vector3 right => new Vector3(1, 0, 0); + public static Vector3 zero => new Vector3(0, 0, 0); + public static Vector3 one => new Vector3(1, 1, 1); + public Vector3 normalized => this; + public static Vector3 operator +(Vector3 a, Vector3 b) => default; + public static Vector3 operator -(Vector3 a, Vector3 b) => default; + public static Vector3 operator *(Vector3 a, float d) => default; + public static Vector3 operator *(float d, Vector3 a) => default; + public static implicit operator Vector2(Vector3 v) => default; + } + + public struct Quaternion { + public float x, y, z, w; + public static Quaternion identity => default; + public static Quaternion Euler(float x, float y, float z) => default; + public static Vector3 operator *(Quaternion rotation, Vector3 point) => default; + } + + public struct Color { + public float r, g, b, a; + public Color(float r, float g, float b, float a = 1f) { this.r = r; this.g = g; this.b = b; this.a = a; } + public static Color white => new Color(1, 1, 1); + public static Color black => new Color(0, 0, 0); + public static Color red => new Color(1, 0, 0); + public static Color green => new Color(0, 1, 0); + public static Color blue => new Color(0, 0, 1); + } + + public struct Rect { public float x, y, width, height; } + + public class Collider : Component { } + public class Collider2D : Component { public new T GetComponent() => default; } + public class BoxCollider2D : Collider2D { } + public class CircleCollider2D : Collider2D { } + public class Rigidbody : Component { } + public class Rigidbody2D : Component { } + + public class SpriteRenderer : Component { public Sprite sprite; public Color color; } + public class Sprite : Object { } + + public static class Time { + public static float time => 0; + public static float deltaTime => 0; + public static float fixedDeltaTime => 0; + public static float unscaledDeltaTime => 0; + public static float timeScale { get; set; } + } + + public static class Input { + public static float GetAxis(string axisName) => 0; + public static float GetAxisRaw(string axisName) => 0; + public static bool GetKey(KeyCode key) => false; + public static bool GetKeyDown(KeyCode key) => false; + public static bool GetKeyUp(KeyCode key) => false; + public static bool GetMouseButton(int button) => false; + public static bool GetMouseButtonDown(int button) => false; + public static bool GetMouseButtonUp(int button) => false; + public static Vector3 mousePosition => default; + } + + public enum KeyCode { + None, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, + Alpha0, Alpha1, Alpha2, Alpha3, Alpha4, Alpha5, Alpha6, Alpha7, Alpha8, Alpha9, + Space, Return, Escape, Tab, LeftShift, RightShift, LeftControl, RightControl, + UpArrow, DownArrow, LeftArrow, RightArrow + } + + public static class Mathf { + public const float PI = 3.14159265f; + public static float Abs(float f) => f < 0 ? -f : f; + public static float Sin(float f) => 0; + public static float Cos(float f) => 0; + public static float Sqrt(float f) => 0; + public static float Clamp(float value, float min, float max) => value; + public static float Clamp01(float value) => value; + public static int Clamp(int value, int min, int max) => value; + public static float Max(float a, float b) => a > b ? a : b; + public static float Min(float a, float b) => a < b ? a : b; + public static int Max(int a, int b) => a > b ? a : b; + public static int Min(int a, int b) => a < b ? a : b; + public static int FloorToInt(float f) => (int)f; + public static int RoundToInt(float f) => (int)f; + public static float Repeat(float t, float length) => t; + } + + public static class Random { + public static float Range(float min, float max) => min; + public static int Range(int min, int max) => min; + public static float value => 0; + } + + public static class Debug { + public static void Log(object message) { } + public static void LogWarning(object message) { } + public static void LogError(object message) { } + } + + public static class Resources { + public static T Load(string path) where T : Object => default; + public static T GetBuiltinResource(string path) where T : Object => default; + } + + public class WaitForSeconds : YieldInstruction { + public WaitForSeconds(float seconds) { } + } + public class YieldInstruction { } + public class Coroutine : YieldInstruction { } + + public class AnimationCurve { + public float Evaluate(float time) => 0; + public static AnimationCurve Linear(float timeStart, float valueStart, float timeEnd, float valueEnd) => new AnimationCurve(); + } + + [AttributeUsage(AttributeTargets.Field)] + public class SerializeField : Attribute { } + [AttributeUsage(AttributeTargets.Field)] + public class HideInInspector : Attribute { } + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Class)] + public class HeaderAttribute : Attribute { public HeaderAttribute(string header) { } } + [AttributeUsage(AttributeTargets.Field)] + public class RangeAttribute : Attribute { public RangeAttribute(float min, float max) { } } + [AttributeUsage(AttributeTargets.Class)] + public class RequireComponent : Attribute { public RequireComponent(Type type) { } } + [AttributeUsage(AttributeTargets.Method)] + public class RuntimeInitializeOnLoadMethodAttribute : Attribute { + public RuntimeInitializeOnLoadMethodAttribute() { } + public RuntimeInitializeOnLoadMethodAttribute(RuntimeInitializeLoadType loadType) { } + } + public enum RuntimeInitializeLoadType { AfterSceneLoad, BeforeSceneLoad, AfterAssembliesLoaded, BeforeSplashScreen, SubsystemRegistration } + + public class Camera : Behaviour { + public static Camera main => null; + public float orthographicSize; + public float fieldOfView; + public float aspect; + public Vector3 ScreenToWorldPoint(Vector3 position) => default; + public Vector3 WorldToScreenPoint(Vector3 position) => default; + public Ray ScreenPointToRay(Vector3 pos) => default; + } + public struct Ray { public Vector3 origin; public Vector3 direction; } + + public class Canvas : Behaviour { + public RenderMode renderMode; + } + public enum RenderMode { ScreenSpaceOverlay, ScreenSpaceCamera, WorldSpace } + public class CanvasScaler : Component { } + public class GraphicRaycaster : Component { } + public class RectTransform : Transform { + public Vector2 anchorMin; + public Vector2 anchorMax; + public Vector2 pivot; + public Vector2 anchoredPosition; + public Vector2 sizeDelta; + } + + public class Font : Object { } +} + +namespace UnityEngine.UI +{ + public class Text : UnityEngine.Behaviour { + public string text; + public UnityEngine.Font font; + public int fontSize; + public UnityEngine.Color color; + public TextAnchor alignment; + public HorizontalWrapMode horizontalOverflow; + } + public enum TextAnchor { UpperLeft, UpperCenter, UpperRight, MiddleLeft, MiddleCenter, MiddleRight, LowerLeft, LowerCenter, LowerRight } + public enum HorizontalWrapMode { Wrap, Overflow } + public class Image : UnityEngine.Behaviour { } + public class Button : UnityEngine.Behaviour { } + public class Graphic : UnityEngine.Behaviour { } +} +STUBEOF + +echo -e " ${GREEN}✓${NC} Unity stubs created" + +# ============================================ +# Step 3: Collect C# source files +# ============================================ +echo "" +echo -e "${YELLOW}[3/5] Collecting C# source files...${NC}" + +# Find all .cs files in Assets folder (excluding generated/editor scripts if needed) +CS_FILES=$(find "$PROJECT_PATH/Assets" -name "*.cs" -type f ! -path "*/Editor/*" 2>/dev/null) +CS_COUNT=$(echo "$CS_FILES" | grep -c "\.cs$" || echo "0") + +if [ "$CS_COUNT" -eq 0 ]; then + echo -e "${RED}ERROR: No C# files found in $PROJECT_PATH/Assets${NC}" + exit 1 +fi + +echo -e " ${GREEN}✓${NC} Found $CS_COUNT C# files" + +# List the files being analyzed +echo -e " Files to analyze:" +echo "$CS_FILES" | while read -r file; do + echo -e " - $(basename "$file")" +done + +# Create project file with source files +cat > "$TOOLS_DIR/UnityAnalyzer.csproj" << EOF + + + netstandard2.1 + 9.0 + disable + false + + CS0649;CS0414;CS0169;CS0067;CS8618;CS0626;CS0108 + false + + $TOOLS_DIR/analysis-results.sarif,version=2.1 + + + + + + all + runtime; build; native; contentfiles; analyzers + + + + + + + + + + +EOF + +echo "$CS_FILES" | while read -r file; do + if [ -n "$file" ]; then + echo " " >> "$TOOLS_DIR/UnityAnalyzer.csproj" + fi +done + +cat >> "$TOOLS_DIR/UnityAnalyzer.csproj" << 'EOF' + + +EOF + +# ============================================ +# Step 4: Restore packages and run analysis +# ============================================ +echo "" +echo -e "${YELLOW}[4/5] Running static analysis...${NC}" +echo -e " (This may take a moment on first run while downloading packages)" +echo "" + +cd "$TOOLS_DIR" + +# Restore packages +dotnet restore --verbosity quiet 2>/dev/null || true + +# Run build (which triggers analyzers) +BUILD_OUTPUT="$TOOLS_DIR/build-output.txt" +dotnet build --no-restore /p:TreatWarningsAsErrors=false 2>&1 | tee "$BUILD_OUTPUT" + +# ============================================ +# Step 5: Parse and display results +# ============================================ +echo "" +echo -e "${YELLOW}[5/5] Analysis Results${NC}" +echo -e "${BLUE}========================================${NC}" + +# Count different types of diagnostics +UNITY_WARNINGS=$(grep -oE "UNT[0-9]{4}" "$BUILD_OUTPUT" | wc -l || echo "0") +CS_WARNINGS=$(grep -E "warning CS[0-9]{4}" "$BUILD_OUTPUT" | wc -l || echo "0") +CS_ERRORS=$(grep -E "error CS[0-9]{4}" "$BUILD_OUTPUT" | wc -l || echo "0") + +echo "" +echo -e "${BLUE}Summary:${NC}" +echo -e " Unity-specific issues (UNT*): ${YELLOW}$UNITY_WARNINGS${NC}" +echo -e " C# warnings (CS*): ${YELLOW}$CS_WARNINGS${NC}" +echo -e " C# errors (CS*): ${RED}$CS_ERRORS${NC}" +echo "" + +# Show Unity-specific diagnostics in detail +if [ "$UNITY_WARNINGS" -gt 0 ]; then + echo -e "${BLUE}Unity-Specific Diagnostics Found:${NC}" + echo -e "${BLUE}----------------------------------------${NC}" + grep -E "UNT[0-9]{4}" "$BUILD_OUTPUT" | sort -u | while read -r line; do + echo -e " ${YELLOW}→${NC} $line" + done + echo "" +fi + +# Show any real C# errors (not from stubs) +if grep -q "error CS" "$BUILD_OUTPUT"; then + REAL_ERRORS=$(grep "error CS" "$BUILD_OUTPUT" | grep -v "UnityStubs.cs" || true) + if [ -n "$REAL_ERRORS" ]; then + echo -e "${RED}C# Errors Found:${NC}" + echo "$REAL_ERRORS" | head -20 + echo "" + fi +fi + +# Common Unity Analyzer diagnostic codes reference +echo -e "${BLUE}Common Unity Analyzer Codes Reference:${NC}" +echo " UNT0001: Empty Unity message (Update, Start, etc.)" +echo " UNT0002: Inefficient tag comparison" +echo " UNT0003: Incorrect usage of GetComponent" +echo " UNT0004: Time.fixedDeltaTime used in Update" +echo " UNT0005: Time.deltaTime used in FixedUpdate" +echo " UNT0006: Incorrect message signature" +echo " UNT0007: Null propagation on Unity objects" +echo " UNT0008: Null coalescing on Unity objects" +echo " UNT0009: Missing static constructor for InitializeOnLoad" +echo " UNT0010: Component instance creation (use AddComponent)" +echo " UNT0011: ScriptableObject instance creation (use CreateInstance)" +echo " UNT0012: Unused coroutine return value" +echo " UNT0013: Invalid SerializeField attribute" +echo " UNT0014: GetComponent with non-Component type" +echo " UNT0015: Incorrect method signature with ContextMenu" +echo " UNT0016: Unsafe way to get position/rotation" +echo " UNT0017: SetPixels invocation" +echo " UNT0018: System.Reflection features" +echo " UNT0019: Indirect calling of SendMessage" +echo " UNT0020: MenuItem with invalid static method" +echo " UNT0021: OnGUI allocation" +echo " UNT0022: Inefficient position/rotation multiplication" +echo " UNT0023: Coalescing assignment on Unity objects" +echo " UNT0024: Obsolete Unity methods" +echo " UNT0025: Input.GetKey in MonoBehaviour FixedUpdate" +echo " UNT0026: GetComponent always allocates" +echo "" + +# Output file locations +echo -e "${GREEN}Analysis complete!${NC}" +echo "" +echo "Output files:" +echo " Build log: $BUILD_OUTPUT" +if [ -f "$TOOLS_DIR/analysis-results.sarif" ]; then + echo " SARIF report: $TOOLS_DIR/analysis-results.sarif" +fi +echo "" +echo -e "${BLUE}========================================${NC}" +echo -e "${BLUE}Tip: For IDE integration in Unity:${NC}" +echo " 1. Open Unity project, then open any .cs file in VS/Rider" +echo " 2. Analyzers auto-run via com.unity.ide.visualstudio package" +echo " 3. Or manually add Microsoft.Unity.Analyzers NuGet to .csproj" +echo -e "${BLUE}========================================${NC}" diff --git a/games/unity/magisterka_1/Directory.Build.props b/games/unity/magisterka_1/Directory.Build.props new file mode 100644 index 0000000..6c57de7 --- /dev/null +++ b/games/unity/magisterka_1/Directory.Build.props @@ -0,0 +1,8 @@ + + + + all + runtime; build; native; contentfiles; analyzers + + + diff --git a/games/unity/magisterka_1/omnisharp.json b/games/unity/magisterka_1/omnisharp.json new file mode 100644 index 0000000..d308d74 --- /dev/null +++ b/games/unity/magisterka_1/omnisharp.json @@ -0,0 +1,8 @@ +{ + "RoslynExtensionsOptions": { + "EnableAnalyzersSupport": true + }, + "FormattingOptions": { + "EnableEditorConfigSupport": true + } +} diff --git a/magisterka_2/Assets/Scripts/Bullet.cs b/magisterka_2/Assets/Scripts/Bullet.cs index dbf8644..e5a5aaf 100644 --- a/magisterka_2/Assets/Scripts/Bullet.cs +++ b/magisterka_2/Assets/Scripts/Bullet.cs @@ -112,7 +112,10 @@ namespace Magisterka.BulletHell public void Despawn() { - _ownerPool?.Return(this); + if (_ownerPool != null) + { + _ownerPool.Return(this); + } } private static Sprite GetOrCreateSprite(Color tint) diff --git a/magisterka_2/Assets/Scripts/EffectManager.cs b/magisterka_2/Assets/Scripts/EffectManager.cs index 1d10a3d..bdecbf7 100644 --- a/magisterka_2/Assets/Scripts/EffectManager.cs +++ b/magisterka_2/Assets/Scripts/EffectManager.cs @@ -86,12 +86,18 @@ namespace Magisterka.BulletHell PlayPulse(position, color, start, end, duration); } - _cameraShaker?.Shake(0.4f, 1.2f * radius); + if (_cameraShaker != null) + { + _cameraShaker.Shake(0.4f, 1.2f * radius); + } } public void ShakeCamera(float duration, float strength) { - _cameraShaker?.Shake(duration, strength); + if (_cameraShaker != null) + { + _cameraShaker.Shake(duration, strength); + } } private void Warmup(int count) diff --git a/magisterka_2/Assets/Scripts/EffectPulse.cs b/magisterka_2/Assets/Scripts/EffectPulse.cs index 75de763..4111be5 100644 --- a/magisterka_2/Assets/Scripts/EffectPulse.cs +++ b/magisterka_2/Assets/Scripts/EffectPulse.cs @@ -70,7 +70,10 @@ namespace Magisterka.BulletHell _isActive = false; gameObject.SetActive(false); - _onComplete?.Invoke(this); + if (_onComplete != null) + { + _onComplete.Invoke(this); + } } private static Sprite BuildPulseSprite() diff --git a/magisterka_2/Assets/Scripts/EnemyController.cs b/magisterka_2/Assets/Scripts/EnemyController.cs index e2d8104..9b4ed5a 100644 --- a/magisterka_2/Assets/Scripts/EnemyController.cs +++ b/magisterka_2/Assets/Scripts/EnemyController.cs @@ -54,7 +54,10 @@ namespace Magisterka.BulletHell float bottomLimit = -_worldBounds.y - despawnPadding; if (transform.position.y < bottomLimit) { - _spawner?.DespawnEnemy(this); + if (_spawner != null) + { + _spawner.DespawnEnemy(this); + } } } @@ -190,9 +193,18 @@ namespace Magisterka.BulletHell private void HandleDeath(Health _) { - EffectManager.Instance?.SpawnExplosion(transform.position, Faction.Enemy, 2.6f + _difficulty * 0.2f); - ScoreManager.Instance?.AddScore(_config.Score + Mathf.RoundToInt(_difficulty * 20f)); - _spawner?.NotifyEnemyKilled(this); + if (EffectManager.Instance != null) + { + EffectManager.Instance.SpawnExplosion(transform.position, Faction.Enemy, 2.6f + _difficulty * 0.2f); + } + if (ScoreManager.Instance != null) + { + ScoreManager.Instance.AddScore(_config.Score + Mathf.RoundToInt(_difficulty * 20f)); + } + if (_spawner != null) + { + _spawner.NotifyEnemyKilled(this); + } Destroy(gameObject); } @@ -204,8 +216,14 @@ namespace Magisterka.BulletHell } player.ApplyDamage(Mathf.Max(10f, _config.ContactDamage)); - EffectManager.Instance?.SpawnHitEffect(player.transform.position, Faction.Player, 0.9f); - _health?.Kill(); + if (EffectManager.Instance != null) + { + EffectManager.Instance.SpawnHitEffect(player.transform.position, Faction.Player, 0.9f); + } + if (_health != null) + { + _health.Kill(); + } } private void OnDestroy() diff --git a/magisterka_2/Directory.Build.props b/magisterka_2/Directory.Build.props new file mode 100644 index 0000000..6c57de7 --- /dev/null +++ b/magisterka_2/Directory.Build.props @@ -0,0 +1,8 @@ + + + + all + runtime; build; native; contentfiles; analyzers + + + diff --git a/magisterka_2/omnisharp.json b/magisterka_2/omnisharp.json new file mode 100644 index 0000000..d308d74 --- /dev/null +++ b/magisterka_2/omnisharp.json @@ -0,0 +1,8 @@ +{ + "RoslynExtensionsOptions": { + "EnableAnalyzersSupport": true + }, + "FormattingOptions": { + "EnableEditorConfigSupport": true + } +}