[Twisted-Python] pb.Copyable, round trip objects, and untrusted clients

David Ripton dripton at ripton.net
Fri May 21 00:45:12 EDT 2004

On 2004.05.20 02:25:20 +0000, Jasper Phillips wrote:
> On Wed, 19 May 2004, David Ripton wrote:
> > I'm working on a client-server game, with hidden information, using PB. 
> >   I don't want to trust the clients.
> Titan, I presume?  Nice game!

Yeah.  I don't have time to maintain 50k lines of Java code, so I need
to rewrite it in 5k lines of Python.  :->

> I'm working on a game more akin to Civilization or Age of Wonders, but have
> basically the same problem.

That if the Mongols upgrade early from horsies to tanks, Europe is toast,
but it's hard to make the game dynamic enough to show the Eiffel Yurt?

> > Because there is hidden information, it's important not to send anything 
> > to the client that it's player shouldn't see.  Doing that with PB is 
> > pretty straightforward.  If a class's data is always secret, don't make 
> > it Copyable.  If parts of a class are secret, censor them in getStateToCopy.
> For me this was more complex, as what a Player knows is itself a true part
> of the Game's State, potentially affecting Action/Event resolution.  I end
> up calculating each Players state myself, and passing them explictly.

What happens if players conspire to share their secret information offline?
Is it okay if someone knows stuff but doesn't Officially Know it, or
does the whole game tend to fall over in the face of such weenie behavior?

If B, you've got a hard ceiling to the amount of security you can
program in, which is both annoying and refreshing (I don't need to fix 
this extremely theoretical security flaw, because there's a much larger 
one I can never fix.  It's like a security variant of Amdahl's Law.  If
your company insists on running Exchange, at least you don't need to worry 
about triply-redundant power supplies on the mail server.)

> Plus this feels to me more like it should be part of the game itself, rather
> than some oblique networking aspect.  Same end effect though.

I've decided to have the server and each client save the action stream
it's seen, which is somewhat similar.  I have code in the previous
version of this game to deduce and predict which stack hidden enemy 
units are in based on partial information.  But the AI isn't smart
enough to worry about what other players know, only what it knows, so
this is essentially local information.  I don't consider it part of the
server's game model.  (Maybe I should, from an everything-in-one-place
perspective.  It would make it easier to persist this information
rather than recompute it.)

Why is what other players know an important part of your game state?
The exact extents of other players' knowledge can't be public, so nobody
but the server can really use this information, right?  What does the
server do with it?  I guess it's useful for diplomacy, if you allow
bartering information.

> > Obviously, the client should only be able to change the server's game 
> > state via a well-defined error-checked interface.  Also fairly 
> > straightforward, though error-prone since you need to forsee and test 
> > against every way to cheat.
> IMHO handling this can avoid the 3rd problem you mention.  I have Players
> send Actions for a given Turn as the only API to change Game State.  These
> actions don't take game object as args, but rather Ids as you suggest below.

I'm now back to wanting to do that in both directions.  Except using
strings instead of object IDs, since the parallel objects on the client 
and server will be distinct.  (But they will use the same class, which
is key to maintainability.  When you find yourself writing ClientGame
and ServerGame, scream until the urge passes, then decouple the concept
from its context until the need is gone.)

> I do send actual objects from the Game to Players, but IMHO this is a bit
> error prone lest you accidentally leave in secret info.  I only do it so
> that the clients can validate actions they plan sending against their
> perceived State using the same mechanism as the Game.

I want to make it symmetrical, so I want to build the client-side model
objects using the action stream, rather than copying them directly.  It
will be painfully boring, but I don't have *that* many actions, and
they're fully documented from last time I decided to go this way.

> IMHO it seems superflous to have the game update the information a client
> sends, only to later access this same information for calculations.  Why not
> just pass back the relavent Ids, and have the Game API look up their True
> counterpart as needed?  This doesn't seem onerous to me.

I wanted a way to bury this detail inside the framework, but it's not
currently practical so I'm flipping completely the other way.  I'd forgotten
how badly I want the ability to fast-forward and rewind through game history
by applying and undoing actions.  (Lets the AI free-run while giving the
ability to watch it as if it were moving more slowly.  Also lets you
review other people's savegames to pick up strategy hints.)

David Ripton    dripton at ripton.net

More information about the Twisted-Python mailing list