what to do when you won't save - unity3d

when I load a new scene I get this error: NullReferenceException: Object reference not set to an instance of an object GameController+d__16.MoveNext () (at Assets/Scrips/GameController.cs:76) UnityEngine.SetupCoroutine.InvokeMoveNext (System.Collections.IEnumerator enumerator, System.IntPtr returnValueAddress) (at :0)
this is my script to save:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Scene_Manager : MonoBehaviour
{
int Saved_scene;
int Scene_index;
public void Load_Saved_Scene()
{
Saved_scene = PlayerPrefs.GetInt("Saved");
if (Saved_scene != 2)
SceneManager.LoadSceneAsync(Saved_scene);
else
return;
}
public void Save_and_Exit()
{
Scene_index = SceneManager.GetActiveScene().buildIndex;
PlayerPrefs.SetInt("Saved", Scene_index);
PlayerPrefs.Save();
SceneManager.LoadSceneAsync(0);
}
public void Next_Scene()
{
Scene_index = SceneManager.GetActiveScene().buildIndex + 1;
SceneManager.LoadSceneAsync(Scene_index);
}
}
and this is my script for the whole game where I call save:
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
[RequireComponent(typeof(GameUI))]
public class GameController : MonoBehaviour
{
public static GameController Instance { get; private set; }
[SerializeField]
private int knifeCount;
[Header("Knife Spawning")]
[SerializeField]
private Vector2 knifeSpawnPosition;
[SerializeField]
private GameObject knifeObject;
public GameUI GameUI { get; private set; }
private void Awake()
{
Instance = this;
GameUI = GetComponent<GameUI>();
}
private void Start()
{
GameUI.SetInitialDisplayedKnifeCount(knifeCount);
SpawnKnife();
}
public void OnSuccessfulKnifeHit()
{
if (knifeCount > 0)
{
SpawnKnife();
}
else
{
StartGameOverSequence(true);
}
}
private void SpawnKnife()
{
knifeCount--;
Instantiate(knifeObject, knifeSpawnPosition, Quaternion.identity);
}
public void StartGameOverSequence(bool win)
{
StartCoroutine("GameOverSequenceCoroutine", win);
}
private IEnumerator GameOverSequenceCoroutine(bool win)
{
if (win)
{
yield return new WaitForSecondsRealtime(0.3f);
FindObjectOfType<LevelLoader>().LoadNextLevel();
FindObjectOfType<Scene_Manager>().Save_and_Exit();
}
else
{
GameUI.ShowRestartButton();
}
}
public void RestartGame()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex, LoadSceneMode.Single);
}
}

Now first of all take a look at this post to understand NullReferenceExceptions.
After that take a closer look at your error message:
NullReferenceException: Object reference not set to an instance of an object GameController+d__16.MoveNext () (at Assets/Scrips/GameController.cs:76)
The (at Assets/Scrips/GameController.cs:76) part tells you exactly where you error is thrown (which basically means where it occured). It's in your Assets/Scrips/GameController.cs script at line 76.
private IEnumerator GameOverSequenceCoroutine(bool win)
{
if (win)
{
yield return new WaitForSecondsRealtime(0.3f);
FindObjectOfType<LevelLoader>().LoadNextLevel();
FindObjectOfType<Scene_Manager>().Save_and_Exit(); // <--- HERE
}
...
}
In your specific implementation my best guess would be that you shouldn't load your new scene before you try to save & quit. You're starting to load your new scene asynchronously and then call another function which loads another scene (?) while not actually preventing the first scene from activating until your other functions actually executed properly. There's a plethora of cases where this can and will break.
I think you'll need to rethink what it is your actually trying to accomplish because these function calls don't make sense like that.

Related

Error: d__7.MoveNext() after changing model

At first my model was humanoid and the game worked fine. I had to change it to generic though and after that I got this error:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Pokemon.Fight
{
public class PokemonTrainer : MonoBehaviour
{
//public Animator Prefab
public Animator animator { get; set; }
private void Awake()
{
animator = GetComponentInChildren<Animator>();
}
public void SpawnTrainer(/*TrainerSO trainer*/)
{
//animator = Instantiate(trainer.trainerPrefab, transform);
//animator.transform.localPosition = Vector3.zero;
}
public void Throw(bool isPlayer, int id, int level)
{
StartCoroutine(ie_throw(isPlayer, id, level));
}
private IEnumerator ie_throw(bool isPlayer, int id, int level)
{
animator.SetTrigger("throw");
yield return new WaitForSeconds(0.11f);
PokemonBall ball = PokemonGameplay.Instance.pokemonEffectPool.GetPokemonBall();
ball.Throw(animator.GetBoneTransform(HumanBodyBones.RightHand).position, isPlayer, id, level);
}
//public void SetEndgame(bool isWin)
//{
// if (isWin) animator.CrossFadeInFixedTime("Victory", 0.1f);
// else animator.CrossFadeInFixedTime("Defeat", 0.1f);
//}
public void OnRebind()
{
animator.Rebind();
}
}
}
Here is the code that had the error and "PokemonBall ball = PokemonGameplay.Instance.pokemonEffectPool.GetPokemonBall();" This line in iethrow was the reason for it. Idk how to solve this, I changed nothing in my code when I change the model. And for this my Pokeball can't run in a right way.
Tried to figure out what is null but noothing is. The ball can still spawn but it headed to a wrong position(I set the position for it).

Unity Mirror AddPlayerForConnection method didn't work as expected

I'm quite new to Mirror. Let me try to explain my setup and problem:
On client-side, player spawn multi-gameobject and select the only one which he would use in a race. For example, he has 4 cars in his garage, when the scene Garage is loaded, there are 4 car-object has been spawned in the scene. And when he select the desired car to use in a race, the Player property in PlayerManager instance will update with the selected car value.
public class PlayerManager : MonoBehaviour {
public static PlayManager Instance;
private void Awake() {
if (Instance != null) Destroy(gameObject);
Instance = this;
}
public Player Player {get; private set;}
public static void UpdateSelectedCar() {
Car car = CarSpawner.SelectedCar;
Player.Car = car;
}
}
public class Player () {
public Car Car { get; set; }
public string Name;
....
public Player(string playerName){
Name = playerName;
}
}
public class Car() {
public GameObject;
public CarName;
.....
public void Instantiate() {
GameObject = Object.Instantiate(carPrefab, carPosition);
}
}
In the NetworkManagerCar, I have setup as below:
public class NetworkManagerCar : NetworkManager {
// There are Host and Join Button in the UI for create host or join as client
private void OnEnable() {
hostBtn.onClick.AddListener(CreateHost);
joinBtn.onClick.AddListener(JoinGame);
}
private void OnDisable() {
hostBtn.onClick.RemoveListener(CreateHost);
joinBtn.onClick.RemoveListener(JoinGame);
}
private void CreateHost() {
StartHost();
networkStatus.text = "Waiting for other to join...";
}
private void JoinGame() {
StartClient();
networkStatus.text = "Finding Match...";
}
public override void OnClientConnect() {
PlayerManager.UpdateSelectedCar();
playerPrefab = PlayerManager.Instance.Player.Car.GameObject;
Debug.Log($"Prefab name: {playerPrefab.name}");
base.OnClientConnect();
Debug.Log($"{PlayerManager.Instance.Player.Name} connected");
}
public override void OnServerAddPlayer(NetworkConnectionToClient conn) {
GameObject player = playerPrefab;
player.name = $"{playerPrefab.name} [connId={conn.connectionId}]";
NetworkServer.AddPlayerForConnection(conn, player);
}
}
It is no problem when I host the game. However, when 1 client joined, I got the bug below. I use ParrelSync to clone client, I have already tried to delete the clone and create a new one but the bug is still:
On host console:
Object Car10(Clone) [connId=0] [connId=250806295] [connId=701038615] (Mirror.NetworkIdentity) netId=2 already has an owner. Use RemoveClientAuthority() first
UnityEngine.Debug:LogError (object,UnityEngine.Object)
On client console:
Spawn scene object not found for CE359B9F. Make sure that client and server use exactly the same project. This only happens if the hierarchy gets out of sync.
Could not spawn assetId=00000000-0000-0000-0000-000000000000 scene=CE359B9F netId=1
OnSpawn message with netId '2' has no AssetId or sceneId
Could anyone tell me where I was wrong :(
You need instantiate "playerPrefab" before passing to AddPlayerForConnection
GameObject player = Instantiate(playerPrefab);
player.name = $"{playerPrefab.name} [connId={conn.connectionId}]";
NetworkServer.AddPlayerForConnection(conn, player);

Switching weapons with PUN 2

I can't seem to get this to work.
The player presses 1 or 2 or 3 etc depending where the weapon is on the hotbar and it will show the weapon by setting it active in the hierarchy.
everything works fine client side obviously but I cannot get it to show from the other players perspective. Not sure where to put the photon view or where to put the code exactly but this is my code that is currently on the hotbar slot.
Also worth mentioning that the item is selected from an actual inventory and not just a simple switch so it all corresponds to another bit of code that is the item script attached to the pickupable item.
Thanks if advanced if anyone can point me in the right direction.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Hashtable = ExitGames.Client.Photon.Hashtable;
using Photon.Realtime;
public class HotbarSlot : MonoBehaviourPunCallbacks
{
public GameObject[] unstaticItems;
public static GameObject[] items;
public Inventory inv;
public NewPlayerHealth updateVitals;
public AudioSource audioSource;
public AudioClip Eating;
public KeyCode key;
public PhotonView PV;
[SerializeField]
private GameObject placeableObjectPrefab;
[SerializeField]
private GameObject currentPlaceableObject;
private float mouseWheelRotation;
void Awake()
{
PV = GetComponent<PhotonView>();
}
void Start()
{
if (unstaticItems.Length > 0)
items = unstaticItems;
audioSource = GetComponent<AudioSource>();
}
void Update()
{
if (!PV.IsMine) return;
if (Input.GetKeyDown(key))
Equip();
if (Input.GetKeyDown(key))
{
EatFood();
}
PlaceFurnace();
RotateFromMouseWheel();
}
void Equip()
{
{
photonView.RPC("EquipRPC", RpcTarget.AllBuffered);
}
}
[PunRPC]
void EquipRPC()
{
{
if (transform.childCount > 1)
{
Item item = transform.GetChild(1).GetComponent<Item>();
if (item.equipmentType == "Hand")
{
for (int i = 0; i < items.Length; i++)
{
if (i == item.equipmentIndex)
{
items[i].SetActive(!items[i].activeInHierarchy);
}
else
{
items[i].SetActive(false);
}
}
}
}
}
}

Minimum players to enter in a room PHOTON

I am doing a multiplayer game and I want to know how I can add a minimum number of players for a user to enter a room . Like to not be alone till one player is connected at least. What I should add to my script? I have this Room Options function but It doesn't work too add like Min players or something to it. (I expected if is MaxPlayers to exist MinPlayers too)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon;
using Photon.Pun;
using UnityEngine.UI;
using Photon.Realtime;
public class MPManager : MonoBehaviourPunCallbacks, IPunObservable
{
public PlayFabAuth auth;
public string GameVersion;
public Text connectState;
public GameObject[] DisableOnConnected;
public GameObject[] DisableOnJoinRoom;
public GameObject[] EnableOnConnected;
public GameObject[] EnableOnJoinRoom;
public LoadedPlayer loadPlayer;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
private void FixedUpdate()
{
connectState.text = "Connection: " + PhotonNetwork.NetworkClientState;
}
public void ConnectToMaster()
{
// PhotonNetwork.connectionStateDetailed
PhotonNetwork.ConnectUsingSettings();
}
public override void OnConnectedToMaster()
{
PhotonNetwork.JoinLobby();
}
public override void OnJoinedLobby(){
foreach(GameObject disable in DisableOnConnected){
disable.SetActive(false);
}
foreach (GameObject enable in EnableOnConnected){
enable.SetActive(true);
}
}
public void CreateOrJoin()
{
PhotonNetwork.LeaveLobby();
PhotonNetwork.JoinRandomRoom();
}
public override void OnJoinRandomFailed(short returnCode, string message)
{
RoomOptions rm = new RoomOptions
{
MaxPlayers = 3,
IsVisible = true
};
int rndID = Random.Range(0, 3000);
PhotonNetwork.CreateRoom("Default: " + rndID, rm, TypedLobby.Default);
}
public override void OnJoinedRoom()
{
foreach (GameObject disable in DisableOnJoinRoom)
{
disable.SetActive(false);
}
foreach (GameObject enable in EnableOnJoinRoom)
{
enable.SetActive(true);
}
Debug.Log(loadPlayer.currentPlayer.name);
GameObject player = PhotonNetwork.Instantiate(loadPlayer.currentPlayer.name , Vector3.zero, Quaternion.identity, 0);
}
public override void OnLeftRoom()
{
PhotonNetwork.LeaveRoom();
}
public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
{
throw new System.NotImplementedException();
}
}
Thank you for choosing Photon!
You need to get the count of actors (PhotonNetwork.CurrentRoom.PlayerCount) when you join the room (OnJoinedRoom) or when another player joins the room (OnPlayerEnteredRoom). When the number of actors joined is enough for you, start the game logic, e.g. load scene, send a custom event etc.

Calling Invoke within a public static function Unity

I'm getting an error that I don't understand. The simplified version of my code:
using UnityEngine;
public class RunLater : MonoBehaviour
{
public static void Do()
{
Invoke("RunThisLater", 2.0f);
}
public void RunThisLater()
{
Debug.Log("This will run later");
}
}
You can pass it in as a parameter like this:
public class RunLater : MonoBehaviour
{
public static void Do(RunLater instance)
{
instance.Invoke("RunThisLater", 2.0f);
}
public void RunThisLater()
{
Debug.Log("This will run later");
}
}
One approach is to have the static parts of the class store a MonoBehaviour reference to itself. Like so:
public class RunLater : MonoBehaviour
{
public static RunLater selfReference = null;
public static void Do()
{
InitSelfReference();
selfReference.DoInstanced();
}
static void InitSelfReference()
{
if (selfReference == null)
{
// We're presuming you only have RunLater once in the entire hierarchy.
selfReference = Object.FindObjectOfType<RunLater>();
}
}
public void DoInstanced()
{
Invoke("RunThisLater", 2f);
}
void RunThisLater()
{
Debug.Log("This will run later");
}
}
You would now be able to call RunLater.Do() from anywhere in your code of other gameObjects. Good luck!