I wrote a class that, given a seed and difficulty, will return a playing field to my game. The generation is consistent (no matter what, the same seed & difficulty level will always result in the same play field). As far as I know all android devices use Java 1.6 so here goes my question(s):
Is it safe to send only the seed and difficulty to other devices in a multiplayer environment?
Do I need to worry about when Google updates Java version level form 1.6? or will they likely update all android devices to that version level (I am assuming the Random class will have been changed)? And if not what would be a good way to detect if Random class is different?
Rephrased, what precautionary measures should be in place to ensure that the class java.util.Random, which my field generation class uses heavily, will result in the same play field for every device? Or, alternatively, would it be more wise to consider sending all play field data to the non-hosting device(s)?
I could probably accomplish the latter with a reliable message with size of:
byte[ROWS * COLUMNS]
In advance, I appreciate any guidance/suggestions in this matter. This is a difficult issue to search for so some links for future views may be appropriate.
There are a few options here, but I guess I was hoping for some magic JVM property defining the java.util.Random class revision version.
First option is to check the java version and compare it against the other device's version. If they are the same it is safe (as far as I know) to assume that the Random class is the same and thus the seed and difficulty can be sent. If, however, they are different you either send all the data or check the documentation/version release notes yourself to see when the Random class was changed and then determine if all the data should be sent based on previously acquired java version identifier.
The second option is to simply always send all the data. Which is what I will personally be doing.
If you're not as lucky as I and your data exceeds the value of Multiplayer.MAX_RELIABLE_MESSAGE_LEN (in bytes) you may have to break the data into multiple messages which could get ugly but is entirely doable.
Related
I'm using the below function to generate UUID
UUID.randomUUID().toString()
In production we have 50+ servers (application server - each is a JVM on its own) and for requests that land in these servers, as a first step we generate a UUID which essentially uniquely identifies a transaction.
What we are observing is that in Server 6 and Server 11, the UUIDs generated are matching at least for 10 to 15 messages per day which is strange because given the load i.e. about 1 million transactions a day, these UUIDs being duplicate within the same day is very odd.
This is what we have done so far
Verified the application logs - we didn't find anything fishy in there, all logs are as normal
Tried replicating this issue in the test environment with similar load in production and with 50+ servers - but this didn't happen in the test environment
Checked the application logic - this doesn't seem to be an issue because all other 48 servers except 6 and 11 which have a copy of the same code base is working perfectly fine and they are generating unique UUIDs per transaction.
So far we haven't been able to trace the issue, my question is basically if there is something at JVM level we are missing or UUID parameter that we need to set for this one off kind of an issue?
Given time, I'm sure you'll find the culprit. In the meantime, there was a comment that I think deserves to be promoted to answer:
You are generating pseudo random UUIDs at multiple locations. If you don't find other bugs, consider either generating all the pseudo random UUIDs at one location, or generate real random UUIDs
So create a UUID server. It is just a process that churns out blocks of UUIDs. Each block consists maybe 10,000 (or whatever is appropriate) UUIDs. The process writes each block to disk after the process verifies the block contains no duplicates.
Create another process to distribute the blocks of UUIDs. Maybe it is just an a web service that returns an unused block when it gets a request. The transaction server makes a request for a block and then consumes those UUIDs as it creates transactions. When the server has used most of its assigned UUIDs, it requests another block.
I wouldn't waste time wondering how UUID.randomUUID() is generating a few duplicate UUIDs per day. The odds of that happening by chance are infinitesimal. (Generating a whole series of duplicates is possible—if the underlying RNG state is duplicated, but that doesn't seem to be the case.)
Instead, look for places where a UUID stored by one server could be clobbering one stored by another. Why does this only happen between 2 servers out of 50? That has something to do with the details of your environment and system that haven't been shared.
As stated above, the chances of a legit collision are impossibly small. A more likely possibly is if the values are ever transferred between objects in an improper way.
For languages like Java that behave as pass by reference, consider the following scenario
saveObject1.setUUID(initObj.getUUID())
initObj.setUUID(UUID.randomUUID());
saveObject2.setUUID(initObj.getUUID())
In this case saveObject1 & saveObject2 will have the same value, because they are both pointed to the same object reference (initObj's UUID reference).
An issue like this seems more likely than the actual UUIDs being a collision, esp if you can reproduce it. Naturally if it doesn't happen all the time it's probably something more complex, like a rare race condition where initObj doesn't get reinitialized in time, causing saveObject1 & 2 to share the same object reference.
I'm making a networked card game that will be played on android and PC.
To handle stuff like shuffling the cards before the game starts and choosing who goes first (and a couple other things like that) I want to use java.util.Random and set a seed on the server and all of the clients to be the same (generated by the server).
This seems to be the easiest way, and more efficient than sending a long message containing the sequence of all 52 cards in the deck shuffled by the server
Is this something I can count on to always generate the same numbers from the same seed on different kind of JVMs/JREs etc (I'm mainly thinking about various versions of android and different versions of dalvik JVM used by android and other things), or should I go the route of shuffling the cards on the server and sending the card list to all the players? (or is there something I can use besides java.util.Random?)
Since standard javadoc states that Random must behave the same in all plattforms, you should trust that. Nevertheless, you could let Random appart and code your own algorithm to produce pseudo-random numbers: For example: Imagine a SINE-based function:
double myRandom=amplitude*Math.sin(frequency * sequence)
... where amplitude is the upper bound of your numbering interval (52), and frequency should be a high constant value, non multiple of PI. And sequence should start by a constant offset value and be incremented every time you get a new random value.
Choosing accurately a value for the frequency, you could also ensure that your algorithm won't produce repeated values within a certain number of iterations.
According to javadoc, all implementations are required to be the same.
Java implementations must use all the algorithms shown here for the
class Random, for the sake of absolute portability of Java code.
http://docs.oracle.com/javase/6/docs/api/java/util/Random.html
I just moved my code from one machine to another, released it and suddenly it created an entry with a key of "576728208506880" so I re-released the exact same code from the original machine and created another field and this time the key created was "21134006"
Can anyone shed any light on why this might be?!
Thanks,
J
It's perfectly normal. App Engine generates numeric IDs between 0 and 2^53, and scatters them out throughout the entire range:
http://googlecloudplatform.blogspot.ca/2013/05/update-on-datastore-auto-ids.html
You can hack around it a bit by using the legacy auto id policy in your settings.
Appengine datastore IDs are not generated sequentially.
(Imagine that you had a burst of 1,000 new entities created in the same second - the short answer is that AppEngine needs a strategy to generate IDs that won't collide).
See this answer for more details and a potential solution.
See "Assigning Identifiers" of the AppEngine docs for more information.
I'm playing around with OSCeleton and Processing and succesfully got to track skeletons and do stuff.
What I'm wondering is if there's any way to change the delay time a "lost_user" message is sent to Processing.
This is taking so long for what I'm trying to achive, since i need to stop tracking a user as soon as he goes away from the screen, so I can accept another user's interaction. (imagine an installation where a lot of people wants to play with).
any help/tips would be really appreciated.
Jon
As far as I can tell from the OSCeleton's source and with my minimal experience with the kinect(I never used OSCeleton), there is no way to modify that code to do that. It seems to be a thing handled even lower, by the driver or by the kinect its self(?).
Yet you need not bind yourself with that, and I would suggest a couple of ways to bypass the problem if I understand properly.
First, the latest drivers and examples should have multi-user support, meaning you can just arrange who is your main user. From what I can tell from the source you do get an osc message in Processing when a new user is detected as well as an ID number. You can put each new user that arrives, into an arrayList and figure out a way to do things without depending on the latest user.
If you are still going for the user-after-user thing though, or I was mistaken about the multi-user support(which is mentioned nowhere in the README), you can check yourself whether a user has left the area. Although you can not get a definitive answer like that you can check for example, whether a specific joint or all joints of a user have moved in the last 10-20 osc messages received. That probably means storing the position of this joint in an 10-20 item array and continuously updating while also doing a check on whether the items are different. If all items in the array are the same, your user has not moved a bit and thus probably should not be taken to account.
Last but not least you can switch to other solutions. The one I used about a year ago was "Synapse for Kinect" which also seems stale now. The latest you can use is a Processing library called SimpleOpenNI which definitively have multi-user tracking and you won't need any intermediary programs running to give you the joints.
I hope this helps
After reading this answer:
best way to pick a random subset from a collection?
It got me wondering, how does one pick a random seed in Java?
And don't say use System.currentTimeMillis() or System.nanoTime(). Read the article to see why not.
That's a hard question, but let me make it harder. Let's say you need to generate a random seed without connecting to the internet, without using user input (IE, there's no gui), and it has to be cross platform (therefore no JNI to access hardware).
Is there some JVM variables we can monitor as a source of our randomness?
Can this be done? Or is it impossible?
Take a look at Uncommons Maths (full disclosure: I wrote it). It should solve most of the problems you'll ever have with random numbers in Java.
Even, if you don't use it you should be able to get some ideas from the various SeedGenerator implementations it provides. Basically, it defaults to using /dev/random. If that doesn't exist (e.g. Windows) it either tries to download data from random.org or it uses SecureRandom.generateSeed.
I think SecureRandom.generateSeed is the best that you can do without relying on anything platform specific or on the Internet.
Combine System.currentTimeMillis() with a global counter that you increment every time you generate the seed. Use AtomicLong for the counter so you can increment with efficiency and thread safety.
"Combine" doesn't mean "add" or "xor" because it's too easy to get duplicates. Instead, hash. You could get complicated and stuff the long and the counter into e.g. 16 bytes and MD5 it, but I would probably use a 64-bit version of the Adler CRC or some other 64-bit CRC.
Um, that article says that 32-bit seeds are bad, but 64-bit seeds are good. System.currentTimeMillis() is a 64-bit seed.