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

David Ripton dripton at ripton.net
Sat May 22 18:32:43 EDT 2004


Jasper Phillips wrote:
> On Thu, 20 May 2004, David Ripton wrote:
> 
> 
>>On 2004.05.20 02:25:20 +0000, Jasper Phillips wrote:

> I used to write Java code for a living;  I came to hate it's shortcomings
> and IMHO Python is purely superior.  Still, was Titan really 50k lines of
> Java?!  Mind boggling.

We have way too many chrome features, and the code is far from minimal. 
    (There's a lot of duplication between client and server, for 
example.)  A tighter and still reasonably complete implementation could 
be done in 10k LOC in Java.  I think 5k LOC in Python is a reasonable 
target.

> I'm treating event history as game state, although I haven't implemented it
> yet.  Not so much for the AIs use, but to model it's effects on future
> events.  IMHO treating it as game state is also a simpler model.

So future events depend on the exact sequence of events used to reach 
the current state, not just the current state?  That sounds expensive.

>>>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.)
> 
> 
> IMHO this seems overly complex.  I don't like maintaining parallel objects
> or parallel calculation, as it smells like ClientGame/ServerGame...

The problem with the separate ClientGame / ServerGame classes is that 
once you allow the big classes on each side to get coupled to their 
location, the small classes start coupling to those big classes, and 
pretty soon you have two slightly divergent copies of most of the code 
in the game, and double maintenance.

Having separate *objects* of the same classes on the two sides is fine, 
though.  In fact, in a game with hidden information, it's inevitable. 
The server Game object will hold the full state, and each client's Game 
object will hold a subset.  This is true whether the server sends 
censored copies of its state to clients, or whether it sends them 
subsets of the full event stream and lets clients generate their own 
censored copies.

>>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.
> 
> 
> Why?  I see no advantage to symmetry here.  IMHO the a trusted-server / 
> untrusted-client asymetrical design is clearly called for.

It is a trusted server and untrusted client.  But the trust is expressed 
by which events each can see.  Symmetry just means less code, because 
things work the same both ways.  I don't think it's necessary, but I do 
think it's good if you can get it.

> I disagree that sending objects isn't practical, IMHO it just helps to
> approach it slightly differently.  I'll try to explain what I mean by
> roughly describing my game as an example;  if my design is crappy please feel
> free to shoot holes in it! :-)
> 
> Much of my game's logic is based upon Copyable Actions which are used by
> both Server and Client, e.g. MoveAction.  These have a .__call__(state)
> which modifies the passed state as they see fit, as well as a
> .validate(state) to ensure a move is legal.  Players create a list of such
> Actions, and pass them to the Game server as their turn.  

Standard command pattern, but cleaner in Python because of __call__.

Do your turns have phases, requiring certain actions to occur at certain 
times?

Can other players interrupt your turn with actions, or are their replies 
(e.g. strikebacks to your attacks) completely automated or deferred 
until their turns?

> All the args for
> Action are literals (such as Unit ids and movement direction), with Actions
> knowing how to find the corresponding objects on passed in State.
> 
> With only literal args these Action objects can be passed safely to the
> game, which will reconstitue it's own versions, validate them, then invoke
> them by passing in it's True State.  Players are given their own PlayerState
> view of TrueState each turn, with real (copies of) objects they can use for
> display, UI and validation.

It seems that only sending game state updates once per turn would reduce 
interactivity too much.  I want to see my opponents' (visible) moves as 
they happen, not batched up at the end of his turn.  Beware of 
sequential solitaire.

PlayerState / TrueState sounds like the ClientGame / ServerGame problem 
I was warning about.  It's not necessarily bad if they have the same 
interface and PlayerState just has a subset of the data, but look out 
for duplicate code.

> Basically it works like passing objects both ways, except it's safe.  The
> costs are minor: referenceable objects must have Ids, Clients must create
> Actions with 'object.id' instead of 'object', and Actions need to either
> 'object = state.getObject(objectId)' or use Game/State methods taking ids
> for args.

I agree that passing handles instead of references definitely works 
better.  I find that an unfortunate limitation of current PB, though not 
a major one since (as Christopher Armstrong pointed out) the amount of 
code needed to convert back and forth each time is small.

> IMHO Making all of this essentially part of the API is cleaner than having
> bulk "Reconsitute Objects" methods.

Yes.  Having direct support in PB for the idea of const (copy this 
object when I send it, but ignore any changes that were made to it on 
the other side if I get it back), so that you don't have to do any of 
this, would be even cleaner.  I don't know if there's much demand for 
this feature from other people, though.

Anyway, I'm looking forward to seeing your game at some point.

-- 
David Ripton     dripton at ripton.net




More information about the Twisted-Python mailing list