Am Donnerstag, 25. Januar 2007 18:38 schrieb Troman: > ----- Original Message ----- > From: "Troman" <[EMAIL PROTECTED]> > To: "Troman" <[EMAIL PROTECTED]> > Sent: Thursday, January 25, 2007 5:57 PM > Subject: temp > > > Am Donnerstag, 25. Januar 2007 15:46 schrieb Giel van Schijndel: > >> On Thu, 25 Jan 2007 07:31:25 +0100, Dennis Schridde <[EMAIL PROTECTED]> > > > > wrote: > >> > Am Donnerstag, 25. Januar 2007 01:21 schrieb Troman: > >> >> ----- Original Message ----- > >> >> From: "Dennis Schridde" <[EMAIL PROTECTED]> > >> >> To: <[email protected]> > >> >> Sent: Thursday, January 25, 2007 12:26 AM > >> >> Subject: Re: [Warzone-dev] Music playlists > >> >> > >> >>> Am Mittwoch, 24. Januar 2007 22:42 schrieb Troman: > >> >>>> ----- Original Message ----- > >> >>>> From: "Dennis Schridde" <[EMAIL PROTECTED]> > >> >>>> To: "Development list" <[email protected]> > >> >>>> Sent: Wednesday, January 24, 2007 8:43 PM > >> >>>> Subject: Re: [Warzone-dev] Music playlists > >> >>>> > >> >>>>> Am Mittwoch, 24. Januar 2007 18:46 schrieb Per Inge Mathisen: > >> >>>>>> On 1/18/07, Troman <[EMAIL PROTECTED]> wrote: > >> >>>>>>> I had some musings about the way this should work. Playlist > >> >>>>>>> script > >> >>>>>>> interface will be most used by scriptors I assume. I see two > >> >>>>>>> main occasions when such an interface might be used: > >> >>>>>>> > >> >>>>>>> 1) when it is time to interrupt any background music that might > >> >>>>>>> be > >> >>>>>>> played and kick in some moody piece to create atmosphere, like > >> >>>>>>> it is usually done in campaigns. > >> >>>>>>> > >> >>>>>>> 2) when someone wants to attach a custom playlist to his map, > >> >>>>>>> the way it is done with Unreal Tournament maps for example. > >> >>>>>> > >> >>>>>> Agreed. > >> >>>>>> > >> >>>>>>> As for the implementation, looks like wz uses 'tracks' to store > >> >>>>>>> songs. Track 2 corresponds to menu, track 1 to the in-game > >> >>>>>>> music. > >> >>>>>> > >> >>>>>> I do not think we should let that get in the way of a decent API. > >> >>>>>> We can change the way Warzone stores songs, if necessary. > >> >>>> > >> >>>> Since i'm not the one to program it it's fine with me. ;-) > >> >>>> > >> >>>>>>> When modder wants his custom playlist to be played when someone > >> >>>>>>> is using his map he either loads all songs manually to the user > >> >>>>>>> track using scripts, like > >> >>>>>>> > >> >>>>>>> playlistAddUserSong("mySong1.ogg"); > >> >>>>>>> playlistAddUserSong("mySong2.ogg"); > >> >>>>>> > >> >>>>>> Sounds good. > >> >>>>>> > >> >>>>>>> Since this is not the most convenient approach it might be a > >> >>>>>>> better idea to load playlist from an external playlist file, > >> >>>>>>> which will come with the mod > >> >>>>>> > >> >>>>>> Well, to me the in-script version above seems more convenient > >> >>>>>> than adding yet another file, since the number of songs will > >> >>>>>> probably never be high. > >> > >> I agree, I think it's better to simply stick with creating the playlist > >> through scripted functions. Also since I believe the scripts support an > >> `#include' style directive, you don't have to clutter all your scripts > >> with > >> playlist-append calls. > >> > >> >>>>>>> In case of a map with custom playlist it is simple, just call > >> >>>>>>> something like playlistPlayUserTrack(); from within the scripts > >> >>>>>>> (or again we can make wz start playing user track automatically > >> >>>>>>> if a map comes with a user playlist) for wz to switch from > >> >>>>>>> player playlist to the custom map playlist. > >> >>>>>> > >> >>>>>> I think starting the script-supplied playlist automatically seems > >> >>>>>> like the simpler and better way. > >> >>>> > >> >>>> What if the user doesn't want any music to be played at the > >> >>>> beginning? > >> >>>> It's probably better to let the modder decide this. > >> >>> > >> >>> I think what Per meant is that there should be an initPlaylist > >> >>> function > >> >>> in the scripts, which is called upon mission start. If the modder > >> >>> doesn't want that, he must not provide that function. > >> >> > >> >> I don't know how we jumped from playback to initialization. Anyway, > >> >> for > >> >> the initialization of the playlist you just place the necessary code > >> >> into the script callback that gets called whenever a map is loaded. > >> > >> I think we should just allow the creation of multiple playlists, and > >> then have some function to select the current active one (like > >> bindPlaylist below). Then when you select a playlist to be active it > >> should simply start > >> playing automatically. If you would want nothing to play then just > >> select playlist NULL or something similar, meaning no playlist is > >> active. > > > > When everything starts you must have the state playing=no/stoped=yes, > > because > > you don't even have a playlist to play from. > > Your idea would imply that bindPlaylist doesn't only bind the playlist, > > but > > also implicitly advises the soundengine to play it. > > Doesn't sound too nice to me. 1st that function does several things > > instead of > > only one and 2nd the modder might not want to start it immediately for > > whatever reason. > > Ditto. I don't know why we would want to force playback, let the modder > decide. > > > Eg. in GL the texture you bind is also not immediately painted on the > > screen. > > Or if AL uses a similar way, I don't think every sound-source you bind is > > immediately played. (But I have _no_ idea of AL, I must admit.) > > So my advice would be to let bindPlaylist bind the playlist and let > > startPlaylist/resumePlaylist handle the beginning playback. > > (Maybe we should have start/stop and pause/resume functions, where > > start/stop > > start from the beginning or stop entirely and pause/resume only ... pause > > and > > resume. Would save us from weird double namings (start and resume being > > the > > same thing) and would also add some functionality for no fees.) > > > >> >>>>>>> In cases when some music must kick in from time to time > >> >>>>>>> depending on some in-game conditions it is a bit more > >> >>>>>>> complicated. > >> >>>>>> > >> >>>>>> There are probably two different needs here: > >> >>>>>> 1) Scripter wants to play a short song to set the theme of some > >> >>>>>> event, then resume the playlist as normal. The new song should > >> >>>>>> then > >> >>>>>> not be in the playlist afterwards. > >> >>>>>> 2) Scripter wants to change the whole theme of a level by playing > >> >>>>>> a new song or songs throughout the remaining time (or until it > >> >>>>>> changes again). So we need a way to reset the playlist; then the > >> >>>>>> scripter can add the new songs. > >> >>>>>> > >> >>>>>> So how about an API like this: > >> >>>>>> playlistReset() -- deletes existing playlist (eg to remove game > >> >>>>>> supplied playlist) > >> >>>>>> playlistAdd(song) -- adds song to top of playlist (eg to add to > >> >>>>>> game's supplied playlist) > >> >>>>>> playlistInterruptWith(song) -- play a song once, then resume > >> >>>>>> playing playlist (eg for event) > >> >>>> > >> >>>> Makes sense to me. > >> >>> > >> >>> Didn't say that it doesn't to me. > >> >>> Just the naming is not my favourite... > >> >>> playlistReset -> clearPlaylist > >> >>> playlistInteruptWith -> playTrack > >> >>> That was my idea... Maybe not ideal, either. > >> > >> This can be accomplished by my proposal above. > > > > ?? > > > >> That way you would have to provide a single song playlist though. This > >> could be done by a wrapping function though: * creating a playlist > >> * add the one song to it > >> * hook some kind of playlistFinished event on it (as a callback > >> function) > >> * add the ID of the currently playing playlist to a member var of the > >> new > >> playlist * make the new playlist active > >> Then upon raising of playlistFinished event (i.e. through callback > >> function): * make previous playlist active again > >> * destroy one-track playlist > > Almost exactly what I had in mind. Seems to be very flexible to me. > > > With the bound playlists (GL style architecture) I don't think we need > > the play-one-track and resume function anymore. I don't even think that > > we should > > provide a wrapper for that purpose... More work for us for something the > > modder can easily achive by himself. Additionaly we need to do some magic > > with our temporary playlists in the background, which might bring > > confusion. > > We would need to find out who created the playlist which just ended to > > know > > if we need to inform the scripts or handle it ourselves. > > (Otherwise we might > > do some harm to the modders playlist or he might to ours.) > > So IMO lots of work for little benefit. > > Scripts should be notified about all playlists/songs events, not only those > created by scripts. > For that matter I mentioned handles in the first post. After the creation > of playlists and/or songs some handles could be returned to the scripts. > Then when playlistFinished/songFinished callbacks occur they would return > playlist/song ID. I don't think we can harm the modder in any way. Well, then go with that wrapper... I just thought it might be a bit too much magic. But if it's not, it's ok for me...
> >> >>>>> My proposal:
> >> >>>>>
> >> >>>>> Function to set a playlist.
> >>
> >> Could by accomplished by multiple playlistAdd(song) calls.
> >
> > Well, I understood that now. This function would have been a merge of
> > createPlaylist and bindPlaylist. (Remember: I came up with those bound
> > playlists after thinking about all this.)
> >
> >> >>>>> Function to immediately play one track.
> >>
> >> As explained above.
> >>
> >> >>>>> Function to stop playlist playback and one function to resume
> >> >>>>> playback.
> >>
> >> Probably would apply to all playlists? I.e. no playlists should be
> >> played from at all.
> >>
> >> That way some `static bool playing;' could accomplish this (i.e. global
> >> across all playlists).
> >
> > ?
> > start/stop, pause/resume would advise the sound engine to
> > start/stop/pause/resume the current playlist, not one single playlist...
> >
> >> >>>>> Function to set playback-modes, like repeat_all, shuffle, fadein,
> >> >>>>> fadeout, crossfade.
> >>
> >> Repeat-all and shuffle shouldn't be to hard to implement.
> >>
> >> The fading functions however might be a bit though. This because it
> >> would basically require you to set AL_GAIN on your playlist ALsource a
> >> lot (to achieve a good fading resolution). AFAIK OpenAL does not provide
> >> any feature for fading.
> >>
> >> So it's either setting AL_GAIN a lot, or somehow manipulating the
> >> decoded PCM data stream.
> >>
> >> As for cross fading. This would basically require two ALsources on the
> >> moment of switching songs. (You can only send one PCM stream through an
> >> ALsource at a time.) Or again manipulating the PCM stream by mixing on
> >> the
> >> software level. (Rather than using the hardware mixer)
> >
> > Actually I didn't think of that yet...
> >
> >> >>> Those effects (not shuffle, but .*fade.*) would also affect
> >> >>> playTrack(). If the modder wants something different, he can switch
> >> >>> modes before and after his custom track. (Reacting to events.)
> >> >>>
> >> >>>> This all can surely be usefull to the end user/scriptor. Crossfades
> >> >>>> for 'insertations' especially in campaigns etc.
> >> >>>>
> >> >>>>> Clearing the playlist is simply supplying an empty playlist.
> >> >>>>> I don't think there is any need to dynamically attach a track to
> >> >>>>> the
> >> >>>>> playlist, am I correct? Why would one attach a song if he doesn't
> >> >>>>> know when it will be played...
> >> >>>>
> >> >>>> You never know what's going on inside of a modder's head, it
> >> >>>> doesn't take much affort to provide this functionality, besides I
> >> >>>> don't see how else we would want to re-fill the list (see below).
> >> >>>
> >> >>> If there is technically no other way, yes. In my idea you could
> >> >>> re-fill
> >> >>> the list simply by setting the playlist to a list of different
> >> >>> songs...
> >> >>> But addTrack should have a switch so you can choose whether to
> >> >>> append to the front or the back... (Or maybe better 2 functions
> >> >>> addTrackFront
> >> >>> addTrackBack, or appendTrack prependTrack, or similarly named.)
> >> >>>
> >> >>> I just got the idea of Open*L style functions... OMG... crazy...
> >> >>> createPlaylist(Playlist*); // New, empty playlist
> >> >>> deletePlaylist(Playlist*); // Trash it, mark pointer invalid
> >> >>> bindPlaylist(Playlist*); // Switch to another playlist
> >> >>> addTrack(Playlist*,Track*); // Append Track
> >>
> >> Wel the functions on their own look quite good to me.
> >> Their prototypes however... Let's just say that I don't like the idea of
> >> passing pointers into the scripting engine.
>
> Why not? That's the way most of the scripting stuff works right now.
> Scripts currently work with a lot of pointers passed from WZ, although from
> the scriptor's point of view there's no difference between integers/bools
> or pointers to some internal wz structures.
> Not that it really matters to me. If we just work with integer ids, that
> would mean we have less different types to define for scripts (I don't
> really like the idea of flooding scripts with dozens of new types, unless
> really needed, but i'm not yet sure what would be optimal for us).
>
> > This was _not_ a proposal for the scripting engine, but for the C-API...
> > The scripting engine would get some integer IDs or similar...
> >
> >> >>> Hmmm... Actually the idea is not that bad...
> >> >>> Would make it easy to handle multiple playlists, eg. one for the
> >> >>> menu and for the game, or when The Modder wants to interupt the game
> >> >>> with a
> >> >>> few different songs to acompany his cutscenes or the attack of the
> >> >>> clones... (And wants to switch back to the usual theme afterwards.)
> >> >>>
> >> >>> Implementation for createPlaylist:
> >> >>> New item of a playlist-linked-list. All pointers NULL. (next, prev,
> >> >>> thisTrack).
> >> >>>
> >> >>> addTrack:
> >> >>> Walk to the end of Playlist*, check if thisTrack is NULL, yes-> set
> >> >>> thisTrack to Track*, no-> append another empty item, link it in, set
> >> >>> it's thisTrack.
> >>
> >> That implementation would have to require that the same piece of code
> >> that
> >> manages the playlist also manages the tracks. Because a pointer in that
> >> playlist would become invalid as soon as someone removed/destroyed/freed
> >> the track without first searching *all* playlists and deleting it from
> >> them.
> >
> > I thought the current resource handler would keep track of who wants some
> > resource. If it doesn't I'll fix that together with the rest of it next
> > month.
> >
> >> >>> bindPlaylist:
> >> >>> Set sound engine's nextTrack pointer to 1st item of the given list,
> >> >>> and
> >> >>> advise it to skipTrack() so it plays nextTrack.
> >> >>>
> >> >>> The linked list would perhaps become a bit unhandy when it comes to
> >> >>> shuffling and repeating, but it seems very handy when binding,
> >> >>> adding or switching to the next track...
> >> >>>
> >> >>> What do you think about this? Opinions, objections?
> >> >>
> >> >> I don't know if linked list is best suitable for this or about other
> >> >> implementation details but the idea itself sounds good, this approach
> >> >> is
> >> >> more flexible than current one. For just the in-game playlists it may
> >> >> be
> >> >> too much, but could be usefull when scripts get involved.
> >> >
> >> > I just don't know what else could be used. There are no dynamic arrays
> >> > in
> >> > C, at least none that I know of. And I don't have another idea how
> >> > several dynamic-sized playlists could be handled. (I am lacking
> >> > experience and probably I didn't read my C book till the end.)
> >>
> >> In fact I think dynamic arrays (std::vector or std::list) are probably
> >> the
> >> best way to solve this. Then once your using C++ anyway you might as
> >> well use a smartpointer to hold the `track' object which will fix the
> >> problem I
> >> mentioned above.
> >>
> >> Such a small usage of C++ should be rather easy to contain/manage in a
> >> single (e.g. `lib/sound/playlist.cpp') source file.
> >
> > Well, C doesn't have std::vector, so I had no other idea...
> > What I just thought about was some selfmade dynamic array:
> > struct Playlist { meta-info; Track[]; }
> > malloc( sizeof(meta-info) + sizeof(Track*) * playlistSize );
> > or realloc( ... );
> > Doesn't look nice, but would be an option...
>
> While surely not as elegant as dynamic arrays we can as well just use fixed
> arrays if those are only used to hold pointers to playlists, to be honest I
> doubt anyone would want more than, say, 20 playlists at a time (i'm being
> rather generous).
>
> >> > And the initial idea why I proposed an implementation was that I
> >> > thought
> >> > that createPlaylist needs to return a pointer to something which we
> >> > can see is empty and which first gets filled when we add a track.
> >> > Probably the solution would have been obvious to everyone, but I had
> >> > to think about it for a second, so I thought it's better if I write it
> >> > down. Then
> >> > I got the idea how simple bindPlaylist could be (I first thought that
> >> > it
> >> > might be very complicated, because the playback needs to be stopped
> >> > and buffers need to be cleared and and and...) so I wrote that down,
> >> > too.
> >>
> >> Simply said, you only need two buffers per playlist.
> >>
> >> The simplicity of stopping/pausing playback would depend on wether you
> >> use
> >> one ALsource/playlist or one for all playlists. In the case of one per
> >> playlist you could simply set the source to paused on deactivating the
> >> current playlist, then upon reactivation set it to play again. (number
> >> of ALsources is limited by OpenAL.)
> >
> > One buffer/source per playlist sounds good. If the playlist is stoped
> > (not paused) we could destroy the buffer and the source.
> >
> > Why are 2 buffers needed? Only case I can imagine is when crossfading,
> > but in
> > that case each playlist has it's buffers it will play from and we only
> > have
> > to adjust the gain between them.
> >
> >> If you were to use one for all playlists however then you have about two
> >> (or three) options:
> >>
> >> one bufferset for all playlists (I believe OpenAL limits the amount of
> >> them
> >> to 64?): 1) * on pausing: stop the ALsource
> >> * deattach all ALbuffers from it, destroy them
> >> * remember the last playing track (as playlist position)
> >> * then upon resuming simply restart playback from that song
> >>
> >> one bufferset per playlist.
> >> 2) * on pausing: stop the ALsource
> >> * retrieve the order of the currently attached (non-finished)
> >> ALbuffers
> >> * deattach all ALbuffers from it (but don't destroy them)
> >> * upon resuming reattach all non-finished ALbuffers to the ALsource
> >> in
> >> the correct order * start the ALsource again
> >>
> >> variation on 2, one bufferset for all playlists:
> >> 3) * on pausing: stop the ALsource
> >> * retrieve the amount of time of unplayed sound from the buffers
> >> (through buffer size/count?) * deattach all ALbuffers from it, destroy
> >> them
> >> * upon resuming somehow calculate a new position to start decoding
> >> from
> >> (should be a bit back if buffers where full) * recreate buffers, decode
> >> data to fill them up
> >> * attach them to the ALsource
> >> * start the ALsource again
> >>
> >> Of these 1 and 3 have the best resource efficiency (e.g. memory, amount
> >> of
> >> active ALsources/ALbuffers). 1 will probably be even more efficient (in
> >> terms of big O), 3 will have better accuracy on time position to resume
> >> playing. 2 will probably be the easiest to implement, might have better
> >> timing accuracy than 3 and will most certainly have better big O
> >> efficiency
> >> than 3.
> >>
> >> >>>>> Stopping and resuming the playlist may be interesting to create
> >> >>>>> moments of total silence or when cutscenes are played.
> >> >>>>>
> >> >>>>> C-Functions:
> >> >>>>> WZSound_setPlaylist( Song * song1, ... );
> >> >>>>> WZSound_playTrack( Track interuptionTrack );
> >> >>>>> WZSound_stopPlaylist();
> >> >>>>> WZSound_resumePlaylist();
> >> >>>>> WZSound_setPlaylistMode( PlaylistMode newMode );
> >> >>>>>
> >> >>>>> typedef PlaylistMode UInt8;
> >> >>>>> #define PLAYLIST_SHUFFLE 0x1
> >> >>>>> #define PLAYLIST_REPEAT_ALL 0x2
> >> >>>>> #define PLAYLIST_CROSSFADE 0x4
> >> >>>>> ...
> >>
> >> What about an enum instead?
> >
> > Doesn't go well with bitwise or...
> > ( PLAYLIST_SHUFFLE | PLAYLIST_CROSSFADE ) will not be defined in the
> > enum.
> >
> >> >>>>> C-Function examples:
> >> >>>>> WZSound_setPlaylist( song1, song2, song3 );
> >> >>>>> WZSound_setPlaylist( NULL );
> >> >>>>> WZSound_setPlaylistMode( PLAYLIST_SHUFFLE | PLAYLIST_CROSSFADE );
> >> >>>>>
> >> >>>>> Script-Function examples:
> >> >>>>> WZSound_setPlaylist( "song1.ogg", "song2.ogg", "song3.ogg" );
> >> >>>>
> >> >>>> Variadic functions won't work, we'll have to fall back to something
> >> >>>> like playlistAddSong(song);
> >> >>>
> >> >>> Ok, then I'm fine with Per's playlistAdd and playlistClear
> >> >>> functions.
> >> >>>
> >> >>>>> WZSound_setPlaylist( "none" );
> >> >>>>> WZSound_playTrack( "event1.ogg" );
> >> >>>>> WZSound_setPlaylistMode( "shuffle", "fadein" );
> >> >>>>> WZSound_setPlaylistMode( "repeat_all", "crossfade", "fadeout" );
> >> >>>>> WZSound_setPlaylistMode( "none" );
> >>
> >> Lets not use Cstrings (or any piece of rope for that matter; i.e.
> >> strings)
> >> to indicate play modes.
> >
> > This was for the scripting engine. I don't think it supports bitflags,
> > does
> > it? So the first and possibly easiest option was concatenating strings.
> > Maybe we could also provide the C-defines (PLAYLIST_SHUFFLE,...) as
> > constants
> > to the scripting engine and add them on another...
>
> Sure, best way to solve this is to provide constants predefined by wz,
> works like a charm.
>
> >> >>>> Any particular reason not to use playlistSetMode() instead of
> >> >>>> WZSound_setPlaylistMode()? It's shorter while preserving the same
> >> >>>> meaning.
> >> >>>
> >> >>> For the scripts I don't care.
> >> >>
> >> >> For the scripts, yes.
> >>
> >> I think scripts should indeed have functions without the WZSound in
> >> front of it.
> >>
> >> >>> For the code I think we should develop some unique and sane naming
> >> >>> convention to prevent name clashes and provide a clear and
> >> >>> consistent API. That's why I came up with WZSound_. Other engine (->
> >> >>> lib/) parts might be called WZScript, WZIvis (what does ivis
> >> >>> actually mean/stand for?) or WZGrahics...
> >>
> >> In the codebase itself I really like this idea.
> >
> > Other idea would be to do it GL style:
> > wzBindPlaylist(), wzAddTrack(), ...
> > This wouldn't make it obvious out of which engine part the function
> > comes, though. Dunno if that is aceptable.
> > LIBNAME_function() is commonly used, I think, so I came up with it 1st.
> >
> >> >>>>> Additionally I would sent following events to the scripts (and
> >> >>>>> over the internal event-bus), namings are currently very bad:
> >> >>>>> playlist_stop
> >> >>>>> playlist_resume
> >> >>>>> playlist_nextTrack
> >> >>>>> playlist_customTrack
> >> >>>>> playlist_customTrackEnd
> >> >>>>> playlist_modeChange
> >> >>>>> playlist_new
> >> >>>>> playlist_end
> >> >>>>>
> >> >>>>> --Dennis
> >> >>>>
> >> >>>> Script events would be usefull. Those would end up being named
> >> >>>> CALL_PLAYLISTEND, CALL_SONGEND etc following wz convention. But
> >> >>>> those
> >> >>>> are details, provide me playlist functionality I'll take care of
> >> >>>> the rest, probably not until mid february though.
> >> >>>
> >> >>> 2.1 won't be released in February and probably not in March or
> >> >>> anytime
> >> >>> soon. So this currently doesn't matter that much. ;)
> >>
> >> In that case lets haul the code over entirely ;-).
> >>
> >> >>>> PS: geez am I the only one having trouble replying to attached
> >> >>>> files?
> >> >>>
> >> >>> Apparently: Yes...
> >> >>
> >> >> Wouldn't have asked if it was apparent. I was refering to those '>'
> >> >> markers actually. Don't see a way how to add them with outlook
> >> >> express,
> >> >> which forces me to make a small detour.
> >> >
> >> > Outlook doesn't give you those '>' if you press reply on a mail which
> >> > has
> >> > an attached file???
> >>
> >> Of course I can advise you to take and use Thunderbird instead ;-) .
> >> It's more powerful than Outlook (e.g. in case of low level access, mem
> >> footprint, etc).
>
> Might as well do this someday, for now I think I'll give Outlook a try and
> see if it offers enough functionality (using Outlook Express right now).
>
> BTW why don't we just use forums for such discussions? This starts to look
> a bit awkward to me. Maybe we can ask Kamaze to set up some protected area
> for the developers and those participating in the mailinglist discussion?
> Personally i'd also be fine with a public forum, not sure if this would
> work well though.
I think most of us are going well with a mailinglist and prefer it this way.
At least to me it's much simpler to fire up my mail client and watch several
threaded discussions. Forums have that flat, time-related style (lost the
words... Allready getting late. I mean they only have one direction, you
can't split of a discussion as easily) which makes the inconvenient IMO...
--Dennis
pgpUYD9JoKWSz.pgp
Description: PGP signature
_______________________________________________ Warzone-dev mailing list [email protected] https://mail.gna.org/listinfo/warzone-dev
