Re: [Alephmodular-devel] Input architecture (ActionFlags)
Status: Pre-Alpha
Brought to you by:
brefin
From: Woody Z. I. <woo...@sb...> - 2003-01-26 18:09:00
|
On Sunday, January 26, 2003, at 04:28 AM, Br'fin wrote: > On Friday, January 24, 2003, at 04:57 PM, Woody Zenfell, III wrote: > >> On Friday, January 24, 2003, at 01:29 PM, Br'fin wrote: >> >>> Well, my initial fears of messing with the action flags involve >>> breaking the M2 Films. If you're going to talk about changing how the >>> action flags are stored, then you better detail how to identify and >>> handle replays from different versions of the code. I don't care so >>> much if our films don't run under Marathon, but we should be able to >>> handle theirs, always. >> >> Yeah simple, the code that handles a replay examines the file, >> determines that it's a "traditional" film file, and sets up to use the >> MarathonFilmUnpacker. Same deal on output (just use a >> MarathonFilmPacker, which writes M2-compatible films, when starting up >> a MarathonGame). > > Given the importance of this, I want more detail than this. This cannot > be a "magic happens here." I want to know *how* you determine it to be > what kind of film file it is. Right, Tim is right on, sorry I thought it was pretty clear how it would work out. Whatever object is trying to mediate the opening of the file hands the data chunk off to some sort of demultiplexer. The demultiplexer's job is to figure out which FilmUnpacker (or WadUnpacker, etc.) should be used for the file - probably by asking several such objects in turn to see which one is willing to handle it. (If multiple are willing, they could give a numeric score as to how well they think they could handle it, etc.) >> Why? If the ActionFlags class is what knows which sorts of things it >> can represent and what types of values it can store for those things, >> why should it not be able to share that information with some kind of >> UI configuration object (which builds the configuration dialog/etc. >> based on what the ActionFlags class says)? > > One thing that occurred to me is just to start off your document with a > discussion of the perceived role of ActionFlags to begin with. Just to > make sure we're all on the same page with what they are and what they > should be. And what they definitely are not. An ActionFlags object encapsulates one player's inputs for one game-tick. That is my definition. With 'inputs' here meaning anything that affects the course of the game (i.e. helps to determine a game-state). (Thus, things like changing the sound volume on the local computer have no business being in ActionFlags - and of course they're not, at the moment.) > To me they are a compact and concise way of passing encoded input data > to the game engine. I can see how it would be useful to expand upon the > allowable number of action flags. I haven't grasped why we need to be > using multiple different kinds of ActionFlags in your queues. Compact and concise may on may not be important. Packing the flags for film files or network packets etc. should produce a concise representation to save disk space or packet space, respectively. But I don't see any particular reason they need to be concise within the game engine. Well you're right, if there's a strict lineage of less-powerful-to-more-powerful (in terms of representational ability) ActionFlags objects, then yes anything done in one representation can be done in the most recent (and thus most powerful) representation. But if one person takes AM in one direction, and develops his own ActionFlags representation with, I don't know, 'spitting', and somebody else takes AM in another direction and has ActionFlags for 'levitation', how do you handle that? It seems obvious to me that when AM is playing the 'spitting' scenario, it uses the 'spitting'-capable ActionFlags. When AM is playing the 'levitation' scenario, it uses the 'levitation'-capable ActionFlags. It seems quite useful to me to allow the type of ActionFlags to change. (Though as noted in my other message, it doesn't seem useful to me to have different ActionFlags types in the course of a single game. Thus queues can depend on holding homogeneous ActionFlags.) > As to UI configuration support, that could be a role for the encoder, > but seems out of scope for the ActionFlags themselves. Whatever. If you don't want your ActionFlags to be able to tell other objects what they can represent (which is all I'm suggesting), I mean, it's your project. But it seems like a poor decision. > Another thing on ActionFlags. They strike me as something that should > always be constant for a particular version of the game. There could be > flags to say 'if in M2 mode, ignore action feature X', but that's in > the game core and not in the action flag itself. Compatibility of > things like replays is the responsibility of the replay loader and it > works by munging the prior ActionFlags into the current internal > version. Whereas in my view, you would simply use the M2ActionFlags type internally. No munging necessary. >> Good question. Probably not too big though I would guess. I mean, >> maybe you have to pay an additional 32 bits for a vtable pointer or >> something? OTOH the benefits are many, I think - different >> ActionFlags representations, switchable on-the-fly, without any chance >> of getting them mixed up. > > 32 bits for the pointer to CActionFlags as well. In addition to > whatever other overhead it being a class adds to the memory usage. This > appears to be deviating from compact ActionFlags. 1. Who ever said anything about storing pointers? I was picturing the queues etc. storing the ActionFlags objects directly in their chunks of memory, a la STL vector et al. This is possible since every ActionFlags object in use at a given moment is of the same type. 2. I really feel that a couple extra kilobytes of runtime memory is not too high a price to pay for the benefits. In my view, object-orientation is the best model we have now for expressing modularity, and so modularizing code almost inevitably means making it object-oriented. There is some additional overhead in both time and space, but in the long run it's almost certainly worth it for the added flexibility and maintenance benefits. If you don't see the benefits of object-orientation, perhaps you have not read _Design Patterns_ or worked in Cocoa. I recommend both; I didn't understand OO prior to them (though I thought I did ;) ). >>> As for the others it seems like when you start a game you setup the >>> current 'flag pipe' that every 30 times a second pulls from a source >>> queue and throws to the player queues. A replay would be 'read from >>> file, pipe to player queues' and a network flag pipe would be 'read >>> from input queue, handle networking, put all player flags on player >>> queue' >> >> Yeah this is a restatement of what I suggested, right? > > I'm not sure. Or else I wouldn't have said it like I did. I wasn't > quite understanding what you had written up before. Whatever starts up the game 'wires up' flag producers and consumers (which communicate with one another via ActionQueues). Flag producers and consumers then just do their job with no knowledge of what's on the other side of the Queues it's using. >>> I'm curious as to what you mean by smearing. > [snip] >> I think my overview of networking and input covers the role of >> smearing. >> > Ok, just read up on that. Ditching and smearing both look like > dangerous behaviors. In general I presume whenever this happens that > the local machine's gameworld is only updated with the final set of > flags that the network stuff 'found'. I don't know what you mean by 'dangerous'. Both are entirely necessary to account for clock drift between machines (and may be useful in coping with changing latency conditions). Currently yes, as you can see from my overview of the current scheme, the game-world update stuff operates only on action_flags that have been around the ring on the network. Ditching and smearing happen between the local_queue and the flags' being put into the network packet. Thus, the game-world update stuff only sees post-ditch, post-smear flags. Note that for the purposes of prediction, it may be useful to move ditching and smearing to an earlier point in the process, informed by information at the network level, so we can avoid mispredicting the local player (which we've both stated is a Bad Thing). But I see no reason to worry about that at the moment (beyond to point out that it's a possibility). >> If the game core can't update faster than 30fps, we're hosed (if we're >> planning on playing in realtime that is ;) ). There's no way around >> it. > > I don't know if it can. I haven't looked into it. But I would presume > the 30fps game core is > fairly fixed in the logic and calculations of all the elements in the > game. I think there's a way to pretty things up so they appear to be > running faster than 30fps, but it doesn't allow things to be processed > faster than that. I think I must have misunderstood what you meant. Heh heh. I read it as "if the game core can't run quickly enough to churn out 30 updated game-states per second". Sounds like you were talking about increasing the tick_rate. The latter sounds very difficult to me, at least if preserving backwards-compatibility is important (and we seem to agree that it is). So some kind of interpolation beyond the standard updating I think is what's in order. But we've both talked about that a fair amount I think. >> Ok, to make things clearer (maybe), I've created a PDF diagramming the >> flows of action_flags in a networked game, a single-player game, and >> in film playback. (It illustrates how Marathon/A1 do it, which is the >> same way I am picturing things working for AM, albeit more loosely >> tied together and perhaps with different routines actually doing the >> work.) I'm sending it to Jesse and asking him to post it at s.b.o. >> > Why the distinction between RealActionQueue and the recording queue > when playing (single or network)? Can't a recording task just peek at > the RealActionQueue for what it needs? No, the idea is that any given queue has only one writer and one reader, to keep synchronization simple. While it may be the case currently that the readers of the RealActionQueue are both in the same thread, and thus have a natural mutual-exclusion property, I don't think we want to unnecessarily bind ourselves to that arrangement. And, as pointed out, I don't think we want to protect every queue access with a mutex. (We have different ideas about what kinds of overhead are acceptable apparently. ;) ) Also with each reader (the recording film-dumper and the game-state updater) having its own copy of the flag data, they can operate more independently, each handling the data at whatever rate it feels like without worrying about what the other guy's doing. For example, the current film packing code waits for something like 256 flags to accumulate in its queue for each player, then writes them out in interleaved, RLE'd chunks. How would the code do that if it were trying to look over the game-updater's shoulder? Make a copy of all the flags? :) (Yeah yeah this may not be the best way for us to produce our films, but it's an example of a specific use...) Woody |