Okay, here's my first cut of packets that I've made up that could let the world server configure the client to some small extent. Aside from the first one, I haven't added support for these yet, but I've made lots of internal architectural changes so that they would be easy to support. My question is, before I code these up, is there anything else we need to add? (I'm aware that at some point we want packets to change the number of available races, classes, deities, etc., but those should be separate).
Code:
// This is a TEXT file that the program reads to determine record structures.
// The format is as follows:
//
// NONE OF THE ENTRIES IN THIS FILE ARE CASE-SENSITIVE
//
// structname <struct name>
// structsize <size>
//
// <byte offset> <type> [struct name] <field name><array sizes>
//
// Structname: This sets the literal name of the struct to be used by the parser.
//
// Structsize: This tells the program how big the structure is.
//
// Byte Offset: must be a decimal number.
//
// Type: can be any of the following:
//
// sint8 or int8 (signed 8-bit number)
// uint8, char, or byte (unsigned 8-bit number)
// sint16 or int16 (signed 16-bit number)
// uint16 or word (unsigned 16-bit number)
// sint32 or int32 (signed 32-bit number)
// uint32 or dword (unsigned 32-bit number)
// sint64 (signed 64-bit number)
// float (32-bit single-precision floating point value)
// double (64-bit double-precision floating point value)
// struct or record (a structure/record)
//
// Structs may only have names that are used in "structname" declarations, e.g.:
//
// itemproperties_struct
//
// Note that unions aren't explicitly specified. They aren't necessary since
// the byte offset tells where each field lies.
//
// Field name: The program is looking for these SPECIFIC names, regardless
// of what they are called in the actual server code. Remember that this program
// doesn't treat anything here as case-sensitive. It's too easy to make typing
// mistakes.
//
// Array sizes: The format should be the same as in C (see below). ALL TEXT
// AFTER THE TERMINATING SEMICOLON IS IGNORED
//
// Comments: ONLY single-line comments using two slashes are supported.
//
// Blank lines: they are ignored.
//
// Tabs: I personally abhor the tab character, but the parser doesn't care.
// The first thing it will do is convert them to spaces.
//
// Whitespace: Put as much whitespace at the beginning or end of each line as
// you want. It will all be stripped prior to parsing.
// ClientVersion_Struct
// ============================================================================
// PURPOSE
//
// Client tells the world server its version.
// ----------------------------------------------------------------------------
// NOTES
//
// 1. A typical string sent would be of the form: SimpleClient_1.0.0.0
// 2. The string could, however, take any form within the space allotted.
// 3. The string is null-terminated.
// ----------------------------------------------------------------------------
// FIELD DETAILS
//
// FileVersion
// A null-terminated string containing the client name and/or version.
// ============================================================================
structname ClientVersion_Struct
structsize 64
00000000 char FileVersion[64]
// PlayerSingleClassInfo_Struct
// ============================================================================
// PURPOSE
//
// World server tells the client details about a single player class.
// ----------------------------------------------------------------------------
// NOTES
//
// 1. Corresponding names for class and stat indices can be found in clientdata.xml.
// ----------------------------------------------------------------------------
// FIELD DETAILS
//
// ClassIndex
// The zero-based index of the player class. Valid values are in the range
// 0-31. The client will ignore all others.
//
// BaseStats
// An array of values to be added to the base player stats for the given class.
// For instance, all warriors might start with a strength bonus.
//
// AddPoints
// Specifies the number of additional points that players have available to
// assign to stats as they wish.
//
// AllowableSkills
// A bit-field that specifies which skills are available to the class, where
// the LSB of the first element is skill #0 and the MSB of the last element is
// skill #255 (little-endian).
// ============================================================================
structname PlayerSingleClassInfo_Struct
structsize 104
00000000 uint32 ClassIndex
00000004 sint32 BaseStats[16]
00000068 uint32 AddPoints
00000072 uint32 AllowableSkills[8]
// PlayerClassInfo_Struct
// ============================================================================
// PURPOSE
//
// World server tells the client details about the available player classes.
// ----------------------------------------------------------------------------
// NOTES
//
// 1. This is a variable-length struct.
// 2. This does NOT allow the world server to change the number of available classes.
// That will be handled in a different packet.
// ----------------------------------------------------------------------------
// FIELD DETAILS
//
// NumClasses
// Contains the number of PlayerSingleClassInfo_Struct entries there are
//
// ClassInfo
// Contains detail information for a single player class. See PlayerSingleClassInfo_Struct
// for documentation on this field.
// ============================================================================
structname PlayerClassInfo_Struct
structsize 108
00000000 uint32 NumClasses
00000004 struct PlayerSingleClassInfo_Struct ClassInfo[1]
// PlayerSingleRaceInfo_Struct
// ============================================================================
// PURPOSE
//
// World server tells the client details about a single player race.
// ----------------------------------------------------------------------------
// NOTES
//
// 1. Corresponding names for class, stat, deity, and skill indices can be found
// in clientdata.xml.
// ----------------------------------------------------------------------------
// FIELD DETAILS
//
// RaceIndex
// The zero-based index of the player race. Valid values are in the range
// 0-31. The client will ignore all others.
//
// ModelIndex
// The number corresponding to the race as understood by the server (there are
// hundreds of these, but only a small number are player races).
//
// Voice
// Specifies the voice pitch (low, medium, high) for sounds such as player
// jumping, getting hit, etc. Valid values are:
// 0 ... low
// 1 ... medium
// 2 ... high
//
// ObsHeight
// Floating-point number that specifies in world coordinates how far a player's
// viewpoint is above the player's feet. For instance, tall races should have
// larger values than short races.
//
// BaseStats
// An array of values that specify the base player stats for a given race, (e.g.
// strength, intelligence, etc.)
//
// AllowableClasses
// A bit-field that specifies which classes are available to the race, where the
// LSB is class #0 and the MSB is class #31 (little-endian).
//
// AllowableDeities
// A bit-field that specifies which deities are available to the race for each class,
// where the LSB is deity #0 and the MSB is deity #31 (little-endian).
//
// AllowableCities
// A bit-field that specifies which starting cities are available to the race for
// each deity, where the LSB is city #0 and the MSB is city #31 (little-endian).
// ============================================================================
structname PlayerSingleRaceInfo_Struct
structsize 337
00000000 uint32 RaceIndex
00000004 uint32 ModelIndex
00000008 uint8 Voice
00000009 float ObsHeight
00000013 uint32 BaseStats[16]
00000077 uint32 AllowableClasses
00000081 uint32 AllowableDeities[32]
00000209 uint32 AllowableCities[32]
// PlayerRaceInfo_Struct
// ============================================================================
// PURPOSE
//
// World server tells the client details about the available player races.
// ----------------------------------------------------------------------------
// NOTES
//
// 1. This is a variable-length struct.
// 2. This does NOT allow the world server to change the number of available races.
// That will be handled in a different packet.
// ----------------------------------------------------------------------------
// FIELD DETAILS
//
// NumRaces
// Contains the number of PlayerSingleRaceInfo_Struct entries there are
//
// RaceInfo
// Contains detail information for a single player race. See PlayerSingleRaceInfo_Struct
// for documentation on this field.
// ============================================================================
structname PlayerRaceInfo_Struct
structsize 341
00000000 uint32 NumRaces
00000004 struct PlayerSingleRaceInfo_Struct RaceInfo[1]
I figure that since this has a direct effect on the community at large we should have a healthy discussion on this topic. I'm aware that we've already had a "blue-sky" discussion on client capabilities, but those are much longer-lead items and this is where we really get to brass tacks. Because the client is currently so closely tied to the server, I could really use some direction on how to make it more flexible in concrete and incremental terms.