How to load scores in Unity? - c#

I have a simple game published in Google Play. When player wins the game his score should be incremented in leaderboard. My problem is that when player wins the game, app stops. I think that problem is in PlayGamesPlatform.Instance.LoadScores because when I removed this part, no one had a problem. Also, I want to notice that not every player has such problem in game. This problem happens just to those, who haven't ever won the game (they have no score in leaderboard). So, PlayGamesPlatform.Instance.LoadScores works only to those who already have some score in leaderboard.
My script:
PlayGamesPlatform.Instance.LoadScores(GPGSIds.leaderboard_rating, GooglePlayGames.BasicApi.LeaderboardStart.PlayerCentered, 1, GooglePlayGames.BasicApi.LeaderboardCollection.Public, GooglePlayGames.BasicApi.LeaderboardTimeSpan.AllTime, (GooglePlayGames.BasicApi.LeaderboardScoreData data) =>
{
long score;
if (long.TryParse(data.PlayerScore.formattedValue, out score))
Social.ReportScore(score + 50, GPGSIds.leaderboard_rating, (bool success) => { });
else
Social.ReportScore(50, GPGSIds.leaderboard_rating, (bool success) => { });
});

Try this google sample from github
Using PlayGamesPlatform.LoadScores()
This method uses the PlayGamesPlatform directly. This approach provides additional flexibility and information when accessing the leaderboard data.
PlayGamesPlatform.Instance.LoadScores(
GPGSIds.leaderboard_leaders_in_smoketesting,
LeaderboardStart.PlayerCentered,
100,
LeaderboardCollection.Public,
LeaderboardTimeSpan.AllTime,
(data) =>
{
mStatus = "Leaderboard data valid: " + data.Valid;
mStatus += "\n approx:" +data.ApproximateCount + " have " + data.Scores.Length;
});
The parameters for LoadScores() are:
leaderboardId start position (top scores or player centered) row count
leaderboard collection (social or public) time span (daily, weekly,
all-time) callback accepting a LeaderboardScoreData object. The
LeaderboardScoreData class is used to return information back to the
caller when loading scores. The members are:
1. Id - the leaderboard id 2. Valid - true if the returned data is valid (the call was successful) 3. Status - the ResponseStatus of the
call 4. ApproximateCount - the approximate number of scores in the
leaderboard 5. Title - the title of the leaderboard 6. PlayerScore -
the score of the current player 7. Scores - the list of scores 8.
PrevPageToken - a token that can be used to call LoadMoreScores() to
get the previous page of scores. 9. NextPageToken - a token that can
be used to call LoadMoreScores() to get the next page of scores.
void GetNextPage(LeaderboardScoreData data)
{
PlayGamesPlatform.Instance.LoadMoreScores(data.NextPageToken, 10,
(results) =>
{
mStatus = "Leaderboard data valid: " + data.Valid;
mStatus += "\n approx:" +data.ApproximateCount + " have " + data.Scores.Length;
});
}
Additional reference How to get the user score value from Google Play Services Leaderboard.
P.S.:
Try setting the scores of all players to default 0 so players who havent played yet can make calls to loadScores.

Related

How to list all APKs with isGame flag set to true?

I got this code:
_pm = _context.PackageManager;
List<string> packageList = new List<string>();
Intent intent = new Intent(Intent.ActionMain);
intent.AddCategory(Intent.CategoryLeanbackLauncher);
var list = _pm.QueryIntentActivities(intent, PackageInfoFlags.MetaData);
var counter = 0;
foreach (var app in list)
{
counter++;
ApplicationInfo ai = _pm.GetApplicationInfo(app.ActivityInfo.PackageName, 0);
if (filter.Equals(IApplicationsControl.Filter.AppsOnly))
{
if (ai.Category != ApplicationCategories.Game)
{
Android.Util.Log.Debug("pm", counter + ". " + ai.Category + " - " + app.ActivityInfo.PackageName);
packageList.Add(app.ActivityInfo.PackageName);
}
}
}
The output:
1. Undefined - com.android.vending
2. Undefined - com.google.android.youtube.tv
3. Undefined - com.myApp.test1
4. Undefined - com.android.traceur
5. Undefined - com.arris.android.stb.rcu
6. Undefined - com.arris.upgradetest
7. Undefined - com.clearchannel.iheartradio.application.tvapplication
8. Undefined - com.ericsson.tv
9. Audio - com.google.android.music
10. Undefined - com.google.android.play.games
11. Undefined - com.uei.uassample
12. Undefined - com.FDGEntertainment.redball4.gp <--- this is a game
13. Undefined - com.fgol.HungrySharkEvolution <--- this is a game
14. Undefined - com.hyperkani.bomberfriends <--- this is a game
15. Undefined - com.madfingergames.deadtrigger2 <--- this is a game
16. Undefined - com.secretexit.turbodismount <--- this is a game
17. Undefined - com.vectorunit.purple.googleplay
I installed several games, such as Hungry Shark and DeadTrigger2, I opend the APKs and both applications got the isGame:true set in their AndroidManifest.xml files.
The code above is listing the categories of my apps as Undefined, this includes my 2 games, it's like that for nearly all of my apps, except some AUDIO app that plays music.
So, in the end, why does my code not work?
I was following this links:
How to check if the app is game or not programmatically?
Also, I found this one, that concerns me a lot:
How can check app is game or not android?
So in the end, is it even possible now to check if an app is a game or not?
My API lvl is 28+
Ofcourse, I searched 2 days without an answer, and then finally decided to post a question here, and ofcourse now i found an answer.
_pm = _context.PackageManager;
List<string> packageList = new List<string>();
Intent intent = new Intent(Intent.ActionMain);
intent.AddCategory(Intent.CategoryLeanbackLauncher);
var list = _pm.QueryIntentActivities(intent, PackageInfoFlags.MetaData);
foreach (var app in list)
{
ApplicationInfo ai = _pm.GetApplicationInfo(app.ActivityInfo.PackageName, 0);
var allFlags = ai.Flags;
if (allFlags.HasFlag(ApplicationInfoFlags.IsGame))
{
packageList.Add(app.ActivityInfo.PackageName);
}
}
What did I do? I saw, out of pure luck, that the ApplicationInfo variable ai, got a field Flags, that contain the correct flag, (not the flag FLAG_IS_GAME nor ApplicationCategories.Game)) also, I found the right class to pick the IsGame from (ApplicationInfoFlags.IsGame)
The rest is simple.
The conclusion, is that the approach to get the information about the app beeing a game or not about the category, or the FLAG_IS_GAME seems not to work as it should.
This worked for me, and hopefully the next guy in the same problem :)

Unity 2019.2.12f1 PlayerPrefs halting script

I am working on building out an authentication system for a project I am working on.
Part of this is to save UserData locally so that it doesn't have to connect to cloud on every run, or force a login ETC.
The problem i am having, is when i am trying to set PlayerPrefs it is not working. I have it running a Debug.Log before each PlayerPrefs.SetString and it only ever displays the first one.
I am able to do PlayerPrefs.SetString in my Start() but for some reason it is not working here and i have no idea why.
Everything works up until i am saving to PlayerPrefs
public Dictionary<string, string> LoggedUser = new Dictionary<string, string>();
public void getUserData(string id, string email)
{
Debug.Log("Getting User Data for ID: " + id);
FirebaseDatabase.DefaultInstance
.GetReference(id)
.GetValueAsync().ContinueWith(task1 =>
{
if (task1.IsFaulted)
{
Debug.Log("Failed");
}
else if (task1.IsCompleted)
{
Debug.Log("Data Retrieved");
DataSnapshot snapshot = task1.Result;
foreach (DataSnapshot user in snapshot.Children)
{
string firstName = user.Child("firstName").Value.ToString();
string lastName = user.Child("lastName").Value.ToString();
string sex = user.Child("sex").Value.ToString();
string country = user.Child("country").Value.ToString();
string age = user.Child("age").Value.ToString();
string userName = user.Child("userName").Value.ToString();
Debug.Log(firstName);
LoggedUser.Add("FirstName", firstName);
LoggedUser.Add("LastName", lastName);
LoggedUser.Add("Email", email);
LoggedUser.Add("age", age);
LoggedUser.Add("sex", sex);
LoggedUser.Add("country", country);
LoggedUser.Add("userName", userName);
Debug.Log("Welcome " + LoggedUser["FirstName"]);
Debug.Log("User signed in successfully: " +newUser.Email +" " +newUser.UserId);
setPlayer();
}
}
});
}
public void setPlayer()
{
Debug.Log("Saving to PlayerPrefs");
Debug.Log("Setting First Name");
PlayerPrefs.SetString("FirstName", "Ezekiel");
Debug.Log("Setting Last Name");
PlayerPrefs.SetString("LastName", LoggedUser["LastName"]);
Debug.Log("Setting Email");
PlayerPrefs.SetString("Email", LoggedUser["Email"]);
Debug.Log("Setting Age");
PlayerPrefs.SetString("age", LoggedUser["age"]);
Debug.Log("Setting Sex");
PlayerPrefs.SetString("sex", LoggedUser["sex"]);
Debug.Log("Setting Country");
PlayerPrefs.SetString("country", LoggedUser["country"]);
Debug.Log("Setting userName");
PlayerPrefs.SetString("userName", LoggedUser["username"]);
Debug.Log("Setting Loggedn State");
PlayerPrefs.SetInt("LoggedIn", 1);
Debug.Log("Saving Player Prefs");
PlayerPrefs.Save();
Debug.Log("Welcome " + PlayerPrefs.GetString("username"));
}
If you don't mind, I can expand on your answer a little bit.
If you use ContinueWithOnMainThread instead of ContinueWith, your continuation logic automatically occurs on the main thread (so you can write PlayerPrefs). I cover a whole ton of ways to handle threading with Firebase and Unity in this article if you'd like to compare them.
Furthermore, this is a stab in the dark, but if you're using Realtime Database then you may also be using Firebase Authentication. If this is the case, then FirebaseAuth.DefaultInstance.CurrentUser actually persists between runs of your game (I cover this a little bit in this video). Since Realtime Database also caches data you request locally, you may actually be doing extra work that the Firebase plugins will handle for you!
I was able to find the solution.
getUserData() method is running async, which creats a new thread. the PlayerPrefs can only run on a main thread.
My solution was to create a boolean that i flippd to true when the Data was loaded into LoggedUser. my Update() method was watching for that to flip to true, where it then called the setPlayer().
Than you all for the help!
You are setting userName
PlayerPrefs.SetString("userName", LoggedUser["username"]);
and retrieving username
Debug.Log("Welcome " + PlayerPrefs.GetString("username"));
Also it should be
PlayerPrefs.SetString("userName", LoggedUser["userName"]);
instead of
PlayerPrefs.SetString("userName", LoggedUser["username"]);

Unity google play games realtime message not send

So i'm currently working on a game with unity, it's an air hockey. And i would like to add a multiplayer mode (1 vs 1).
So after the player have a match with an opponent, they are connected in a room where the game begins.
But i'm having issue when i want to receive the opponent message.
In the player script movement, i add this on the void update()
Multiplayer.Instance.SendMyUpdate(positionX, PositionZ);
and in the multiplayer script, i add this:
public void SendMyUpdate(float posX, float posZ) {
string PlayerUserNameString = PlayGamesPlatform.Instance.RealTime.GetSelf ().DisplayName;
char[] characters = PlayerUserNameString.ToCharArray ();
string data = characters + ":" + posX + ":" + posZ;
byte[] bytedata = System.Text.ASCIIEncoding.Default.GetBytes (data);
PlayGamesPlatform.Instance.RealTime.SendMessageToAll (false, bytedata);
}
And on the method OnRealTimeMessageReceived:
string rawdata = System.Text.ASCIIEncoding.Default.GetString (data);
string[] cut = rawdata.Split (new string[] { ":" }, System.StringSplitOptions.RemoveEmptyEntries);
OpponentUserName = System.Convert.ToSingle (cut[1]).ToString();
Transform target = GameObject.Find ("mallet Opponent").transform;
Vector3 newpos = new Vector3
(
System.Convert.ToSingle(cut[2]),
0,
System.Convert.ToSingle(cut[3])
);
After i wrote this and build it on two devices, when the room is connected and the game begins, the opponent player doesn't move at all, and i don't know where the issue.
Any ideas?
Arrays are zero based so opponent user name should be cut[0] and:
System.Convert.ToSingle(cut[3])
cut[3] will look for the 4th split result and there are only three so an exception will occur. That is enough to prevent the method working and the position updating. If so there should also be an error in the console log.
However perhaps the OnRealTimeMessageReceived is not even being called. You need to throw in some breakpoints and debug, or add some debug logs to see how far things are getting. If it isn't even getting to a method you expect then the question can be rephrased "why is method X not being called"

Socket connection from Unity to retrieve SUMO's vehicles

I would like to generate a 3D scenario for a traffic simulation.
The main idea would be having SUMO running a simulation and then getting the direction, speed and coordinates (X,Y) from each vehicle, so that I would create 3D models for this cars.
For this purpose, I was thinking about using some kind of TCP/IP communication between Unity and SUMO. Since this is possible while communicating SUMO with a network simulator such as OMNeT++, I was wondering if this would also be possible. I don't need to control the simulation in SUMO from Unity, just retrieve data regarding the vehicles in the network.
Unfortunately, I have no remarkable experience with Unity, so I cannot provide any code trying to achieve this...
EDIT:
As requested, I included some code. However, I only have code in Java.
String configFile = "test/resources/sumo_maps/Test2/Test2.sumo.cfg";
SumoTraciConnection trial = new SumoTraciConnection(configFile,-1);
trial.runServer();
Collection<Vehicle> vehicles = trial.getVehicleRepository().getAll().values();
for(Vehicle car : vehicles){
bw.write(time + " // The vehicle with ID: " + car.getID()+ " is driving "
+ "with a speed of "+ car.getSpeed() + " and is in coordinates x: " +car.getPosition().getX()+
" and y: " + car.getPosition().getY());
bw.newLine();
}
Now, let's proceed to get a bit into the class SumoTraciConnection and its methods. This class is part of the mentioned (in the comments) library Traci4j.
It can be found in GitHub in case you need more info: https://github.com/egueli/TraCI4J/blob/master/src/java/it/polito/appeal/traci/SumoTraciConnection.java
The constructor:
public SumoTraciConnection(String configFile, int randomSeed) {
this.randomSeed = randomSeed;
this.configFile = configFile;
}
Now the runServer() method (I put the one with a boolean argument because if no parameter is given then it is automatically called with a false) Basically, this boolean is used to determine wheter the GUI version of SUMO or the console version will be ran:
public void runServer(boolean withGui) throws IOException, InterruptedException {
retrieveFromURLs(); //Checks if the configFile given has an "http://" at the beggining, in order to download the file
int port = findAvailablePort(); //creates a Socket and finds a port with ServerSocket.getLocalPort()
runSUMO(port, withGui); //It is used to run SUMO with different options, such as the configFile for the simulation, the remote port... sumoProcess is set here as: sumoProcess = Runtime.getRuntime().exec(argsArray);, where argsArray contains the different options mentioned
tryConnect(InetAddress.getLocalHost(), port, sumoProcess); // tryConnect basicaly calls this method tryConnectOnce, which connects as a client to the sumo process mentioned before, and does some checks that everything is correct.
postConnect(); //I will explain this function after
}
postConnect() initialices the DataInput and DataOutput streams and creates the repositories. I show now the relevant parts of the code:
dis = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
dos = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
vehicles = new HashMap<String, Vehicle>();
edgeRepo = new Repository.Edges(dis, dos, newIDListQuery(Constants.CMD_GET_EDGE_VARIABLE));
addStepAdvanceListener(edgeRepo);
laneRepo = new Repository.Lanes(dis, dos, edgeRepo, newIDListQuery(Constants.CMD_GET_LANE_VARIABLE));
vehicleListQuery = newIDListQuery(Constants.CMD_GET_VEHICLE_VARIABLE);
addStepAdvanceListener(new StepAdvanceListener() {
public void nextStep(double step) {
vehicleListQuery.setObsolete();
}
});
vehicleListBefore = new HashSet<String>(vehicleListQuery.get());
vehicleRepo = new Repository.Vehicles(dis, dos, edgeRepo, laneRepo, vehicles, vehicleListQuery);
addStepAdvanceListener(vehicleRepo);
Where one StepAdvanceListener is just the following(I cannot explain exactly what is this for but I understand that is something that allow us to realize the new simulationstep has been done, so we have to update the repositories):
//Interface for an object that can be notified when the simulation advances by one step.
public interface StepAdvanceListener {
/**
* Callback for step advancement.
* #param step the new simulation time, in seconds
*/
void nextStep(double step);
}
Up to here, it would be the part related to the connection with SUMO. In the next edit (I need some rest right now..) I'll put the parts related with the Repositories and the Data retrieval
Thanks in advance!

Using webdriver PageFactory to pick certain page

I have a web project where clicking a button navigates to another page. The new page can be 1 of three possible pages depending on data in the server. (The url may be the same for 2 of those pages)
I have three classes representing expected elements on each page using the PageObject model.
What is the best way to actually find what page actually got loaded? Is there an OR type of wait that I can wait on three unique elements and get the one that actually got loaded?
Yes, it is possible to check the presence of unique element (which identifies the page) and then return respective page in the framework.
However, a test should know the page it is expecting next and should assume that the correct page has loaded and perform further actions/assertions. You can even put an assertion here to verify correct page has loaded. If a different page has loaded, then the test eventually fails as assertions would fail.
This way test becomes more readable and describes flow of application.
Also, setting up test data upfront for the tests, is always advisable. This way you would know what data is available on server and test would know which page would render.
I had a similar issue where I needed to detect if a login was for a new user (the login page then goes to a terms & conditions page rather than direct to the home page).
Initially I just waited and then tested the second page but this was just a pain so I came up with this.
To Test the result with this:
var whichScreen = waitForEitherElementText(By.CssSelector(HeaderCssUsing), "HOME SCREEN", "home", terms.getHeaderLocator(), terms.headerText, "terms", driver, MAX_STALE_RETRIES);
if(whichScreen.Item1 && whichScreen.Item2 == "terms")
{
terms.aggreeToTerms();
}
The method that this calls is :
protected Tuple<bool, string> waitForEitherElementText(By locator1, string expectedText1, string return1Ident,
By locator2, string expectedText2, string return2Ident, IWebDriver driver, int retries)
{
var retryCount = 0;
string returnText = "";
WebDriverWait explicitWait = new WebDriverWait(driver, TimeSpan.FromSeconds(globalWaitTime));
driver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(0.5));
while (retryCount < retries)
{
try
{
explicitWait.Until<bool>((d) =>
{
try
{
if (Equals(d.FindElement(locator1).Text, expectedText1)) { returnText = return1Ident; };
}
catch (NoSuchElementException)
{
if (Equals(d.FindElement(locator2).Text, expectedText2)) { returnText = return2Ident; };
}
return (returnText != "");
});
return Tuple.Create(true, returnText);
}
catch (StaleElementReferenceException e)
{
Console.Out.WriteLine(DateTime.UtcNow.ToLocalTime().ToString() +
":>>> -" + locator1.ToString() + " OR " + locator2.ToString() + "- <<< - " +
this.GetType().FullName + "." + System.Reflection.MethodBase.GetCurrentMethod().Name +
" : " + e.Message);
retryCount++;
}
}
return Tuple.Create(false,"");
}
The explicit wait until uses a boolean so will loop around for the full wait time (I have a very slow Test server so I set this to 60 seconds). the implicit wait is set to half a second so the element tests will attempt every half a second and loop around until either true is returned or it fails.
I use a Tuple so that I can detect which screen I am on, and in this case agree to the terms & conditions which then sets me back on my normal page path

Categories

Resources