Reputation: 4747
I've built a simple real-time multiplayer math game in Meteor that you can try out here: http://mathplay.meteor.com
When playing locally (using different browsers), everything works fine. But when I play over the Internet with friends, the clients often get out of sync: a question listed as active for one player is actually already solved by another player.
My guess is that some code that should be server-only gets executed on one of the clients instead. Any suggestions on how to debug this behavior?
Here is what happens on the client when user submits an answer:
Template.number_input.events[okcancel_events('#answertextbox')] = make_okcancel_handler({
ok: function (text, event) {
question = Questions.findOne({ order_number: Session.get("current_question_order_number") });
if (question.answer == document.getElementById('answertextbox').value) {
console.log('True');
Questions.update(question._id, {$set: {text: question.text.substr(0, question.text.length - 1) + question.answer, player: Session.get("player_name")}});
callGetNewQuestion();
}
else {
console.log('False');
}
document.getElementById('answertextbox').value = "";
document.getElementById('answertextbox').focus();
}
});
callGetNewQuestion() triggers this on both client and server:
getNewQuestion: function () {
var nr1 = Math.round(Math.random() * 100);
var nr2 = Math.round(Math.random() * 100);
question_string = nr1 + " + " + nr2 + " = ?";
question_answer = (nr1 + nr2);
current_order_number = Questions.find({}).count() + 1;
current_question_id = Questions.insert({ order_number: current_order_number, text: question_string, answer: question_answer });
return Questions.findOne({_id: current_question_id});//current_question_id;
},
Full source code is here for reference: https://github.com/tomsoderlund/MathPlay
Upvotes: 5
Views: 1240
Reputation: 12348
Your problem lies with this:
callGetNewQuestion()
triggers this on both client and server
This will generate a different _id
because of the timing difference, as well as a different question which will then get replaced with that one that the server generated. However, this might not always be the case. This makes it very easy to let things get out of sync, simply because your client is generating its own stuff.
You'll need to figure out a better approach at making sure the client generates the same data as the server. Which can be done by making sure that a random number generator is seeded the same way and thus would give the same random numbers every time. This will resolve any flickering because the values are different.
Then, for the actual bug you might not want to do this:
return Questions.findOne({_id: current_question_id});
But do this instead (only on the client, do nothing on the server):
Session.set('current_order', current_order_number); // ORDER! Not the _id / question_id.
That way, you can put the following in a template helper:
return Questions.findOne({ order_number: Session.get('current_order') });
In essence, this will work in a reactive way on the Collection and not dependent on the return value.
Upvotes: 3