saving files on IOS from a Unity 3D game - c#

Ok, so I followed the tutorial at unity3d.com (located here)
Just so that you dont have to or want to watch the whole video , here is the save/load functions.
//This one saves/creates the file
void OnDisable()
{
BinaryFormatter binFormatter = new BinaryFormatter();
FileStream file = File.Create(Application.persistentDataPath + "/savedgame.dat");
GameData data = new GameData();
data.coinAmount = coinAmount;
data.upgradeLevel = upgradeLevel;
binFormatter.Serialize(file, data);
file.Close();
}
//And this one loads it
void OnEnable()
{
if (File.Exists(Application.persistentDataPath + "/savedgame.dat"))
{
BinaryFormatter binFormatter = new BinaryFormatter();
FileStream file = File.Open(Application.persistentDataPath + "/savedgame.dat",FileMode.Open);
GameData data = (GameData)binFormatter.Deserialize(file) ;
file.Close();
coinAmount = data.coinAmount;
upgradeLevel = data.upgradeLevel;
}
}
I'm using OnDisable/OnEnable so that my game autosaves every time the users exits. This works on a pc and a mac, but when I build it to the Ipad air2 and its like nothing happens. Xcode trows a exception that says unknown filename(-1).
Thanks in advance for the help
Upon further investigation on android it turns out that the file gets created and the game reads data from it. The problems is here :
data.coinAmount = coinAmount;
data.upgradeLevel = upgradeLevel;
For some reason this does not write the correct data when the app runs on Android(probably the same for IOS).
When I supply a hard coded value i.e : data.coinAmount = 100; the game then reads it correctly.
Upon even further investigation turns out that the code work when you call Application.quit but does not work when we "force close" the app i.e using the ipads front button. Need help with this

Ok, so turns out when we stop a Unity game with the home button on a mobile device the methods OnEnable/OnDisable dont seem to we called or working properly. So my solution to the problem is to migrate the save code to the OnApplicationPause(bool pauseStatus) method. After a few tests this seems to be called every time you press the home screen, thus making sure that the game autosaves.
However this only fixed the issue on android devices. Someone please tells me what happens when a IOS user presses the home button so I can freakin save my game when that happens.
Fixed the issue. After some debugging it turns out that ios and .Net JIT do not like each other. This code fixes the issue:
if (Application.platform == RuntimePlatform.IPhonePlayer)
{
System.Environment.SetEnvironmentVariable("MONO_REFLECTION_SERIALIZER", "yes");
}
I recommend putting it in the Awake() method.

Related

Application.persistenDataPath not working anymore

Since yesterday evening my Application.persistenDataPath is not working anymore on one place in code. I am using it 2 times. On the first place it works on the second it doesnt work anymore...
Maybe a hint for you is, that I saved json very often yesterday. Also I had infinite loops what maybe caused the Application Settings to Crash.
On Android Build it is working fine. (I get the right Path on both usages)
What I have tried below the code
Both in the same Class.
Unity 2021.3.2f
Using Google Firebase
Visual Studio 2022 Community Edition
This the code where it works:
I am saving a Photo to the given Path.
//then Save To Disk as PNG
byte[] bytes = avatarTexture.EncodeToPNG();
var dirPath = Application.persistentDataPath + "/Resources/User/";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
if (File.Exists(dirPath + "avatar" + ".png"))
{
File.Delete(dirPath + "avatar" + ".png");
}
File.WriteAllBytes(dirPath + "avatar" + ".png", bytes);
saveUserDataAsJson(getUserToken(user.DisplayName, user.Email));
_warningLoginText.text = "";
_confirmLoginText.text = Translation.authManager_login_notification_loginSucceeded;
This is the code where it does not work:
I am saving a JSON File with User Information.
DataSnapshot snapshotYear = taskYear.Result;
_year = Convert.ToInt32(snapshotYear.Value);
FirebaseDatabaseUser tempUser = new FirebaseDatabaseUser(_token, _day, _month, _year);
var json = JsonConvert.SerializeObject(tempUser);
Debug.Log("Can see it in Console");
//After pressing Play Button in Unity
//Editor i get no Debug outprint here
Debug.Log(Application.persistentDataPath);
var folderPath = Application.persistentDataPath + "/Resources/User/";
Debug.Log("Can not see it in Console");
//HERE THE CODE STOPS AND NOTHING HAPPEN
//NO ERROR NO LOG NO FURTHER CODE WORKING
//HERE NOT WORKING ANYMORE
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
if (File.Exists(folderPath + "userdata" + ".json"))
{
File.Delete(folderPath + "userdata" + ".json");
}
File.WriteAllText(folderPath + "userdata" + ".json", json);
I have tried:
rebuild Project Settings
Print the Path in Console it was empty ""
Cleaned GI Cache
Restarted my PC
Cloned the project new
Tried using Application.dataPath (only for debugging tests, not to use it in my code) also not working in Unity Play Mode but on Android it points right to the APK.
First usage (Place in Code where it works) I get Path:
Computer: C:\Users\{user}\AppData\LocalLow\{company}\{app}\Resources\User\
Android: .\Android\data\com.{company}.{app}\...\Resources\User\
Second usage (Place in Code where does not work) I get Path:
Computer: ""
Android: ".\Android\data\com.{company}.{app}\...\Resources\User\"
I hope someone can explain the issue. I cannot solve the problem from myself. Need someone who has more background knowledge.
so the anwer was based on the Help of #derHugo :
Some of the Unity API is using only the Unity main thread. Application.persistentDataPath is one piece of this Unity API elements.
So the problem was, that in the first code snippet i was using the Unity Main Thread, but in the second code snippet i used a Background Thread. Was really easy to fix. Instead of using another thread, i used:
`<myasyncfunction>.ContinueWithOnMainThread(task => {....
//second code snippet
})`
Refactoring tips of this Code:
File.Exists can be removed, it is totally redundant. WriteAllText creates or overwrites the file by default anyway.
The Construction of data paths over and over again makes no sense. Better way is to create public static readonly paths and use them instead.
Hope the Solution of #derHugo can help someone else.
Have a nice Day if you read this :)

C# WPF application crashing when playing 16 players

I am running into an issue with my C# WPF application crashing silently when I am trying to play on 16 VideoViews. I did not see any error messaged popup, nor did I see anything in Windows Event viewer.
Each player instance have WindowsFormHost and hosting a VideoView in that and I am playing RTSP streams on them.
Crash time is not fixed, sometimes it crash after 2 hours, and sometimes after 7-8 hours.
Core.Initialize(AppInfo.VlcDir.FullName);
private LibVLC libVlc = null;
private LibVLCSharp.Shared.MediaPlayer mediaPlayer = null;
this.libVlc = new LibVLC(this.GetParsedPlayerOptions().ToArray());
this.mediaPlayer = new LibVLCSharp.Shared.MediaPlayer(this.libVlc);
this.videoPlayer.MediaPlayer = this.mediaPlayer;
this.mediaPlayer.Volume = 0;
this.mediaPlayer.EnableKeyInput = false;
this.mediaPlayer.EnableMouseInput = false;
// Then I added a bunch of event handlers for VideoView and MediaPlayer.
// Then I have a different function which plays videos
if (this.mediaPlayer != null)
{
var media = new Media(this.libVlc,GetPlaybackStreamUrl(this.Server), FromType.FromLocation);
this.mediaPlayer.Media = media;
this.mediaPlayer.Play();
try
{
media.Dispose();
}
catch
{
}
}
Please let me know if you need any more information.
Any suggestions of what I could be doing wrong, or anything missing?
I am running on Windows 10. Visual Studio 2019, application compiled as X86.
I am not able to find the option to upload log file, but I did attach that to the issue on videolan forum, which can be found here: https://code.videolan.org/videolan/LibVLCSharp/-/issues/564
Thanks.
I was not able to find the problem with the code or the crash stack for where it's dying.
But I was able to fix the problem by increasing the address space, by using editbin to add /LARGEADDRESSSPACE to process post build.

SoundPlayer not working when visual studio application is published

When I run in Microsoft Visual Studio, the sound works. However, after I published it, the sound doenst work. The sound properties are set to Content. Can someone help? Thanks
private void InitializeSound()
{
// Create an instance of the SoundPlayer class.
player = new SoundPlayer(#"Sounds\sirenpolice3.wav");
}
enter image description here
try this sample
using (var player = new SoundPlayer(#"Sounds\sirenpolice3.wav"))
{
// Use PlaySync to load and then play the sound.
// ... The program will pause until the sound is complete.
player.PlaySync();
}

Disable/enable ARKit during runtime in Unity3d - C#

Iam working with Unity3d, using C# and the ARKit plugin (2.0 from Github)
In my current application iam using the ARKit for measuring distances. The tool iam creating needs this functionality only for this reason, so i was wondering how i could enable the ARKit, when the user needs the ruler and disable it, if not.
I want to avoid that there is some performance losing while the user is using a non ARKit Tool. Em i right if i would say, that the ARKit still works in the background, if you where initializing it once? Iam new on the ARKit thing, so i dont have an perfect overview of how to handle it.
To drop some Code lines makes no sence, its basically the plugin importet into the project, and my own script which depends on some functions - i didnt changed anything in the source code of the plugin. The measuring tool itself which i programmed works pretty well, but i could not determine how to activate and deactivate basically the ARKit.
Can someone help me out with this? When iam disabeling the GameObjects, the scripts are running at it seems to be a "dirty" method to avoid those functionallitys but i have to make it clean (for excample also the video map in the background needs to be disabled - and i guess those ARKit functions will not be paused or disabled, just because some scripts are disalbed, it seems the api still runs in the background because it lags when i do so)
If you need more informations, please let me know. Every help or suggestion would be very nice.
Thanks a lot!
The current ARKit API doesn't have a method to disable or enable it in Unity, during run-time at this point.
With than being said, Unity has its own function to enable and disable VR, AR or XR plugins. If ARKit is built correctly, this method should work. So, you might be able to disable/enable ARKit by setting XRSettings.enabled to false and enable it by setting it to true.
It's also a good idea to call XRSettings.LoadDeviceByName with an empty string, wait for frame, before setting XRSettings.enabled to false to disable it:
IEnumerator DisableAR()
{
XRSettings.LoadDeviceByName("");
yield return null;
XRSettings.enabled = false;
}
then call to disable:
StartCoroutine(DisableAR());
I guess I am answering a pretty old post. I found a way but I don't know if that is what you are expecting.
Like #Programmer told
The current ARKit API doesn't have a method to disable or enable it in Unity, during run-time at this point.
So the way that I used is incorporating Programmer's code along with that if you need the camera to render some skybox or solid color, I have done something like that in Non-AR mode by saving the current texture before changing it, as the live video is given as texture to the material and after saving that changed the texture to null and when you want to re-enable AR you set the textures back to the saved value and it gets loaded correctly.
bool ARMode;
bool isSupported;
Camera cam;
UnityARCameraManager ARCameraManager;
private Texture2D _videoTextureY;
private Texture2D _videoTextureCbCr;
private void Awake()
{
cam = Camera.main;
isSupported = FindObjectOfType<UnityARCameraManager>().sessionConfiguration.IsSupported;
ARMode = isSupported;
ARCameraManager = FindObjectOfType<UnityARCameraManager>();
}
void DisableAR()
{
XRSettings.enabled = false;
ARCameraManager.enabled = false;
_videoTextureY = (Texture2D)cam.GetComponent<UnityARVideo>().m_ClearMaterial.GetTexture("_textureY");
_videoTextureCbCr = (Texture2D)cam.GetComponent<UnityARVideo>().m_ClearMaterial.GetTexture("_textureCbCr");
cam.GetComponent<UnityARVideo>().m_ClearMaterial.SetTexture("_textureY", Texture2D.blackTexture);
cam.GetComponent<UnityARVideo>().m_ClearMaterial.SetTexture("_textureCbCr", Texture2D.blackTexture);
cam.clearFlags = CameraClearFlags.SolidColor;
cam.backgroundColor = Color.black;
cam.GetComponent<UnityARVideo>().enabled = false;
}
void EnableAR()
{
ARCameraManager.enabled = true;
XRSettings.enabled = true;
cam.clearFlags = CameraClearFlags.Depth;
cam.GetComponent<UnityARVideo>().m_ClearMaterial.SetTexture("_textureY", _videoTextureY);
cam.GetComponent<UnityARVideo().m_ClearMaterial.SetTexture("_textureCbCr", _videoTextureCbCr);
cam.GetComponent<UnityARVideo>().enabled = true;
}

Not able to communicate with "Stockfish-9-armv7" binary file

I am developing a Chess Game in Unity3D. I want to develop it for the Android platform. For AI I am using the Stockfish Chess Engine. I downloaded the Stockfish binary for Android named "Stockfish-9-armv7". I placed this binary file in my StreamingAssets folder so that it correctly goes into the targeted platform during build step. Everything works fine till here i.e. when I build my Unity project the file is placed in the correct location and I can very well see it.
Now in order for my AI to work I have to communicate with this binary file using UCI protocols. And so I wrote a C# script in my Unity project that creates a process to run the binary file and communicate with it. But this is not working.
However when I do the exact same thing for Windows i.e. using the windows binary version of Stockfish named "stockfish_9_x64.exe" and building it as a standalone application, things work perfectly and I am able to communicate with the engine via my C# code.
I researched it online but unable to find much resources and guidance. I found a similar post and reading through it led me conclude that maybe it has something to do with file permissions. The guy who asked this question actually solved the issue by writing these two lines of code:
string[] cmd = { "chmod", "744", Path.Combine(strToFolder, fileName) };
Java.Lang.Runtime.GetRuntime().Exec(cmd);
However he was using Xamarin and had access to Java Runtime library. I am using Unity and C# and I really don't know how to change the execute/run permission of this binary file and run it. In fact I don't even know whether this is the problem or not.
I just want to integrate stockfish into my Unity project with Android as the targeted platform. If anyone has any ideas, suggestions or if anyone has done this before, please guide me. Even if I am wrong from the start and my approach is buggy let me know that as well along with the corrected approach.
Given below is my code:
public class CommunicateWithEngine {
public static Process mProcess;
public static void Communicate()
{
// since the apk file is archived this code retreives the stockfish binary data and
// creates a copy of it in the persistantdatapath location.
string filepath = Application.persistentDataPath + "/" + "Stockfish-9-armv7";
if (!File.Exists(filepath))
{
WWW executable = new WWW("jar:file://" + Application.dataPath + "!/assets/" + "Stockfish-9-armv7");
while (!executable.isDone)
{
}
File.WriteAllBytes(filepath, executable.bytes);
}
// creating the process and communicating with the engine
mProcess = new Process();
ProcessStartInfo si = new ProcessStartInfo()
{
FileName = System.IO.Path.Combine(Application.persistentDataPath, "Stockfish-9-armv7"),
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardError = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
};
mProcess.StartInfo = si;
mProcess.OutputDataReceived += new DataReceivedEventHandler(MProcess_OutputDataReceived);
mProcess.Start();
mProcess.BeginErrorReadLine();
mProcess.BeginOutputReadLine();
SendLine("uci");
SendLine("isready");
}
private static void SendLine(string command) {
mProcess.StandardInput.WriteLine(command);
mProcess.StandardInput.Flush();
}
private static void MProcess_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
string text = e.Data;
Test.PrintStringToTheConsole(text);
}
}
For anyone struggling with the same problem as OP and me. After 12 hours searching and googling here is a solution. You can use executable stockfish binary, but you have to change extension for binary to .so and import it in unity in folder /Assets/Plugins/Android. After build you can find it on device in folder /data/data//lib. Here you can execute it and get input and output.

Categories