Skip to content

Commit

Permalink
Fix #303
Browse files Browse the repository at this point in the history
- Completely review the way of how the preview icon is releasing the
resources.
- Never ever release resources from the finalizer! Unity will just
crash, it won't politely report the mistake.
  • Loading branch information
ihsoft committed Feb 1, 2019
1 parent 8927ea5 commit 993d76d
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 42 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,7 @@
* [Fix #301] "volumeOverride" is not working .
* [Fix #297] IMC-15K has wrong part volume.
* [Fix #302] Structurel panel has wrong nodes.
* [Fix #303] Game's crashing on the new parts.

# 1.17 (January 28th, 2019):
* KSP 1.6 support. This mod's version is not compatible with the prior versions of KSP!
Expand Down
101 changes: 59 additions & 42 deletions Source/KIS_IconViewer.cs
@@ -1,25 +1,27 @@
using KISAPIv1;
using KSPDev.LogUtils;
using KSPDev.PartUtils;
using System;
using System.Linq;
using UnityEngine;

namespace KIS {

public sealed class KIS_IconViewer : IDisposable {
public sealed class KIS_IconViewer {
const float IconPosY = 0;
const int CameraLayer = 22;
const float LightIntensity = 0.4f;
const float CameraZoom = 0.75f;
const float RotationsPerSecond = 0.20f; // Full round in 5 seconds.

Camera camera;
int cameraShift;
float cameraShift;
GameObject iconPrefab;
bool disposed;

static Light iconLight;
static int cameraGlobalShift;
static int iconCount;
static float globalCameraShift;

public Texture texture { get; private set; }

Expand All @@ -29,39 +31,45 @@ public sealed class KIS_IconViewer : IDisposable {
} else {
MakePartIcon(part.partInfo, resolution, VariantsUtils.GetCurrentPartVariant(part));
}
iconCount += 1;
}

public KIS_IconViewer(AvailablePart avPart, int resolution, PartVariant variant) {
MakePartIcon(avPart, resolution, variant);
iconCount += 1;
}

/// <summary>Warns if the icon is not disposed properly.</summary>
/// <remarks>
/// This method cannot release the Unity resources since teh access to them is only allowed from
/// the Unity main thread. The best thing this method can do is spamming log errors.
/// </remarks>
~KIS_IconViewer() {
if (camera != null) {
Dispose();
if (!disposed) {
DebugEx.Error("RESOURCES LEAK! The IconViewer was not disposed: camera={0}, iconPrefab={1}",
camera, iconPrefab);
}
}

/// <summary>Releases all the used resources.</summary>
/// <remarks>
/// This method <i>must</i> be called if an icon becomes unusable. Otherwise, all the cached Unity
/// objects will live and take memory till the scene is reloaded. Some of the internal counters
/// will also not get updated as expected. Simply put, jut call it!
/// <para>It's safe to call this method multiple times.</para>
/// </remarks>
public void Dispose() {
if (!disposed) {
if (camera != null) {
UnityEngine.Object.Destroy(camera.gameObject);
}
if (iconPrefab != null) {
UnityEngine.Object.Destroy(iconPrefab);
}
ReleaseCameraSpot();

// The Dispose() method MUST be called instead of garbage-collecting icon instances
// because we can only access the cam.gameObject member from the main thread.
public void Dispose()
{
if (camera != null) {
UnityEngine.Object.DestroyImmediate(camera.gameObject);
camera = null;
}
if (iconPrefab != null) {
UnityEngine.Object.DestroyImmediate(iconPrefab);
iconPrefab = null;
}
if (texture != null) {
(texture as RenderTexture).Release();
texture = null;
}
iconCount -= 1;
if (iconCount == 0) {
cameraGlobalShift = 0;
disposed = true;
}
}

Expand All @@ -78,10 +86,6 @@ public void Dispose()
camera.Render(); // Update snapshot.
}

static void ResetCamIndex() {
cameraGlobalShift = 0;
}

#region Local utility methods
void SetLayerRecursively(GameObject obj, int newLayer) {
if (null == obj) {
Expand All @@ -98,7 +102,8 @@ public void Dispose()

void MakeKerbalAvatar(Part ownerPart, int resolution) {
// Icon Camera
GameObject camGo = new GameObject("KASCamItem" + cameraGlobalShift);
cameraShift = ReserveCameraSpot();
GameObject camGo = new GameObject("KASCamItem" + cameraShift);
camGo.transform.parent = ownerPart.transform;
camGo.transform.localPosition = Vector3.zero + new Vector3(0, 0.35f, 0.7f);
camGo.transform.localRotation = Quaternion.identity;
Expand Down Expand Up @@ -134,8 +139,9 @@ public void Dispose()
}

// Icon Camera
GameObject camGo = new GameObject("KASCamItem" + cameraGlobalShift);
camGo.transform.position = new Vector3(cameraGlobalShift, IconPosY, 0);
cameraShift = ReserveCameraSpot();
GameObject camGo = new GameObject("KASCamItem" + cameraShift);
camGo.transform.position = new Vector3(cameraShift, IconPosY, 0);
camGo.transform.rotation = Quaternion.identity;
camera = camGo.AddComponent<Camera>();
camera.orthographic = true;
Expand All @@ -146,6 +152,25 @@ public void Dispose()
RenderTexture tex = new RenderTexture(resolution, resolution, 8);
texture = tex;

// Layer
camera.cullingMask = 1 << CameraLayer;
SetLayerRecursively(iconPrefab, CameraLayer);

// Texture
camera.targetTexture = tex;
camera.ResetAspect();

ResetPos();
}

void ReleaseCameraSpot() {
if (--iconCount == 0) {
globalCameraShift = 0;
DebugEx.Fine("Icon camera global shift is reset to zero");
}
}

float ReserveCameraSpot() {
//light
if (iconLight == null && HighLogic.LoadedSceneIsFlight) {
GameObject lightGo = new GameObject("KASLight");
Expand All @@ -157,18 +182,10 @@ public void Dispose()
iconLight.renderMode = LightRenderMode.ForcePixel;
}

// Layer
camera.cullingMask = 1 << CameraLayer;
SetLayerRecursively(iconPrefab, CameraLayer);

// Texture
camera.targetTexture = tex;
camera.ResetAspect();

// Cam index
cameraShift = cameraGlobalShift;
cameraGlobalShift += 2;
ResetPos();
iconCount++;
globalCameraShift += 2.0f;

return globalCameraShift;
}
#endregion
}
Expand Down
1 change: 1 addition & 0 deletions Source/ModuleKISInventory.cs
Expand Up @@ -868,6 +868,7 @@ public enum InventoryType {
GameEvents.OnHelmetChanged.Remove(OnHelmetChanged);
GameEvents.onPartActionUICreate.Remove(OnPartActionMenuCreate);
GameEvents.onEditorVariantApplied.Remove(OnPartVariandChanged);
DisableIcon(); // Release the resources!
}
#endregion

Expand Down

0 comments on commit 993d76d

Please sign in to comment.