- Home /
How would I use a server to constantly check time to prevent cheating? (Energy System)
I have been searching all over the forums and the internet looking at how other developers have worked out their solution for an energy system using times. (I didnt post the working script with tick timer as it is fairly long, 245 lines, and its a bit messy haha, still a work in progress)
-The Question- To determine whether a user should get an energy, should I just use this IEnumerator to get times every so often, or try to establish an open connection to the server? I want the game to be playable whether the user has an internet connection or not, but to only give energy based off of server times to prevent cheating.
I have finished setting up the high scores and was going to use the same server to access its time, however when i use the WWW form it only opens the connection once and tells me that current time. (even if in update, I will have 50 of the exact same time until an energy is given) Is the suggested way to keep an open connection to the server? or would I just check the time once every time the script is activated? (it is not a singleton, I just have the time checking on one scene, as I don't know how to keep an open connection in unity)
I echoed time very simply on the server side, if you need more information please let me know. I have a working timer for energy using a tick timer, but it is not connected to the server yet. I wanted to know the correct way to handle this task before I set forth and start modifying the scripts. (I did try to modify it to check the server, and realised it was not going to keep the connection open, so that means every time the game wants to check the time it will open a new connection to the server?)
-This is when I tried using IEnumerators-
IEnumerator getTime()
{
string posurl = phpController + "?this is where you would add your secret key";
WWW posgetwww = new WWW(posurl);
yield return posgetwww;
timez = posgetwww.text.Trim();
closeTime = timez;
Save();
Debug.Log("The Time is now: " + timez);
}
with this "timez" will hold the servers echoed time, but again it would only work for when a new time is needed (using energy, or just getting an energy) so the real question is, do most games keep an open connection to decide when to give energy? or do they just check every so often? I figured opening new connections every 2-5 minutes could be costly for the server? but I guess constant connections wouldn't be much better anyway. All help is greatly appreciated!
-edit- The Trim is there because the server sent me the time with a lot of white space, which I didnt think would work
For the time being, I guess I will just get server times every so often, I have been thinking about getting a server time + timeTillNextEnergy and saving that one, then checking the server everytime the scene loads with this script, I just don't think this is the usual solution for this problem.
Sorry to answer your question with another question, but you don't explain why you are not considering Time.realtimeSinceStatup or time += Time.deltaTime or frame counting... so why do you need an extra complex slow fancy solution when there's plenty of simple $$anonymous$$imum impact solutions???
Well, I guess thats what the tick timer was for, I was following a few different tutorials relating to my problem here, and I figured it would be easier to compare DateTimes and TimeSpans than to create timers, I have the option to be 4 different players (which has caused a number of problems but most have been taken care of besides this one) and I am still fairly new to scripting and game development in general. I would use that method if it is easier and could be used when the game is off. I want to create an energy timer that most of the games I have played use. Oh, and this application is being developed for the mobile platform, Android in particular. Another thing to note, I'm new to the usage of co-routines, and the highscores and timer was a good excuse to start learning how to use them, so this is my initial attempt.
The best way to describe what I'm trying to do is the notorious "lives like candy crush system". Basicly every action (playing a level) consumes energy, when the user runs out, they have to wait for the energy to come back. This (hopefully) makes the user want to do well in the level etc. $$anonymous$$ost of the games I have played on mobile using a system like this require a CONSTANT internet connection to even play the game. I want to be able to play the game anytime, while still preventing the user from cheating their system time to gain "energy" quickly. PAD is a good game to use to describe my energy system, however that one also requires a constant connection to internet.
Answer by NoseKills · May 31, 2015 at 11:03 PM
The length of this conversation (and the problems mentioned) is an indication of why Candy Crush / Jelly Splash / Farm Hero Saga don't use this kind of "cheat prevention". It's impossible to do a fool proof system without requiring constant internet connection, and the user has the freedom of choosing when to be connected.
When the user brings the app back to foreground (un-paused or restart), without server time it's impossible to know if the user tampered with time settings or if the app really was paused for 2 weeks... There is no way to run any logic when the app is closed.
Big companies don't do this because the risk of pissing off legit customers with this kind of systems (can't play offline / forgetting to turn on WIFI => energy not charging etc..) greatly outweighs the benefit gotten from it (especially when there's plenty of competition out there that doesn't have these restrictions).
Also if someone really wants to hack, they'll find a way (modifying playerprefs etc. are options. Remember to encrypt them).
I want to be able to play the game anytime, while still preventing the user from cheating their system time to gain "energy" quickly
Also remember to take into consideration situations where the player loses energy when not connected. You can't trust the client time as the reference point for when recharging begun. The player can start playing the game offline for the first time and with the calendar turned back a year. Then when he loses all energy and connects to server, the game will think a year has passed and fill his energy. This can be repeated unless you save the latest server time & energy combo as some kind of a "floor limit" the game won't believe to be true even offline.
You can use UTC time and you don't have to worry about time zones and daylight saving time.
Thank you for the valid points Nose$$anonymous$$ills, I guess my "simple" project will have to make do with what I have, as I wont be moving it to an authoritative server. This being my first game, I will have to accept that nothing will be fool proof and it seems very unlikely I will be able to solve this problem while allowing offline play.
Also, how would I learn about encryption of the playerpref values? I bought a few assets that offer encryption, but I already made my Index saving class before hand and didnt want to move all my code as I am still quite new to program$$anonymous$$g (4 months or so with C#)
One of the assets I bought was the Simple IAP system, that offers encryption
Thank you everyone for the insight, ^^ may we all make captivating games.
You're welcome. Forgive me if my tone sounds a bit pushy after having this conversation about half a dozen times the past year at work ;D
There's a few plug-ins on the asset store that can do encrypted playerprefs. I haven't tried many of them but this one https://www.assetstore.unity3d.com/en/#!/content/10395 offers that and much more.
it's cool, that's sweet you get to do this for work, that is what I'm trying to do at the moment here, and I figured I have not seen any game even attempt to try a solution like this so why not be one of the first? I'll have to look into that asset more later, as I'm strapped for funds right now, it looks really good and thank you for the tip! I wish you well with your mesh vertex's my friend, I wish I could help as well, happy dev'ing!
Answer by starikcetin · May 31, 2015 at 08:52 PM
It will be more likely an idea rather then solution but, if you store the "process" time rather than "finish" time, then changing the clock will only change when the process finished, not the total time.
Detailed explain:
Look two examples below:
1- You have a variable that keeps the end time. For example action happened at 03.00 and you need to wait one hour for it. So your variable will hold the info "04.00".
2- You have two variables. One of them stores "required amount of time" (in this example, it's "01.00" [hours.minutes]), and the other one hold "passed time".
If you go on with first one, then when user changes clock, the code will become completely messed, it can even go negative values.
But if you use second one like this (you can use a whole different method, it's up to you): You define a invoke method that invokes AddTime() every 1 seconds. And in AddTime you add 1 seconds to your passed time holder variable. You compare the required time variable and passed time variable to get result.
Then as it's not depended on clock directly, changing time won't change anything.
Have a nice day!
-EDIT- I think I see what your saying now, had to re-read it, but if you save the "process" time do you mean when energy was used? if thats the case changing the time would not change this variable, right?
that is pretty much what I am currently doing I think. When energy is < max, the game stores the timestamp. I have another variable to stop the game saving the time constantly such as "timerSet = true" (which was false in the beginning, at max energy) $$anonymous$$G
if (energy < maxEnergy)
if (timeSet == false)
StartCoroutine(GetTime())
SaveTime()
timeSet = true;
else if (timeSet == true)
// code here that checks the times to deter$$anonymous$$e if the
// player should get another energy such as...
currentTime = DateTime.Now // this variable can be a DateTime
// The server time is turned into a string to be saved
// which is then converted back to a DateTime when being
// compared to the current time now (this is where im having
// issues, the current Time.
if (currentTime > setTime + waitTime)
energy++
save();
timeSet = false;
I just thought of something to stop the game from checking the server all the time.. once I have the first saved time, I could have the application calculate all the next times without pinging the server all the time, and if the date suddenly changes, get the script to check in with the server? Now the problem is timezones... which is why I would rather use a servers time, however I can get past this with just saving 2 timestamps, server and clientside, and checking both, if there are stipulations check in with the server. again though, I don't think this is the norm in todays production standards.
If timezones is a problem, then you can actually move whole timekeeping process to server and only send results to clients. So the time-jacking will become completely impossible and you won't face local timezone problems.
For your edit: look the edit in main answer.
I like the concept, it seems really intuitive, but will it work with the game offline? (I mean when the application is closed) I could use something like that with the tick timer I am currently using I think.
No, it requires a working application as it keeps time continuously, but you can run it on a master server too, if you can make it work as authoritative.
That is what I figured, I really like the idea, and one way to incorporate it to work offline.. is the ticktimer, take a look -
private int waitTime = 120; // This would be a saved variable perhaps, in seconds
private int timeWaited = 0; // This would be your "process" time
private int energyTick = 0; // this stores how many elapsed events
// DOES NOT WOR$$anonymous$$ for multiple saves.
void Start()
{
someTimer = new Timer((waitTime - timeWaited) * 1000);
someTimer.Elapsed += new ElapsedEventHandler(OnTick);
someTimer.Stop();
}
private void OnTick(object source, ElapsedEventArgs e)
{
print(energyTick + " (OnTick) this counts energy while the app is closed))");
energyTick += 1;
timeWaited = 0;
if (energyTick >= energy$$anonymous$$ax)
{
energyTick = energy$$anonymous$$ax;
//someTimer.Stop();
if (energyTick == energy$$anonymous$$ax)
{
someTimer.Stop();
}
}
else if (energyTick == energy$$anonymous$$ax)
{
someTimer.Stop();
}
}
I was having issues with the timer constantly ticking, so I tried to make it stop as many times as I seen it going.
another thing to note is that you cant do SetInt to playerprefs while in offline mode, so multiple players destroy this concept
Answer by Eno-Khaon · Jun 01, 2015 at 01:25 AM
I know that for some of Nintendo's 3DS titles, they lock the player out of specific activities in games for 24 hours when the clock is detected as having been changed. I don't know whether similar data is easily available in Unity, but here's some food for thought:
Android:
iOS:
that is definately worth reading into for this project here, thank you very much for the tip Eno $$anonymous$$haon! it may very well help me with this here :D, now to just figure out how to fine tune that and I can use that to check "stipulations." It is most likely inevitable ill be working with Android api sometime in the near future, maybe this will get me kickstarted on it.
I can't seem to figure out how to make ACTION_TI$$anonymous$$E_CHANGED trigger on specific timed intervals, although I haven't been looking for very long. for example, anything up to 30-40 seconds I wouldn't care much about, anything after that I would want this to fire, and allow me to check in with my server.. I will investigate further. Lol.. and a question on S.O. gets a negative? It doesn't seem like its possible, I've been mucking about for 3 hours now, back to the project. I'll update this when somebody clarifies that for me.
really the whole point of this is to reduce server overhead. ^^
It has been confirmed that there is no way to check based off of certain criteria using the afore-mentioned API.
-qoute-
No, that isn't possible. This broadcast is sent when the time is set (changed). If you are listening for this broadcast Intent you will get it every time. There isn't a way to tell Android that you only want to get triggered under certain circumstances.
Your answer
Follow this Question
Related Questions
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Upload an image onto the database from Unity 1 Answer
How can I bypass CORS with Unity WebGL? 3 Answers
I need to update a int in a specific row on mysql server. 0 Answers