This used to work consistently for a long time until it randomly started getting a NullReferenceExeption
for my singleton class, i have been trying to understand why but it makes no sense to me, it looks like it’s triggering an OnApplicationPause
method before Awake
methods but i don’t get it…
[196986-aa.png*_|196986]
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BreakInfinity;
public class MineSpawner : MonoBehaviour
{
[SerializeField] private int maxMinesAtOnce;
[SerializeField] private float mineSpawnInterval;
[SerializeField] private float spawnHeight;
[SerializeField] private float[] chance;
[SerializeField] private GameObject[] mineTypes;
[SerializeField] private Transform mineSlotsParent;
private DataController dataC;
private void Start()
{
dataC = DataController.Instance;
SpawnSavedMines();
InvokeRepeating("SpawnMine", 0f, mineSpawnInterval);
}
void SpawnSavedMines()
{
for (int i = 0; i < dataC.minesParent.Count; i++)
{
GameObject newMine = Instantiate(mineTypes[dataC.minesType_], mineSlotsParent.GetChild(dataC.minesParent*));*_
newMine.gameObject.GetComponent().maxHitPoints = dataC.minesMaxHitPoints*;*
newMine.gameObject.GetComponent().mineType = dataC.minesType*;*
}
CheckCurrentMinesAmount();
}
void SpawnMine()
{
CheckCurrentMinesAmount();
if (PlayerPrefs.GetInt(“CurrentMines”) < maxMinesAtOnce)
{
float percentageCap = 0f;
for (int i = 0; i < chance.Length; i++) // gets the sum of total percentages
{
percentageCap += chance*;*
}
float tempChance = 0f; // initializes percentage checking
float roll = Random.Range(0f, percentageCap); // random number roll for percentage
for (int i = 0; i < mineTypes.Length; i++)
{
if (roll >= tempChance && roll < tempChance + chance*)*
{
GameObject newMine = Instantiate(mineTypes*, GetRandomFreeChild());*
newMine.transform.position += new Vector3(0, spawnHeight, 0);
newMine.transform.eulerAngles = new Vector3(0,Random.Range(0,360),0);
switch (newMine.tag)
{
case “Copper”:
newMine.GetComponent().maxHitPoints = BigDouble.Round(dataC.copperOreHealth +
dataC.copperOreHealth * Random.Range(0,0.1f));
break;
case “Iron”:
newMine.GetComponent().maxHitPoints = BigDouble.Round(dataC.ironOreHealth +
dataC.ironOreHealth * Random.Range(0, 0.1f));
break;
}
newMine.GetComponent().mineType = i;
}
tempChance += chance*; // add new percentage to check before looping again*
}
}
}
Transform GetRandomFreeChild()
{
int randomParentNum;
do
{
randomParentNum = Random.Range(0, mineSlotsParent.childCount);
} while (mineSlotsParent.GetChild(randomParentNum).childCount != 0);
return mineSlotsParent.GetChild(randomParentNum);
}
void CheckCurrentMinesAmount()
{
int count = 0;
foreach (Transform childs in mineSlotsParent)
{
if (childs.childCount != 0)
{
count++;
}
}
PlayerPrefs.SetInt(“CurrentMines”, count);
}
private void SaveMines()
{
if (dataC == null) Debug.Log(“dataC is null”); //debug
dataC.minesParent.Clear();
dataC.minesMaxHitPoints.Clear();
dataC.minesType.Clear();
for (int i = 0; i < mineSlotsParent.childCount; i++)
{
if (mineSlotsParent.GetChild(i).childCount != 0)
{
dataC.minesParent.Add(i);
dataC.minesMaxHitPoints.Add(mineSlotsParent.GetChild(i).GetChild(0).GetComponent().maxHitPoints);
dataC.minesType.Add(mineSlotsParent.GetChild(i).GetChild(0).GetComponent().mineType);
}
}
CheckCurrentMinesAmount();
dataC.SaveMineObjects();
}
private void OnApplicationQuit()
{
SaveMines();
Debug.Log(“MineSpawner OAQ triggered”);
}
private void OnApplicationPause(bool pause)
{
SaveMines();
Debug.Log(“MineSpawner OAP triggered”);
}
}
The singleton DataController class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BreakInfinity;
using TMPro;
public class DataController : MonoBehaviour
{
public float basePrice, baseProd, baseSpeed, priceMult, prodMult, speedMult; //for prototype
[SerializeField] private float saveCycleSeconds;
[SerializeField] private string saveFileName;
[SerializeField] private TMP_Text smallInvCopper;
[SerializeField] private TMP_Text smallInvIron;
Data data;
MineData mineData;
UpgradeData upgradeData;
MineObjects mineObjects;
Init init;
public BigDouble coins;
public BigDouble copper;
public BigDouble iron;
public BigDouble damage;
public BigDouble copperOreHealth;
public BigDouble ironOreHealth;
public BigDouble copperPerSecond;
public BigDouble ironPerSecond;
///////
public int copperMineLevel;
public int ironMineLevel;
public BigDouble copperMineProd;
public BigDouble ironMineProd;
public float copperMineRate;
public float ironMineRate;
public BigDouble copperUpgradePrice;
public BigDouble ironUpgradePrice;
////////
public float copperPriceMultiplier;
public float ironPriceMultiplier;
public byte copperPriceULevel;
public byte ironPriceULevel;
private float copperTimer;
private float ironTimer;
////////
public List minesParent;
public List minesMaxHitPoints;
public List minesType;
///////
#region singleton stuff
public static DataController Instance
{
get
{
if (_instance == null)
{
Debug.LogWarning(“DataController is null”);
_instance = FindObjectOfType(typeof(DataController)) as DataController;
if (_instance == null) Debug.LogError(“DataController still null after fixing attempt :(”);
Debug.Log(“DataController now fixed”);
}
return _instance;
}
set
{
_instance = value;
}
}
private static DataController _instance;
#endregion
private void Awake()
{
_instance = this;
data = SavingSystem.SaveExists(saveFileName) ? SavingSystem.LoadData(saveFileName) : new Data();
mineData = SavingSystem.SaveExists(saveFileName + “MineData”) ? SavingSystem.LoadData(saveFileName + “MineData”) : new MineData();
upgradeData = SavingSystem.SaveExists(saveFileName + “UpgradeData”) ? SavingSystem.LoadData(saveFileName + “UpgradeData”) : new UpgradeData();
mineObjects = SavingSystem.SaveExists(saveFileName + “MineObjects”) ? SavingSystem.LoadData(saveFileName + “MineObjects”) : new MineObjects();
init = SavingSystem.SaveExists(saveFileName + “Init”) ? SavingSystem.LoadData(saveFileName + “Init”) : new Init();
Load();
UpdateOPS();
}
private void Start()
{
InvokeRepeating(“AutoSaveCycle”, saveCycleSeconds, saveCycleSeconds);
copperTimer = Time.time;
ironTimer = Time.time;
}
private void Update()
{
//copper += copperPerSecond * Time.deltaTime;
//iron += ironPerSecond * Time.deltaTime;
UpdateSmallInv();
if (Time.time > copperTimer)
{
copper += copperMineProd;
smallInvCopper.text = Utils.IdleGameNumberBigDouble(copper);
copperTimer += copperMineRate;
}
if (Time.time > ironTimer)
{
iron += ironMineProd;
smallInvIron.text = Utils.IdleGameNumberBigDouble(iron);
ironTimer += ironMineRate;
}
}
public void UpdateOPS() //
{
copperUpgradePrice = basePrice * BigDouble.Pow(priceMult, copperMineLevel);
copperMineProd = baseProd * BigDouble.Pow(prodMult, copperMineLevel);
copperMineRate = baseSpeed / Mathf.Pow(speedMult, copperMineLevel);
if (copperMineRate > 0) copperPerSecond = copperMineProd / copperMineRate;
if (ironMineRate > 0) ironPerSecond = ironMineProd / ironMineRate;
SaveMineData();
}
public void UpdateSmallInv()
{
smallInvCopper.text = Utils.IdleGameNumberBigDouble(copper);
smallInvIron.text = Utils.IdleGameNumberBigDouble(iron);
}
void AutoSaveCycle()
{
InternalSave();
}
void OnApplicationPause()
{
InternalSave();
SaveMineData();
SaveUpgradeData();
//SaveMineObjects();
Debug.Log(“OnApplicationPause Triggered!”, gameObject);
}
void OnApplicationQuit()
{
InternalSave();
SaveMineData();
SaveUpgradeData();
//SaveMineObjects();
Debug.Log(“OnApplicationQuit Triggered!”, gameObject);
}
void Load()
{
coins = data.coins;
copper = data.copper;
iron = data.iron;
damage = data.damage;
copperOreHealth = data.copperOreHealth;
ironOreHealth = data.ironOreHealth;
copperPerSecond = data.copperPerSecond;
ironPerSecond = data.ironPerSecond;
////////////////////////////
copperMineLevel = mineData.copperMineLevel;
ironMineLevel = mineData.ironMineLevel;
copperMineProd = mineData.copperMineProd;
ironMineProd = mineData.ironMineProd;
copperMineRate = mineData.copperMineRate;
ironMineRate = mineData.ironMineRate;
copperUpgradePrice = mineData.copperUpgradePrice;
ironUpgradePrice = mineData.ironUpgradePrice;
////////////////////////////
copperPriceMultiplier = upgradeData.copperPriceMultiplier;
ironPriceMultiplier = upgradeData.ironPriceMultiplier;
copperPriceULevel = upgradeData.copperPriceULevel;
ironPriceULevel = upgradeData.ironPriceULevel;
///////////////////////////
minesParent = mineObjects.minesParent;
minesMaxHitPoints = mineObjects.minesMaxHitPoints;
minesType = mineObjects.minesType;
}
public void InternalSave()
{
data.coins = coins;
data.copper = copper;
data.iron = iron;
data.damage = damage;
data.copperOreHealth = copperOreHealth;
data.ironOreHealth = ironOreHealth;
data.copperPerSecond = copperPerSecond;
data.ironPerSecond = ironPerSecond;
SavingSystem.SaveData(data, saveFileName);
}
public void SaveMineData()
{
mineData.copperMineLevel = copperMineLevel;
mineData.ironMineLevel = ironMineLevel;
mineData.copperMineProd = copperMineProd;
mineData.ironMineProd = ironMineProd;
mineData.copperMineRate = copperMineRate;
mineData.ironMineRate = ironMineRate;
mineData.copperUpgradePrice = copperUpgradePrice;
mineData.ironUpgradePrice = ironUpgradePrice;
SavingSystem.SaveData(mineData, saveFileName + “MineData”);
}
public void SaveUpgradeData()
{
upgradeData.copperPriceMultiplier = copperPriceMultiplier;
upgradeData.ironPriceMultiplier = ironPriceMultiplier;
upgradeData.copperPriceULevel = copperPriceULevel;
upgradeData.ironPriceULevel = ironPriceULevel;
SavingSystem.SaveData(upgradeData, saveFileName + “UpgradeData”);
}
public void SaveMineObjects()
{
mineObjects.minesParent = minesParent;
mineObjects.minesMaxHitPoints = minesMaxHitPoints;
mineObjects.minesType = minesType;
SavingSystem.SaveData(mineObjects, saveFileName + “MineObjects”);
Debug.Log(“mine objects saved!”);
}
}
_*