Intermittent NSTimer problem in Release mode on device - iphone

I am having a problem where most, but not all, of the time on my device my NSTimer action is not being called when compiled in Release mode. It's always fine in Debug mode on the device, and it's always fine in either mode in the simulator.
The only thing that's slightly unusual about this situation is that it's wrapped with another class to allow us to inject platform-specific implementations of things like timers at runtime, thinking forwards to monodroid etc. Nothing particularly unusual going on though.
Code:
using System;
using MonoTouch.Foundation;
namespace OurCompany.PlatformAbstraction.Ios
{
public class IosTimer : IPlatformTimer
{
private NSTimer backingTimer;
public double IntervalMs{get; set;}
public IosTimer(double intervalMS)
{
this.IntervalMs = intervalMS;
}
public event EventHandler Elapsed;
private void NsTimerElapsed()
{
if (Elapsed != null)
{
Elapsed(this, EventArgs.Empty);
}
}
public void Start ()
{
TimeSpan ts = TimeSpan.FromMilliseconds(this.IntervalMs);
this.backingTimer = NSTimer.CreateRepeatingScheduledTimer(ts, NsTimerElapsed);
}
public void Stop ()
{
this.backingTimer.Invalidate();
this.backingTimer = null;
}
}
}
Calling code:
private IosTimer t;
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
t = new IosTimer(100);
t.Elapsed += UpdateLabel;
t.Start();
}
private void UpdateLabel(object sender, EventArgs e)
{
// not being called in Release mode on the phone
// works fine in Debug mode on the phone, works fine in both modes in the simulator
}
I'm also noticing general behaviour differences - where something works fine in the simulator but not on the device. Also slight behaviour changes given two identical deployments of the exact same code to the same device(!)
Posted this yesterday on the MonoTouch forums but it seems a bit quiet over there.
Thanks in advance.

Transpired this was threading related. Solved by using InvokeOnMainThread() in my Elapsed event handlers.

Related

Unity & PhotonEngine. After scene reaload Joining to Lobby, CreateRoom and JoinRandom functions called repeatedly

I ran into a problem in the last step of a test project using Photon Network. When you first connect and join the room, everything goes without errors. However, after completing the match, exiting the room, and using LoadScene(), errors appear:
JoinLobby operation (229) not called because client is not connected or not yet ready, client state: JoiningLob <- in OnConnectedToMaster()
Through experience, I realized that the ConnectUsingSettings() methods and other Photon methods are called multiple times. But the connection to the lobby happens and I can create a room, but I immediately encounter MissingReferenceException errors.
I've seen a solution from guys who ran into this very same problem. The problems arose because of the events. Wherever this could happen, I unsubscribed from the events, but that doesn't help. What else can cause such problems, because I obviously missed something that prevents me from completely closing the scene during the transition?
Sorry for my language, used Google Translate
Code:
LobbyManager.cs
private void StartConnect()
{
PhotonNetwork.NickName = master.GameSettings.NickName;
PhotonNetwork.GameVersion = master.GameSettings.NickName;
PhotonNetwork.ConnectUsingSettings();
PhotonNetwork.AutomaticallySyncScene = true;
}
public override void OnConnectedToMaster()
{
Debug.Log("Connected to server");
if(!PhotonNetwork.InLobby) PhotonNetwork.JoinLobby();
}
public override void OnJoinedLobby()
{
onConnected.Invoke();//This use for show UIElements on Canvas
}
JoinRandomRoom class
public void OnClick_JoinRandomRoom()
{
if (!PhotonNetwork.IsConnected) return;
if (GameModeGlobalData.SelectedGameMode != null)
{
SetRoomOptions();
PhotonNetwork.JoinRandomRoom(expectedRoomProperties, GameModeGlobalData.SelectedGameMode.MaxPlayers);
}
}
public override void OnJoinRandomFailed(short returnCode, string message)
{
Debug.Log("Join random failed: " + message + ". Room will be created...");
_createRoomMenu.CreateAndJoinRoom();
}
public void SetRoomOptions()
{
expectedRoomProperties[RoomData.GAME_MODE] = GameModeGlobalData.SelectedGameMode.GameModeName;
}
private void OnDisable()
{
ShowPanels.RemoveAllListeners();
}
And CreateRoom.cs
private ExitGames.Client.Photon.Hashtable _roomCustomProperties = new ExitGames.Client.Photon.Hashtable();
public void CreateAndJoinRoom()
{
if (!PhotonNetwork.IsConnected) return;
if (GameModeGlobalData.SelectedGameMode != null)
{
RoomOptions roomOptions = GetCustomRoomOptions();
roomOptions.CleanupCacheOnLeave = true;
PhotonNetwork.CreateRoom(randomRoomName, roomOptions);
}
}
public RoomOptions GetCustomRoomOptions()
{
RoomOptions options = new RoomOptions();
options.MaxPlayers = _maxPlayer;
options.IsOpen = true;
options.IsVisible = true;
string[] roomProperties = new string[]{ RoomData.GAME_MODE };
_roomCustomProperties[RoomData.GAME_MODE] = GameModeGlobalData.SelectedGameMode.GameModeName;
options.CustomRoomPropertiesForLobby = roomProperties;
options.CustomRoomProperties = _roomCustomProperties;
return options;
}
The project has grown, and I blame myself for not testing it at the very beginning. Didn't think there would be problems at this stage
Sorry for this post. Its resolved. For those who may encounter this in the future, in addition to unsubscribing from events, check all classes that inherit from MonoBehaviourPunCallbacks for overridden OnDisable() methods.
Like this:
public override void OnDisable()
{
base.OnDisable();
}
This in turn will call the
PhotonNetwork.RemoveCallbackTarget(this);
Also, from the documentation:
Do not add new MonoBehaviour.OnEnable or MonoBehaviour.OnDisable. Instead, you should override those and call base.OnEnable and base.OnDisable.
I forgot about it and used MonoBehaviour.OnDisable.

Automatically open UWP app that launches on startup

I am working on a UWP app generated by Unity. Following the documentation on StartUpTasks here I have set the app to launch at startup, however when it does it launches minimized in the taskbar. I need the app to be open when it launches, but do not know what to call and where to make this happen.
This is the code generated by Unity:
namespace UnityToUWPApp
{
class App : IFrameworkView, IFrameworkViewSource
{
private WinRTBridge.WinRTBridge m_Bridge;
private AppCallbacks m_AppCallbacks;
public App()
{
SetupOrientation();
m_AppCallbacks = new AppCallbacks();
}
public virtual void Initialize(CoreApplicationView applicationView)
{
applicationView.Activated += ApplicationView_Activated;
CoreApplication.Suspending += CoreApplication_Suspending;
// Setup scripting bridge
m_Bridge = new WinRTBridge.WinRTBridge();
m_AppCallbacks.SetBridge(m_Bridge);
m_AppCallbacks.SetCoreApplicationViewEvents(applicationView);
}
private void CoreApplication_Suspending(object sender, SuspendingEventArgs e)
{
}
private void ApplicationView_Activated(CoreApplicationView sender, IActivatedEventArgs args)
{
CoreWindow.GetForCurrentThread().Activate();
}
public void SetWindow(CoreWindow coreWindow)
{
m_AppCallbacks.SetCoreWindowEvents(coreWindow);
m_AppCallbacks.InitializeD3DWindow();
}
public void Load(string entryPoint)
{
}
public void Run()
{
m_AppCallbacks.Run();
}
public void Uninitialize()
{
}
[MTAThread]
static void Main(string[] args)
{
var app = new App();
CoreApplication.Run(app);
}
public IFrameworkView CreateView()
{
return this;
}
private void SetupOrientation()
{
Unity.UnityGenerated.SetupDisplay();
}
}
}
How can I ensure that when the app starts it is open and active?
UWP apps that are set as Startup task get launched as minimized/suspended by design. This is to ensure a good user experience for Store app by default and avoid having a ton of apps launch into the user's face on boot.
Classic Win32 apps as well as desktop bridge apps can continue to start in the foreground for backwards compat/consistency reasons.
To accomplish your goal, you can include a simple launcher Win32 exe in your package and set that as startup task. Then when it starts you just launch the UWP from there into the foreground. Note that doing this will require you to declare the "runFullTrust" capability, which will require an additional onboard review for the Microsoft Store.
To declare the Win32 exe as startup task, follow the "desktop bridge" section from this doc topic:
https://learn.microsoft.com/en-us/uwp/api/Windows.ApplicationModel.StartupTask

Unity GestureRecognizer ManipulationStarted and -updated are not working

Please look at the code below, if I use this structure for Tap, Hold and Navigation in Unity for Hololens, it works as expected. But Manipulation does not even get called. I looked at Holokit but I could not understand how holoKit is firing them. I also do not want to import this heavy Holokit on my simple, light project. I am really thankful, anybody can tell me how I can use a simple Gesture Recognizer Manipulation delegate.
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.WSA.Input;
namespace Assets.Scripts
{
public class GestureRecognizerManager : MonoBehaviour
{
private GestureRecognizer _recognizer;
private void Awake()
{
_recognizer = new GestureRecognizer();
_recognizer.ManipulationStarted += RecognizerOnManipulationStarted;
_recognizer.ManipulationUpdated += RecognizerOnManipulationUpdated;
_recognizer.StartCapturingGestures();
}
private void RecognizerOnManipulationUpdated(ManipulationUpdatedEventArgs obj)
{
Debug.Log("D");
}
private void RecognizerOnManipulationStarted(ManipulationStartedEventArgs obj)
{
Debug.Log("K");
}
private void OnApplicationQuit()
{
_recognizer.ManipulationStarted -= RecognizerOnManipulationStarted;
_recognizer.ManipulationUpdated -= RecognizerOnManipulationUpdated;
_recognizer.StopCapturingGestures();
_recognizer.Dispose();
}
}
}
Ok, it works by this line of code in initialization stage:
_recognizer.SetRecognizableGestures(GestureSettings.ManipulationTranslate);

Unity Adding points to a user only once after collision

So I'm getting ready to create my first game, I just finished classes on the C# language so I apologize if I'm using stuff such as interfaces wrong and all that. However, for my question; I'm trying different things and seeing what works. I've created a coin, and a player. The coin works as it should, however sometimes when I collect it, it will give me twice the points it should. The coins value is 15, sometimes when I collect a coin it'll add 15 points, other times it will add 30. How do I prevent this from happening.
Here's my code:
Coin Controller Class:
public class CoinController : MonoBehaviour, IEconomy {
private int MoneyValue;
void Start () {
MoneyValue = 15;
}
void Update () {
}
void OnTriggerEnter(Collider col) {
if (col.CompareTag("Player")) {
Destroy(transform.gameObject);
Value();
}
}
public int Value() {
return EconomyController.Money += MoneyValue;
}
}
Economy Controller:
public class EconomyController : MonoBehaviour{
public static int Money;
void Start() {
Money = 0;
}
}
Economy Interface:
public interface IEconomy {
int Value();
}
I would like to point some things about your code:
A good practice when declaring variables is using lowerCamelCase:
thisIsLowerCamelCase
ThisIsNot
This is a variable name convention that is largely used in programming to differentiate Methods and Classes from variables.
Another thing I've noticed is that your "Money" variable is static and it is still being updated on your CoinController. I'd set this variable to be private int variable and use a setter to update it. With that in mind... Have you tried to use Debug.Log to check if the OnTriggerEnter is triggering twice before the object is destroyed?
Simply write:
Debug.Log ("This should only happen once!");
And play the game. If your console shows this message two times, this trigger is being called twice. Another thing that you might notice is that you are calling the Value () method after you called the Destroy (transform.gameObject).
I would do something like:
public class CoinController : MonoBehaviour{
private int moneyValue = 15;
private EconomyController economyController;
void Start (){
economyController = FindObjectOfType (typeof (EconomyController)) as EconomyController;
}
void OnTriggerEnter (Collider col) {
if (col.CompareTag("Player")) {
AddValue();
}
}
public int AddValue() {
EconomyController.money += moneyValue; //Option one.
EconomyController.AddMoney (moneyValue) ; //Option two.
DestroyGameObject ();
}
private void DestroyGameObject (){
Destroy(transform.gameObject);
}
}
Using the clean code principles, option 2 is using a public void function created inside the EconomyController class changing a private variable.
My intuition tells me that you are probably collecting two coins at the time. I'm not sure how you are setting out the coins but I've had a similar problem before.
Imagine a game of snake. Lets say you've programmed it so once you eat a square you create a new one to a random location. There is a probability that the new square would appear inside the snake so it would instantly be eaten. This could be why it happens only some of the time.
Try disabling the collider before you destroy it.
Destroying a gameobject isn't instant and it's (annoyingly) quite easy to set off triggers multiple times.
void OnTriggerEnter(Collider col) {
if (col.CompareTag("Player")) {
// Pseudo Code: GetComponent<TheColliderItIs>().Enabled = false;
Value();
Destroy(transform.gameObject);
}
}

Unity Google Play Services

I am trying to get Google play services into the game I have developed. Here is the script I have on my main screen. I get no response out of it at all. I have tried all the different SHA1 codes and I am not sure what is wrong. Any Ideas???
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GooglePlayGames;
using UnityEngine.UI;
using GooglePlayGames.BasicApi;
using UnityEngine.SocialPlatforms;
public class GPS_Main : MonoBehaviour {
private bool IsConnectedToGoogleServices;
public Text SignIn;
private void Awake()
{
PlayGamesClientConfiguration config = new PlayGamesClientConfiguration.Builder().Build();
PlayGamesPlatform.InitializeInstance(config);
PlayGamesPlatform.Activate();
}
// Use this for initialization
void Start () {
LogIn();
}
// Update is called once per frame
void Update () {
}
void LogIn()
{
Social.localUser.Authenticate(success => { });
}
public bool ConnectToGoogleServices()
{
if (!IsConnectedToGoogleServices)
{
Social.localUser.Authenticate((bool success) =>
{
IsConnectedToGoogleServices = success;
});
}
return IsConnectedToGoogleServices;
}
public static void ToAchievementUI()
{
if (Social.localUser.authenticated)
{
Social.ShowAchievementsUI();
}
else
{
Debug.Log("Not authenticated");
}
}
}
This has really been an annoying event. I have been through many videos and books trying to find the correct fix.
There are many things that cause this to happen, the best way to find it is to try connecting your phone and then using adb logcat to see what is causing the problem.
Also i have found a little bug in your function ConnectToGoogleServices :
public bool ConnectToGoogleServices()
{
if (!IsConnectedToGoogleServices)
{
Social.localUser.Authenticate((bool success) =>
{
IsConnectedToGoogleServices = success;
});
}
return IsConnectedToGoogleServices;
}
This function is always returning IsConnectedToGoogleServices initial state.
I tried a bit of explanation in this post Google Play Sign in for Unity
, however I can't understand from your question what are all options you have tried and where you are stuck in your problem. 6 months old question at the time of me writing this. Hope you've sorted this out already. If so, please post your findings here that may help others.
For anyone landing on this question for an answer, pls refer to my answer on the other post (link above) if that is of any help for your problem and also note down the problem in the code (on the question), I think AminSojoudi tried pointing it out as well. Social.localUser.Authenticate() is taking the argument of a callback function (refer documentation). So don't expect it to assign IsConnectedToGoogleServices the result (success or failure) within ConnectToGoogleServices() scope itself. If Authenticate() call runs faster than your code execution, you may get a success, but that won't happen and your function won't return the actual success status of Authenticate() function call anytime. If your rest of the code (leaderboard, achievements) relies on IsConnectedToGoogleServices Boolean flag, then those will not work as well.
public bool ConnectToGoogleServices()
{
if (!IsConnectedToGoogleServices)
{
Social.localUser.Authenticate((bool success) =>
{
IsConnectedToGoogleServices = success; // <-- callback result
});
}
return IsConnectedToGoogleServices; // <-- this won't return the result of a callback result.
}