Forum begins after the advertisement:
[Part 7] SceneFader NullReferenceException and SaveData EndOfStreamException
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 7] SceneFader NullReferenceException and SaveData EndOfStreamException
- This topic has 5 replies, 2 voices, and was last updated 10 months, 3 weeks ago by Terence.
-
AuthorPosts
-
February 4, 2024 at 1:09 am #13221::
Anonymes FRACTAL has helped us point out a few bugs on the project files for Part 7 of this series:
This is better, I can now move my player, but always bugs. Respawn button is broken and i have 3 error in console :
NullReferenceException: Object reference not set to an instance of an object SceneFader.SetColorImage (System.Single& _alpha, SceneFader+FadeDirection _fadeDirection) (at Assets/Scripts/SceneFader.cs:71) SceneFader+d__5.MoveNext () (at Assets/Scripts/SceneFader.cs:40) UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at :0) UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator) SceneTransition:Start() (at Assets/Scripts/SceneTransition.cs:26)
There can be only one active Event System. UnityEngine.EventSystems.EventSystem:OnEnable () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:424)
EndOfStreamException: Unable to read beyond the end of the stream. System.IO.BinaryReader.ReadByte () (at :0) System.IO.BinaryReader.Read7BitEncodedInt () (at :0) System.IO.BinaryReader.ReadString () (at :0) SaveData.LoadBench () (at Assets/Scripts/Singletons/SaveData.cs:71) GameManager.RespawnPlayer () (at Assets/Scripts/Singletons/GameManager.cs:64) UnityEngine.Events.InvokableCall.Invoke () (at :0) UnityEngine.Events.UnityEvent.Invoke () (at :0) UnityEngine.UI.Button.Press () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:70) UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Button.cs:114) UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:57) UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:272) UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:501)
February 4, 2024 at 1:11 am #13222::Update 2 March 2024: Rewrote this part to document the solutions better.
Fixing the
EndOfStreamException
Here are the fixes you’ll need to implement to fix the issues here. For starters, under SaveData.cs, we will need to ensure that
LoadPlayerData()
,LoadShadeData()
andLoadBenchData()
checks if the file is empty, so that it doesn’t cause an EndOfStreamException. The changes are highlighted below.SaveData.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; using UnityEngine.SceneManagement; [System.Serializable] public struct SaveData { public static SaveData Instance; //map stuff public HashSet<string> sceneNames; //bench stuff public string benchSceneName; public Vector2 benchPos; //player stuff public int playerHealth; public int playerHeartShards; public float playerMana; public int playerManaOrbs; public int playerOrbShard; public float playerOrb0fill, playerOrb1fill, playerOrb2fill; public bool playerHalfMana; public Vector2 playerPosition; public string lastScene; public bool playerUnlockedWallJump, playerUnlockedDash, playerUnlockedVarJump; public bool playerUnlockedSideCast, playerUnlockedUpCast, playerUnlockedDownCast; //enemies stuff //shade public Vector2 shadePos; public string sceneWithShade; public Quaternion shadeRot; public void Initialize() { if(!File.Exists(Application.persistentDataPath + "/save.bench.data")) //if file doesnt exist, well create the file { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.bench.data")); } if (!File.Exists(Application.persistentDataPath + "/save.player.data")) //if file doesnt exist, well create the file { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.player.data")); } if (!File.Exists(Application.persistentDataPath + "/save.shade.data")) //if file doesnt exist, well create the file { BinaryWriter writer = new BinaryWriter(File.Create(Application.persistentDataPath + "/save.shade.data")); } if (sceneNames == null) { sceneNames = new HashSet<string>(); } } #region Bench Stuff public void SaveBench() { using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.bench.data"))) { writer.Write(benchSceneName); writer.Write(benchPos.x); writer.Write(benchPos.y); } } public void LoadBench() {
if(File.Exists(Application.persistentDataPath + "/save.bench.data"))string savePath = Application.persistentDataPath + "/save.bench.data"; if(File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.bench.data"))) { benchSceneName = reader.ReadString(); benchPos.x = reader.ReadSingle(); benchPos.y = reader.ReadSingle(); } } else { Debug.Log("Bench doesnt exist"); } } #endregion #region Player stuff public void SavePlayerData() { using(BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.player.data"))) { playerHealth = PlayerController.Instance.Health; writer.Write(playerHealth); playerHeartShards = PlayerController.Instance.heartShards; writer.Write(playerHeartShards); playerMana = PlayerController.Instance.Mana; writer.Write(playerMana); playerHalfMana = PlayerController.Instance.halfMana; writer.Write(playerHalfMana); playerManaOrbs = PlayerController.Instance.manaOrbs; writer.Write(playerManaOrbs); playerOrbShard = PlayerController.Instance.orbShard; writer.Write(playerOrbShard); playerOrb0fill = PlayerController.Instance.manaOrbsHandler.orbFills[0].fillAmount; writer.Write(playerOrb0fill); playerOrb1fill = PlayerController.Instance.manaOrbsHandler.orbFills[1].fillAmount; writer.Write(playerOrb1fill); playerOrb2fill = PlayerController.Instance.manaOrbsHandler.orbFills[2].fillAmount; writer.Write(playerOrb2fill); playerUnlockedWallJump = PlayerController.Instance.unlockedWallJump; writer.Write(playerUnlockedWallJump); playerUnlockedDash = PlayerController.Instance.unlockedDash; writer.Write(playerUnlockedDash); playerUnlockedVarJump = PlayerController.Instance.unlockedVarJump; writer.Write(playerUnlockedVarJump); playerUnlockedSideCast = PlayerController.Instance.unlockedSideCast; writer.Write(playerUnlockedSideCast); playerUnlockedUpCast = PlayerController.Instance.unlockedUpCast; writer.Write(playerUnlockedUpCast); playerUnlockedDownCast = PlayerController.Instance.unlockedDownCast; writer.Write(playerUnlockedDownCast); playerPosition = PlayerController.Instance.transform.position; writer.Write(playerPosition.x); writer.Write(playerPosition.y); lastScene = SceneManager.GetActiveScene().name; writer.Write(lastScene); } Debug.Log("saved player data"); } public void LoadPlayerData() {if(File.Exists(Application.persistentDataPath + "/save.player.data"))string savePath = Application.persistentDataPath + "/save.player.data"; if(File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.player.data"))) { playerHealth = reader.ReadInt32(); playerHeartShards = reader.ReadInt32(); playerMana = reader.ReadSingle(); playerHalfMana = reader.ReadBoolean(); playerManaOrbs = reader.ReadInt32(); playerOrbShard = reader.ReadInt32(); playerOrb0fill = reader.ReadSingle(); playerOrb1fill = reader.ReadSingle(); playerOrb2fill = reader.ReadSingle(); playerUnlockedWallJump = reader.ReadBoolean(); playerUnlockedDash = reader.ReadBoolean(); playerUnlockedVarJump = reader.ReadBoolean(); playerUnlockedSideCast = reader.ReadBoolean(); playerUnlockedUpCast = reader.ReadBoolean(); playerUnlockedDownCast = reader.ReadBoolean(); playerPosition.x = reader.ReadSingle(); playerPosition.y = reader.ReadSingle(); lastScene = reader.ReadString(); SceneManager.LoadScene(lastScene); PlayerController.Instance.transform.position = playerPosition; PlayerController.Instance.halfMana = playerHalfMana; PlayerController.Instance.Health = playerHealth; PlayerController.Instance.heartShards = playerHeartShards; PlayerController.Instance.Mana = playerMana; PlayerController.Instance.manaOrbs = playerManaOrbs; PlayerController.Instance.orbShard = playerOrbShard; PlayerController.Instance.manaOrbsHandler.orbFills[0].fillAmount = playerOrb0fill; PlayerController.Instance.manaOrbsHandler.orbFills[1].fillAmount = playerOrb1fill; PlayerController.Instance.manaOrbsHandler.orbFills[2].fillAmount = playerOrb2fill; PlayerController.Instance.unlockedWallJump = playerUnlockedWallJump; PlayerController.Instance.unlockedDash = playerUnlockedDash; PlayerController.Instance.unlockedVarJump = playerUnlockedVarJump; PlayerController.Instance.unlockedSideCast = playerUnlockedSideCast; PlayerController.Instance.unlockedUpCast = playerUnlockedUpCast; PlayerController.Instance.unlockedDownCast = playerUnlockedDownCast; } Debug.Log("load player data"); Debug.Log(playerHalfMana); } else { Debug.Log("File doesnt exist"); PlayerController.Instance.halfMana = false; PlayerController.Instance.Health = PlayerController.Instance.maxHealth; PlayerController.Instance.Mana = 0.5f; PlayerController.Instance.heartShards = 0; PlayerController.Instance.unlockedWallJump = false; PlayerController.Instance.unlockedDash = false; PlayerController.Instance.unlockedVarJump = false; } } #endregion #region enemy stuff public void SaveShadeData() { using (BinaryWriter writer = new BinaryWriter(File.OpenWrite(Application.persistentDataPath + "/save.shade.data"))) { sceneWithShade = SceneManager.GetActiveScene().name; shadePos = Shade.Instance.transform.position; shadeRot = Shade.Instance.transform.rotation; writer.Write(sceneWithShade); writer.Write(shadePos.x); writer.Write(shadePos.y); writer.Write(shadeRot.x); writer.Write(shadeRot.y); writer.Write(shadeRot.z); writer.Write(shadeRot.w); } } public void LoadShadeData() {if (File.Exists(Application.persistentDataPath + "/save.shade.data"))string savePath = Application.persistentDataPath + "/save.shade.data"; if(File.Exists(savePath) && new FileInfo(savePath).Length > 0) { using(BinaryReader reader = new BinaryReader(File.OpenRead(Application.persistentDataPath + "/save.shade.data"))) { sceneWithShade = reader.ReadString(); shadePos.x = reader.ReadSingle(); shadePos.y = reader.ReadSingle(); float rotationX = reader.ReadSingle(); float rotationY = reader.ReadSingle(); float rotationZ = reader.ReadSingle(); float rotationW = reader.ReadSingle(); shadeRot = new Quaternion(rotationX, rotationY, rotationZ, rotationW); } Debug.Log("Load shade data"); } else { Debug.Log("Shade doesnt exist"); } } #endregion }Fixing the SceneFader issue
Please refer to post #13223 below.
Respawn issue
With the above fixes, an error will still occur if you die before you first sit on a bench. This will be addressed in a future part of the series.
Original post
Below is the original post made by Anonymes:I have resolve some of your bug. Add verification 0 byte save file in the load data method and load bench method :
if (File.Exists(filePath) && new FileInfo(filePath).Length > 0)
In the bench load method add benchname and benchPos default position in the else condition for prevent respawn bug with new game.
and for duplicate event system, in game manager add this function :
private void EnsureEventSystem() { if (FindObjectOfType<EventSystem>() == null) { GameObject eventSystemGO = new GameObject("EventSystem"); eventSystemGO.AddComponent<EventSystem>(); eventSystemGO.AddComponent<StandaloneInputModule>(); } }
in Awake and delete the event system game object in canva prefab.
Enjoy. ;)
February 4, 2024 at 1:16 am #13223::For the SceneFader issue at Line 71, it is caused by
fadeOutUIImage
being null when its function (SetColorImage()
) is being called by SceneTransition.cs. This happens because the function is called in SceneTransition’sStart()
, which runs before SceneFader’sStart()
(wherefadeOutUIImage
is set).This can be fixed by changing the
Start()
in SceneFader.cs toAwake()
, so that it is called before SceneTransition’sStart()
runs, ensuring thatfadeOutUIImage
variable is set beforeSetColorImage()
is called bySceneTransition
in our game.using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.SceneManagement; public class SceneFader : MonoBehaviour { public float fadeTime; private Image fadeOutUIImage; public enum FadeDirection { In, Out } // Start is called before the first frame update void
StartAwake() { fadeOutUIImage = GetComponent<Image>(); } // Update is called once per frame void Update() { } public IEnumerator Fade(FadeDirection _fadeDirection) { float _alpha = _fadeDirection == FadeDirection.Out ? 1 : 0; float _fadeEndValue = _fadeDirection == FadeDirection.Out ? 0 : 1; if(_fadeDirection == FadeDirection.Out) { while(_alpha >= _fadeEndValue) { SetColorImage(ref _alpha, _fadeDirection); yield return null; } fadeOutUIImage.enabled = false; } else { fadeOutUIImage.enabled = true; while (_alpha <= _fadeEndValue) { SetColorImage(ref _alpha, _fadeDirection); yield return null; } } } public IEnumerator FadeAndLoadScene(FadeDirection _fadeDirection, string _sceneToLoad) { fadeOutUIImage.enabled = true; yield return Fade(_fadeDirection); SceneManager.LoadScene(_sceneToLoad); } void SetColorImage(ref float _alpha, FadeDirection _fadeDirection) { fadeOutUIImage.color = new Color(fadeOutUIImage.color.r, fadeOutUIImage.color.g, fadeOutUIImage.color.b, _alpha); _alpha += 0.02f * (_fadeDirection == FadeDirection.Out ? -1 : 1); } }February 4, 2024 at 3:06 am #13225::It’s rather this code :
<code> private void EnsureEventSystem() { if (FindObjectOfType<EventSystem>() == null) { GameObject eventSystemGO = new GameObject("EventSystem"); eventSystemGO.AddComponent<EventSystem>(); eventSystemGO.AddComponent<StandaloneInputModule>(); } }</code>
February 4, 2024 at 3:11 am #13226::for prevent respawn problem of position I add this in LoadPlayerData :
LoadBench(); if (benchName != null) { SceneManager.LoadScene(benchName ); } else { SceneManager.LoadScene(lastScene); } if (benchPos != null) { PlayerController.Instance.transform.position = benchPos ; } else { PlayerController.Instance.transform.position = playerPosition; }
February 8, 2024 at 12:14 am #13262 -
AuthorPosts
- You must be logged in to reply to this topic.