From 038604d1d2e6ce9ee8e3d5d7b5e157a49901269e Mon Sep 17 00:00:00 2001 From: Dave Hoover Date: Tue, 9 Feb 2010 04:11:36 +0000 Subject: [PATCH] Make piece prediction harder. Since the client & server share RNGs, many puzzles (e.g. yohoho's swordfighting) wind up lending themselves to easy piece prediction; the board is set up with a seed, and the RNG is only ever used to generate pieces. Someone snooping that could (and people have) pre-generate all the pieces in order, letting you snoop ahead. Now, Board implementations can choose to use certain events to pull bits from the RNG so that the actual ACTIONS taken perturb things, making things branch to the point that prediction is prohibitively hard. A while back, I'd wanted to do this across the board for all actions, but unfortunately in yohoho we have various non-board-altering events that come in and are executed in different orders on client and server, so things fell out of sync pretty quickly. The thought rattled around in my head again, so I'm doing it again. This time, Boards have to explicitly opt in on each event, so they can be sure to restrict it to those that are safe to use. git-svn-id: svn+ssh://src.earth.threerings.net/vilya/trunk@896 c613c5cb-e716-0410-b11b-feb51c14d237 --- .../puzzle/client/PuzzleController.java | 2 ++ .../com/threerings/puzzle/data/Board.java | 34 +++++++++++++++++++ .../puzzle/server/PuzzleManager.java | 4 ++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/java/com/threerings/puzzle/client/PuzzleController.java b/src/java/com/threerings/puzzle/client/PuzzleController.java index 56f287e3..61dffaad 100644 --- a/src/java/com/threerings/puzzle/client/PuzzleController.java +++ b/src/java/com/threerings/puzzle/client/PuzzleController.java @@ -713,6 +713,8 @@ public abstract class PuzzleController extends GameController return; } + getBoard().seedFromEvent(getPlayerIndex(), event); + _events.add(Integer.valueOf(event)); if (isSyncingBoards()) { _states.add((board == null) ? null : board.clone()); diff --git a/src/java/com/threerings/puzzle/data/Board.java b/src/java/com/threerings/puzzle/data/Board.java index 3ebe20a7..bd8983ca 100644 --- a/src/java/com/threerings/puzzle/data/Board.java +++ b/src/java/com/threerings/puzzle/data/Board.java @@ -85,6 +85,40 @@ public abstract class Board { } + /** + * Allows puzzles to add extra noise to their random number generators based on the specific + * events sent from the client to make it more difficult for a hacked client to predict things + * such as piece generation. + * + * @param pidx the player index that submitted the progress event. + * @param gevent the progress event itself. + */ + public void seedFromEvent (int pidx, int gevent) + { + if (isSeedingEvent(pidx, gevent)) { + _rando.next(getSeedForEvent(pidx, gevent)); + } + } + + /** + * Returns whether this event is the sort of thing we should use to generate extra noise on + * our random number generator. + */ + protected boolean isSeedingEvent (int pidx, int gevent) + { + return false; // By default, nothing is + } + + /** + * Returns a number of bits to read off the random number generator for this event. + * Subclasses can replace this with something that better understands the formats of its + * particular events if desired. + */ + protected int getSeedForEvent (int pidx, int gevent) + { + return (pidx ^ gevent) % 7; + } + /** Used to generate random numbers. */ protected static class BoardRandom extends Random implements Cloneable diff --git a/src/java/com/threerings/puzzle/server/PuzzleManager.java b/src/java/com/threerings/puzzle/server/PuzzleManager.java index 62aef0b4..42834bee 100644 --- a/src/java/com/threerings/puzzle/server/PuzzleManager.java +++ b/src/java/com/threerings/puzzle/server/PuzzleManager.java @@ -371,6 +371,8 @@ public abstract class PuzzleManager extends GameManager compareBoards(pidx, cboard, gevent, before); } + _boards[pidx].seedFromEvent(pidx, gevent); + // apply the event to the player's board if (!applyProgressEvent(pidx, gevent, cboard)) { log.warning("Unknown event", "puzzle", where(), "pidx", pidx, "event", gevent); @@ -426,7 +428,7 @@ public abstract class PuzzleManager extends GameManager * * @param pidx the player index that submitted the progress event. * @param gevent the progress event itself. - * @param cboard a snapshot of the board on the client iff the client has board syncing + * @param cboard a snapshot of the board on the client if the client has board syncing * enabled (which is only enabled when debugging). * * @return true to indicate that the event was handled.