Technical solution to eliminate desync in single-player sessions
" " So, somehow, your seed that is sent at the start of the session changes in the middle of the session, when I start lagging or hacking. Without the server saying anything. Right. It's Aliens. Aliens, I tell you. |
![]() |
I don't think too many people understand how the game currently work. From what I understand, the client already run a full simulation and the server already validate client actions by running the same simulation. Syncing is done in real time which cause desync even with small latency. The only difference here is that the server would run the simulation later and validate client actions later. Instead of the server moving monsters according to your delayed actions while your client is moving monsters right away causing desync, it would move monsters according to your action at the precise moment it happened. It would perform the same checks it probably already does to prevent hacks.
|
![]() |
" Delta is not inspected on the first packet at all. Right now your code (in main()) only sends one packet. That whole if branch is never executed. The current state of the code you posted doesn't fully simulate the scenario that you're discussing. Bigger problem: I actually ran the code. Granted I had to go find a damn C# compiler >< >< >< >< (of all things!) Running it unmodified yields: Attack seed: 3464761944756207526 Attack seed: 7272146002879287738 Attack seed: 3464761944756207526 Attack seed: 7272146002879287738 The client's packet is hacked, buffered 'future' packets. IGN: SplitEpimorphism
|
![]() |
" Thanks, Scrotie, you pinned the charlatan's shell game back on page 54 and spared me from wasting any more time on his empty posturing. And if anyone was in doubt, now you know why it's called pseudocode... Last edited by RogueMage#7621 on Nov 21, 2013, 2:28:59 AM
|
![]() |
" What hundreds of actors? " That's it. That's how frequent your "seed" changes. By your own admission. Guess what? These "actors" you're talking about? It's simply a matter of minimizing changes. Things like, I dunno, pausing and waiting and breakpointing. Elementary things, really. Then again, you're a 12 year industry veteran. You should already know this. Right? |
![]() |
Sachiru, whenever you call .Next() the seed changes. It has nothing to do with the packet itself.
Here is the latest code, I commented everything much better: http://pastebin.com/raw.php?i=PpkzipAS It should provide a better explanation on how RNG is used. =) syrioforel: Sorry, I had copy-pasted the wrong version up. Use this one I just linked. Last edited by qwave#5074 on Nov 21, 2013, 2:30:52 AM
|
![]() |
" I'm the hacker. I have complete control over my local system. Why the hell would I call .Next on that function? I can write a thread that intercepts it and calls something else. |
![]() |
" Because the server is going to call .Next(), and it needs to match the simulation. Seriously, if you get on Skype I can explain it much easier, but it seems that you are just trolling. You've literally asked the same 'how do seeds work' question like 200 times now. Do some research. Last edited by qwave#5074 on Nov 21, 2013, 2:43:06 AM
|
![]() |
" No thank you, I have no intention of being infected with stupid over Skype. " So this is your vaunted next function? How in the nine layers of hell would you ensure that the server runs this every time I run it on the client, without the client saying, "Hey, I ran qwave's magical hackproof next function"? Aliens again? Or Psychic computers? My original hack concept stands. You just changed the variables. Your code, with my hack injected: for (var count = 0; count < target; count++) { // next changes only to the next iteration of seed state on function call, so guess what, I just save current seed state and do my computations on another variable. Your code doesn't magically change seed state without Next being called, so I'll be an uber l33t h4xx0r and intercept all calls to it var savedSeedState = seed.GetCurrentState(); for(x=timestamp, x< timestamp +999ms; x+1ms) { var rng = (savedSeedState.Next() % timestamp); var simulated_damage = new Random(Convert.ToInt32(rng)).Next(1, 10); if (damage < simulated_damage) { var rng = (seed.Next() % timestamp); var returnedDamage = new Random(Convert.ToInt32(rng)).Next(1, 10); return returnedDamage; } } // For the sake of explanation, this damage represents an actual 'damage roll' var damage = new Random(Convert.ToInt32(rng)).Next(1, 10); // This output will be the same on the client/server due to the deterministic seed Console.WriteLine(environment + " simulation output: " + damage); } |
![]() |
" It's obviously magic to you. But if you run the code, you will see how the server runs this every time. I wrote this code to prove this fact. RUN THE CODE. |
![]() |