
Originally Posted by
Iscah
If that's the concern, then surely having them publicly release the method would be the quickest way for people to learn how to exploit it?
Even if they publish the RNG code itself, the fault could lie elsewhere. Heck, it could be in code seemingly entirely unrelated to the lottery.
I'm going to pose a hypothetical here; I have no idea if this is what actually happened -- probably not, since it's a stab in the dark -- but it's the type of thing I saw happen more than a few times when I still worked in the games industry. And I suspect that whatever went wrong in the lottery, while probably different in details, was pretty dang similar in terms of failure of process at the very least.
So, let's say you're a developer at SQEX, working on a housing lottery system. You've got it all coded so that people can bid on a house, put down the placeholder money, and then it will pick one of those bidders. Yay!
"But wait," says a co-worker. "What if someone bids on a house and then cancels their account, or moves to another server? If someone who was no longer there to have the house was a lottery winner, people would be out with pitchforks and torches!"
"Oh," you say, "that's true; we'd really better filter the list to remove any invalid bidders when we do the drawing!"
So you look at the codebase and spot some other code calling a utility function like, for instance,
Code:
/**
* Checks if a character lives on a specific world and is currently valid.
*/
static bool PlayerUtilityLibrary::CheckIsValidCharacterWorld(uint64 CharacterID, Servers::WorldGUID World)
{
// Code stuff
}
Great, that looks like just what you need!
So you change the lottery code such that before it draws a winner, it runs through the list of folks bidding and calls this function.
Now it's time to test: you and four other developers log into the test server and head to a house to all bid on it. It says there are five bids. You then have one of the developers log off and delete that test account. You run the lottery, everyone standing there to watch for the results... and it awards the house to someone, saying there were four bids. Great! It filtered to ensure only valid bids. Everything works. You run the lottery a few more times, and it all looks good!
So the lottery code gets checked in and signed off on, checked off the to-do list, and eventually compiled into the patch that's shipped.
But unbeknownst to you, that "CheckIsValidCharacterWorld" function was made specifically to check for things like /tell and social functions (and not documented as such), and thus the definition of 'valid' it operates on actually includes "character must be online". It might not even have been clear in the code of that function; that one might've called some other function that called some other function that said "the character must be online to be valid". So even if you looked in the code of the "CheckIsValidCharacterWorld" function, it might've still looked like exactly what you need.
And, of course, since no one thought someone being online or offline would be relevant to your lottery code, no one thought to check what happened if bidders were offline when it ran; all those test accounts were standing right by the placard during the test to make sure whoever won can then immediately check they can claim the plot. (Just like no one probably would think to check any number of other things like "what if the person was in an instanced duty when the lottery ran" or "what if the player was in the login queue when the lottery ran" or whatever. It's working off of a character record, not a connection session record, after all!)
So the code goes live and everyone bids and it's great. And then the lottery runs, and -- just as you coded it to -- filters to remove 'invalid' players. You just didn't realize that 'invalid' included 'offline' -- so anyone not online when the lottery runs has their bid removed as invalid. Suddenly, huge numbers of houses show as having 0 bids (because no bidder happened to be online when the lottery ran), and people are confused and angry and upset, and you're left to dig frantically through the code to figure out what went wrong.
Thus the RNG code could be perfectly flawless, but the system still breaks badly. And to even demonstrate where the issue was, you'd have to publish not just the RNG code, but the overall lottery code, then the hypothetical CheckIsValidCharacterWorld code and whatever that code called -- like GetCharacterPlayerAccount, GetAccountSubscriptionStatus, GetCharacterWorldState, and whatever other hypothetical functions were called.
Again, this probably isn't what actually specifically happened, but this type of thing happens startlingly often with large and/or long-lived codebases. It's especially true because many software companies take a QA approach -- "take these steps to see if this feature works" (like "go bid on a house with five test accounts, delete one account, then see if the lottery picks from only four accounts and successfully awards to one of them") -- versus a really formal test engineering approach (where you have a comprehensive test plan that tests whether entirely unrelated factors might influence a given bit of functionality).
Ironically, stuff like that is a lot less likely at a "small indie developer", because you probably have 14 people and a more reasonably-sized codebase; there's a decent chance you're familiar with every part of the code, and if you aren't 100% certain on what a part of that codebase does (like "does CheckIsValidCharacterWorld actually do the thing I want"), you can usually just shout across the room to ask the person who wrote it.
The tl;dr form of this near-essay-length post: the failure could be in something entirely different than the actual RNG portion, and based on my own past game industry experience, there's a fairly reasonable chance it was. So even if they did publish the RNG code, that wouldn't do anything to show where the issue was.