Dbserver-protocols
dbserver listens on several ports, each one providing a different service. Most services correspond to another server which will connect. All of these services use the common Network protocol, in TCP-only mode.
account
AccountServer connects to this service. It deals primarily with the ShardAccount container, with auth_id being the container ID for this DbList.
It can receive the following commands:
ACCOUNT_SVR_CONNECT
This message has no body. If an AccountServer is already connected, dbserver will respond by closing the link. Otherwise, it will respond with DBSERVER_ACCOUNT_PROTOCOL_VERSION:
autobits protocol_version string shard_name autobits count repeated count times: autobits auth_id string auth_name
protocol_version will be DBSERVER_ACCOUNT_PROTOCOL_VERSION, currently 20070925.
dbserver will send the complete list of names and container IDs for all ShardAccount containers.
If IsLoggingMaster is set in server_cfg, dbserver will also send a ACCOUNT_CLIENT_UPDATE_LOG_LEVELS message:
repeated LOG_LEVELS times: packint(1) log_level
These are the log levels, as managed by log.h, for all logging types in order from 0 to LOG_LEVELS. They are set in servers.cfg with SetLogLevel lines.
ACCOUNT_SVR_RELAY_CMD
autobits message_dbid optional autobits auth_id string cmd
auth_id is sent only if message_dbid is 0.
If message_dbid is not 0, then it is the container ID of an Ent, and dbserver will send a DBSERVER_RELAY_CMD to the MapServer where that Ent is connected:
string relay_cmd
where relay_cmd will be:
cmdrelay_dbid %d 0 conprint "%s"
filled in with message_dbid and cmd.
If auth_id is not 0, then it is the auth_id of a player, which will be used to find the link that game client has with the dbserver. If one exists, then dbserver will send it a DBGAMESERVER_ACCOUNTSERVER_UNAVAILABLE:
string cmd
with cmd unchanged.
ACCOUNT_SVR_CHARCOUNT_REQUEST
autobits auth_id bits(1) vip
The vip flag will be applied to the ShardAccount auth_id, doing an SQL update if necessary.
Some SQL queries will be run to get the current character count, and when they are complete, dbserver will respond with a ACCOUNT_CLIENT_CHARCOUNT_REPLY:
autobits auth_id autobits unlocked_used_count autobits total_char_count autobits bonus_slots autobits server_max_count autobits vip_only_server
ACCOUNT_SVR_CHARCOUNT_REPLY
autobits auth_id autobits shards repeated shards times: string shard_name autobits unlocked_used autobits total_used autobits account_extra autobits server_max autobits vip_only_server
If shards is 0 then instead the packet will contain:
autobits auth_id autobits shards string error_msg
dbserver finds the game client connection corresponding to auth_id and sends it DBGAMESERVER_ACCOUNTSERVER_CHARCOUNT, which is identical to the message received, except the auth_id is not included.
ACCOUNT_SVR_SLOTCOUNT_REQUEST
autobits auth_id
dbserver replies with ACCOUNT_CLIENT_SLOTCOUNT_REPLY:
autobits auth_id autobits slot_count
Taking slot_count from the ShardAccount container for auth_id
ACCOUNT_SVR_PRODUCT_CATALOG_UPDATE
autobits timestamp autobits auth_timeout string mtx_environment string playspan_domain string playspan_catalog string playspan_url_home string playspan_url_categoryview string playspan_url_itemview string playspan_url_showcart string playspan_url_addtocart string playspan_url_manageaccount string playspan_url_supportpage string playspan_url_supportpage_de string playspan_url_supportpage_fr string playspan_url_upgradetovip string coh_url_newfeatures string coh_url_newfeaturesupdate autobits playspan_store_flags
dbserver will send DBSERVER_ACCOUNTSERVER_CATALOG to every map server, proxying the contents of the packet.
dbserver will send DBGAMESERVER_ACCOUNTSERVER_CATALOG to every connected game client, proxying the contents of the packet.
ACCOUNT_SVR_CLIENTAUTH
autobits auth_id autobits timestamp string playspan_digest
dbserver finds the game client connection corresponding to auth_id and proxies this message as DBGAMESERVER_ACCOUNTSERVER_CLIENTAUTH, excluding the auth_id field.
ACCOUNT_SVR_PLAYNC_AUTH_KEY
autobits auth_id autobits request_key string plaync_auth_key
dbserver finds the game client link for this auth_id and proxies this message as DBGAMESERVER_ACCOUNTSERVER_PLAYNC_AUTH_KEY, excluding the auth_id.
ACCOUNT_SVR_SHARDXFER
OrderId order_id autobits step
Depending on the value of step, the layout of the rest of the packet changes. Each of these messages is a step in the process of transferring a player character from one dbserver to another. dbserver will respond with ACCOUNT_CLIENT_SHARDXFER, which begins with the same two fields:
OrderId order_id autobits step
The rest of the messages are described below, for each possible value of step.
When step is SHARDXFER_VALIDATE_SRC:
autobits ent_id
dbserver responds with:
bits(1) exists
where exists is 1 if the ent_id is a valid Ent and 0 if it does not exist.
When step is SHARDXFER_VALIDATE_DST:
autobits auth_id bits(1) vip
dbserver responds with:
autobits unlocked_used_count autobits total_used_count autobits account_max_slots autobits server_max_slots autobits vip_only_server
When step is SHARDXFER_FULFILL_COPY_SRC:
autobits ent_id autobits type string visitor_data_packet
then dbserver will send DBSERVER_RELAY_CMD to the MapServer for this Ent (forcibly loading them to a MapServer if the player is offline) with:
cmdrelay_dbid %d shardxfer_init %s %d %d %s
populated with ent_id, order_id, type, home_shard, visitor_data_packet where home_shard is the shard_id of this dbserver in turnstile_server.cfg.
If type is XFER_TYPE_VISITOR_OUTBOUND or XFER_TYPE_VISITOR_BACK then visitor_data_packet will be suffixed by a semicolon and the name of this shard from servers.cfg.
If ent_id is not a loaded Ent, and type is XFER_TYPE_PAID, then dbserver runs SQL queries to load the Ent and continues. For all other values of type, it returns an error to AccountServer.
When step is SHARDXFER_FULFILL_COPY_DST:
string container_txt
then dbserver will run an SQL query to check the Ent table for rows where AccSvrLock is order_id (or in development mode, where AccSvrLock is kOrderIdInvalid - this probably breaks things). If that row exists, then the ID of that Ent is returned. Otherwise, a new Ent will be created from container_txt, and the ID of that Ent is returned:
autobits ent_id
dbserver will extract the AuthName from container_txt and validate that this account has free character slots. It will rename the character if there is a collision, and grant a rename token to the character if it does so. The container is then created and added to the SQL queue for writing. The container is immediately backed up into a hogg, and then unloaded.
When step is SHARDXFER_FULFILL_COMMIT_SRC:
autobits dbid string dst_shard autobits dst_dbid autobits type
In this step, visitor transfers (when type is XFER_TYPE_VISITOR_OUTBOUND or XFER_TYPE_VISITOR_BACK) are handled differently: for these, dbserver finds the turnstile server for the destination shard, and sends it DBSERVER_COOKIE_REQUEST:
OrderId order_id autobits dbid autobits type autobits dst_dbid autobits auth_id string account_name bits(128) auth_data autobits home_shard_id autobits dst_shard_id
For non-visitor transfers, dbserver instead sends AUCTION_CLIENT_ACCOUNT_SHARDXFER to AuctionServer, to begin the inventory transfer:
OrderId order_id autobits dbid string dst_shard autobits dst_dbid
In development mode, dbserver skips the AuctionServer interaction and sends back a response to AccountServer with no further fields.
When step is SHARDXFER_FULFILL_COMMIT_DST:
autobits auth_id autobits ent_id
dbserver sends an SQL update to remove the AccSvrLock field from the Ents table for ent_id, and sends ACCOUNT_CLIENT_MARK_SAVED to AccountServer:
autobits auth_id autobits count // always 1 in this scenario repeated count times: OrderId order_id
then responds with ACCOUNT_CLIENT_SHARDXFER as usual, with no additional fields.
When step is SHARDXFER_FULFILL_COMMIT_RECOVERY:
autobits auth_id
dbserver searches the Ents table for entries with AccSvrLock matching this OrderId, and then runs the COMMIT_DST procedure on those rows. It then responds with:
bits(1) found
where found is 1 if any rows matched this OrderId, and 0 if none did.
When step is SHARDXFER_FULFILL_XFER_JUMP:
autobits dbid
dbserver sends a DBSERVER_RELAY_CMD to the client (forcibly loading offline characters onto a MapServer if necessary), with this command:
cmdrelay_dbid %s shardxfer_jump
populated with dbid.
For this step, dbserver does not send a ACCOUNT_CLIENT_SHARDXFER response to AccountServer.
ACCOUNT_SVR_RENAME
OrderId order_id bits(1) fulfill autobits ent_id
When fulfill is false, dbserver will do some checks and then respond with ACCOUNT_CLIENT_RENAME:
OrderId order_id bits(1) validating bits(1) confirm
validating will be 1. confirm will be 1 if:
- The Ent is currently loaded (this may be a bug, it does not check for the renameable flag)
- There is an Ent in the SQL database with this ID, which is not locked, and the DbFlags column for that row has the DBFLAG_RENAMEABLE bit set.
When fulfill is true, the Ent will be loaded if necessary, forcibly loaded onto a MapServer if currently offline, and then sent a DBSERVER_RELAY_CMD with:
cmdrelay_dbid %d order_rename %s
populated with ent_id and order_id
If the Ent is loaded, no response will be sent (bug), otherwise an ACCOUNT_CLIENT_RENAME will be sent with validating set to 0, and confirm will be set to 1 if the Ent was found and sent the command.
ACCOUNT_SVR_SLOT
OrderId order_id autobits auth_id
dbserver increments the SlotCount field in the ShardAccount identified by auth_id and saves the container. It responds to AccountServer with ACCOUNT_CLIENT_SLOT:
OrderId order_id bits(1) confirm
where confirm is 1 if the update was applied, and 0 if no ShardAccount with this ID could be found.
ACCOUNT_SVR_RESPEC
OrderId order_id bits(1) fulfilling autobits ent_id
When fulfilling is 0, dbserver checks the Ent identified by ent_id, and responds with ACCOUNT_CLIENT_RESPEC:
OrderId order_id bits(1) validating bits(1) confirm
where validating is 1 and confirm is 1 if the Ent exists and is not locked.
When fulfilling is 1, the Ent will be loaded if necessary, forcibly loaded onto a MapServer if currently offline, and then sent a DBSERVER_RELAY_CMD with:
cmdrelay_dbid %d order_respec %s
The response will have validating set to 0 and confirm set to 1 if the Ent was found and a command sent. The response might not be sent if the container is already loaded (bug).
ACCOUNT_SVR_NOTIFYTRANSACTION
autobits auth_id autobits2 sku autobits inv_type OrderId order_id autobits granted autobits claimed bits(1) success
The game client link for auth_id is found. If dbserver has a direct link to that client, nothing happens. Otherwise, dbsevers send a DBSERVER_ACCOUNTSERVER_NOTIFYTRANSACTION to the player's current MapServer with the same content as this message, except the auth_id is replaced with the entity ID of the player's current character.
ACCOUNT_SVR_NOTIFYREQUEST
autobits auth_id autobits type OrderId order_id bits(1) success string message
The game client link for auth_id is found. A DBGAMESERVER_ACCOUNTSERVER_NOTIFYREQUEST is sent with the same content as this message, without the auth_id.
ACCOUNT_SVR_NOTIFYSAVED
autobits auth_id autobits type OrderId order_id bits(1) success string message
The game client link for auth_id is found. If there is a direct connection to the dbserver, nothing happens. Otherwise, a DBSERVER_ACCOUNTSERVER_NOTIFYSAVED is sent to the MapServer where that client is connected, with the same content as this message, with the auth_id replaced by the ent_id of the player's current character.
ACCOUNT_SVR_INVENTORY
autobits auth_id autobits count repeated count times: autobits2 sku autobits granted_total autobits claimed_total autobits expires packint(1) shard_xfer_free_only autobits shard_xfer_tokens bits(128) loyalty_status autobits loyalty_points_unspent autobits loyalty_points_earned autobits virtual_currency_balance autobits last_email_time autobits last_num_emails_sent
This data is stored in the ShardAccount container, and then either sent to the game client or MapServer as DBGAMESERVER_ACCOUNTSERVER_INVENTORY or DBSERVER_ACCOUNTSERVER_INVENTORY
ACCOUNT_SVR_CERTIFICATION_GRANT_ACK
ACCOUNT_SVR_CERTIFICATION_CLAIM_ACK
ACCOUNT_SVR_CERTIFICATION_REFUND_ACK
ACCOUNT_SVR_MULTI_GAME_TRANSACTION_ACK
ACCOUNT_SVR_MULTI_GAME_TRANSACTION_COMPLETED
ACCOUNT_SVR_FORCE_LOGOUT
autobits auth_id
The game client connected for auth_id is forcibly disconnected, notifying connected MapServer or QueueServer.
ACCOUNT_SVR_DB_HEARTBEAT
arena
This service supports the same protocol messages as the db service, documented below. It is used for ArenaServer to connect to dbserver, and the remote socket address of the ArenaServer connected on this port is used in processing DBCLIENT_REQ_ARENA_ADDRESS, but this service is not otherwise different.
auction
AuctionServer connects to this service. It can receive the following commands:
AUCTION_SVR_CONNECT (2)
The message has no parameters. dbserver will accept only a single connection, and while it has one, it will respond to all further AUCTION_SVR_CONNECT messages by closing the connection.
dbserver responds with AUCTION_CLIENT_CONNECT (2):
packint(1) protocol_version string shard_name bits(1) have_inactive_players something....
AUCTION_SVR_SEND_INV (3)
autobits entity_id string inventory
dbserver finds the mapserver for entity_id, and proxies the message there as DBSERVER_AUCTION_SEND_INV
inventory is eventually decoded by AuctionInventory_FromStr in the mapserver, but dbserver proxies it without inspecting its value.
AUCTION_SVR_SEND_HISTORYINFO (4)
autobits entity_id string identifier autobits buying_count autobits selling_count autobits history_count repeated history_count times: autobits date autobits price
dbserver finds the mapserver for entity_id, and proxies the message there as DBSERVER_AUCTION_SEND_HIST.
AUCTION_SVR_BATCH_SEND_ITEMINFO (5)
autobits entity_id zipped data
dbserver finds the mapserver for entity_id, and proxies the message there as DBSERVER_AUCTION_BATCH_INFO. The zipped data is not inspected by dbserver.
After this output packet has been queued, dbserver sends AUCTION_CLIENT_DATAOK to the AuctioServer, with no both. This is a primitive form of flow control. It does not wait for the message to be sent to the mapserver before doing this.
AUCTION_SVR_XACT_CMD (7)
autobits entity_id autobits type XactCmd cmd
dbserver finds the mapserver for entity_id. If there is one, it proxies the message there as DBSERVER_AUCTION_XACT_CMD. If there is no mapserver, then dbserver responds to AuctionServer with AUCTION_CLIENT_XACT_UPDATE, sending:
autobits xid autobits subid autobits result
Where xid and subid are taken from cmd, and the result is set to kXactCmdRes_No.
AUCTION_SVR_RELAY_CMD_BYENT (9)
packint(1) entity_id packint(1) force string msg
dbserver finds the mapserver for entity_id. If there is one, it sends DBSERVER_RELAY_CMD there with msg as the body. If there is no mapserver, and force is set to 1, then the message is queued for relaying when the entity is available, and dbserver begins attempting to load the entity into a mapserver.
AUCTION_SVR_THROTTLE_ON (10)
This message has no parameters, and dbserver sends no response. It enables throttling, which prevents some (???) messages from being sent to the AuctionServer.
AUCTION_SVR_THROTTLE_OFF (11)
This message has no parameters, and dbserver sends no response. It disables throttling.
AUCTION_SVR_ACCOUNT_SHARDXFER (12)
OrderId order_id autobits dbid
dbid is interpreted as an Ent id. dbserver will offline (???) and delete (???) the player, and then send AccountServer an ACCOUNT_CLIENT_SHARDXFER with:
OrderId order_id autobits SHARDXFER_FULFILL_COMMIT_SRC
beacon
client
This service is used for the game client to communicate with dbserver.
It is documented on Client-to-dbserver
db
This service is used to communicate with MapServer and RaidServer.
Every NetLink for the db server has a unique lock_id, starting from 0. They are used to identify current connections to MapServer in order to send messages.
DBCLIENT_INITIAL_CONNECT
optional packint(1) map_protocol
If map_protocol is not present (the body is empty), it is 0. If map_protocol is not equal to DBSERVER_PROTOCOL_VERSION (currently 20110503) then dbserver will respond with DBSERVER_CLIENT_CMD_FAILED and close the NetLink.
Otherwise, dbserver sends these commands back to the MapServer:
DBSERVER_TIMEOFFSET:
bits(32) seconds_since_2000 float32 time_zone_delta
These values are set based on the system clock. time_zone_delta is the difference between UTC and local time, in hours.
DBSERVER_OVERRIDDEN_AUTHBITS
bits(128) overridden_auth_bits
The value of overridden_auth_bits is set based on OverrideAuthBit lines in servers.cfg.
If any DisabledZoneEvents entries are present in servers.cfg, dbserver sends a DBSERVER_DISABLED_ZONE_EVENTS command:
repeated string event
One entry for each DisabledZoneEvents line in servers.cfg
If user reactivation is active, dbserver sends a DBSERVER_NOTIFY_REACTIVATION message, with no body.
DBSERVER_UPDATE_LOG_LEVELS:
repeated LOG_LEVELS times: packint(1) log_level
These are the log levels, as managed by log.h, for all logging types in order from 0 to LOG_LEVELS. They are set in servers.cfg with SetLogLevel lines.
DBSERVER_ACCOUNTSERVER_CATALOG:
autobits catalog_timestamp autobits auth_timeout string mtx_environment string play_span_domain string play_span_url_home string play_span_url_categoryview string play_span_url_itemview string play_span_url_showcart string play_span_url_addtocart string play_span_url_manageaccount string play_span_url_supportpage string play_span_url_supportpage_de string play_span_url_supportpage_fr string play_span_url_updatetovip string coh_url_newfeatures string coh_url_newfeaturesupdate autobits play_span_store_flags
These appear to be values set in account_server.cfg. Most of them are URLs.
DBCLIENT_READY
This message is understood by dbserver, but does not appear to be sent by mapserver; it is suspected to be historical debris.
DBCLIENT_REGISTER
packint(1) map_id packint(1) local_ip packint(1) remote_ip packint(1) udp_port packint(1) tcp_port packint(1) static_link packint(1) cookie string patch_version optional string map_name
A MapServer sends this message when it starts up, immediately after DBCLIENT_INITIAL_CONNECT.
static_link is set based on the command line of the MapServer
map_id is a signed int, set on the command line of the MapServer. Negative values mean that a map_name field will be sent and edit mode will be used.
If map_id is non-negative, then dbserver selects the container for this mapserver based on map_id, and closes the link if the map_id is not known. Otherwise, dbserver selects the container based on map_name, and enables edit mode on this container. If static_link is set, then dbserver searches for a map with this name. If static_link is not set, or no map of this name is found, then a new map container is created and populated with the data in the map_name field.
udp_port and tcp_port are the ports on which the MapServer will listen for game clients, and are set on the command line.
cookie is set on the command line of the MapServer, and sent as-is. If the cookie is non-zero, then dbserver will validate that it matches the cookie matches the container referenced by map_id, and will close the link if it does not match. This is used to ensure the MapServer is the one this dbserver wanted to spawn, and not from a previous instance of dbserver.
local_ip and remote_ip are sent by the mapserver, based on the result of gethostbyname(NULL). They will use the first two results from this function. If one of those results is an rfc1918 address, or 127.0.0.1 (none of the other loopback addresses are recognised as "local"), then it will be local_ip; otherwise local_ip will be the first result from gethostbyname() and remote_ip will be the second.
The map container in the dbserver will have its link set to the link which sent this message, and will be marked starting and active. dbserver will respond to the MapServer with DBSERVER_CONTAINERS, sending the container for map_id followed by the containers for all static maps.
DBCLIENT_REGISTER_CONTAINER_SERVER
packint(1) list_id
The client attempts to claim ownership of the DbList identified by list_id. This is used by RaidServer to register itself with dbserver. Only one link may own a DbList at a time. If another link has claimed the DbList, then this one is marked as waiting for it. If the owner of the DbList is disconnected, then a link which is waiting for it will become the owner.
When a link becomes the owner of a DbList, then dbserver sends it a DBSERVER_CONTAINER_SERVER_ACK:
packint(1) list_id packint(1) max_session_id
Owning a DbList affects the handling of DBCLIENT_CONTAINER_RELAY and DBCLIENT_REGISTER_CONTAINER_SERVER_NOTIFY messages.
DBCLIENT_REGISTER_CONTAINER_SERVER_NOTIFY
packint(1) notify_mask
All DbLists owned by this link have their notify mask set to notify_mask.
notify_mask is a bitmask, where each bit corresponds to a ContainerType value. For each bit set, when a notification for that DbList is available, a DBSERVER_CONTAINER_SERVER_NOTIFY will be sent:
packint(1) list_id packint(1) container_id packint(1) member_id bits(1) is_added
Notifications are only sent for the addition of Ents (player characters loading onto a map), deletion of containers, and for adding and removing group members. When an Ent is added, an add notification is sent for all groups that Ent is currently a member of.
is_added is 1 if a thing is being added, and 0 if a thing is being removed.
container_id is the id of the container being updated - either the group where members are being added or removed, or the container being deleted.
member_id is 0 if the operation is the removal of a group (supergroup deletion, etc), or the member ID if the operation is adding or removing a member from a group.
DBCLIENT_READY_FOR_PLAYERS
packint(1) map_id
This message is sent by MapServer when it has finished settup in the map. It marks the MapCon as not starting. If the MapCon has been marked for shutdown in the dbserver, then the dbserver will respond with an empty DBSERVER_TEAM_LEFT_MISSION message.
DBCLIENT_CONTAINER_INFO
This message has no body. dbserver will respond with DBSERVER_CONTAINER_INFO:
packint(1) count string dbserver_status repeated count-1 times: string container_status
dbserver_status will be a string like "DbServer started on %s, Up %d hours, %d minutes"
container_status will be a string like "0040 Ent (1)", giving the number of allocated containers in the each DbList, and its name and ContainerType value.
DBCLIENT_REQ_CONTAINERS
packint(1) user_data packint(1) list_id packint(1) cmd packint(1) count repeated count times: packint(1) container_id
dbserver will respond to this message with DBSERVER_CONTAINERS, with some containers selected from DbList list_id. user_data is returned in the DBSERVER_CONTAINERS response.
If cmd is CONTAINER_CMD_LOAD_ALL, count is ignored and all containers in the list are selected. Otherwise, container_id values are sent in the message, and those containers are selected.
Depending on the command selected, three other operations might be performed on this list:
- With CONTAINER_CMD_LOCK_AND_LOAD, CONTAINER_CMD_LOAD_ALL, CONTAINER_CMD_TEMPLOAD, or CONTAINER_CMD_TEMPLOAD_OFFLINE the containers will be loaded if necessary. Otherwise, containers that are not loaded will return an error code of CONTAINER_ERR_DOESNT_EXIST for that container.
- With CONTAINER_CMD_LOCK or CONTAINER_CMD_LOCK_AND_LOAD the containers will be locked to this link. Any container which is already locked by another link will return an error code of CONTAINER_ERR_ALREADY_LOCKED for that container.
- With CONTAINER_CMD_TEMPLOAD or CONTAINER_CMD_TEMPLOAD_OFFLINE any containers that have to be loaded for this message will be unloaded after it is finished.
- With CONTAINER_CMD_TEMPLOAD_OFFLINE the special handling for offline players (???) is used.
DBCLIENT_SET_CONTAINERS
packint(1) list_id packint(1) cmd packint(1) callback_id packint(1) count repeated count times: packint(1) container_id packint(1) notdiff packint(1) debugdiff string str optional string debugdiff_str
debugdiff_str is only sent when debugdiff is not 0, otherwise it is skipped
dbserver stores the containers, and responds with DBSERVER_CONTAINER_ACK to most messages:
packint(1) list_id packint(1) callback_id packint(1) count repeated count times: packint(1) ack_id
The ack_id values will be the container_id values that were updated.
One DBSERVER_CONTAINER_ACK response is sent after every update is applied, containing all acks so far (this appears to be a bug, and not used for anything). Acks are used by MapServer to return the container_id when creating containers, and otherwise ignored.
The exception to this are:
- when list_id is the AutoCommands list, in which case dbserver will instead respond by broadcasting a DBSERVER_CONTAINERS message to all active MapServers with the new container value
- when the container is a GroupCon type, and cmd is not CONTAINER_CMD_UNLOCK_NOMODIFY, in which case dbserver will instead respond by broadcasting a DBSERVER_CONTAINERS message to all interested links:
- MapServers that are running members of a MapGroup
- MapServers that have connected Ents for other groups
- the MapServer for a supergroup base
- the statserver for a statserver group
- the link that sent the DBCLIENT_SET_CONTAINERS message)
In these cases, no DBSERVER_CONTAINER_ACK messages are sent.
Possible values for cmd are:
- CONTAINER_CMD_CREATE, in which case id must be -1 and the container will be created.
- CONTAINER_CMD_CREATE_MODIFY, in which case id may be -1 and the container will be created if no container with this id exists.
- CONTAINER_CMD_DELETE, which will mark the container for deletion. str is ignored.
- CONTAINER_CMD_UNLOCK, which will apply updates and then unlock the container if this link has it locked.
- CONTAINER_CMD_UNLOCK_NOMODIFY, which will unlocked the container if this link has it locked, and not attempt to update the container. str is ignored
- CONTAINER_CMD_TEMPLOAD, which will load the container before updating it, and unload it after updating it, regardless of whether it was already loaded.
All other values of cmd will apply the update to an existing container.
If an error occurs, dbserver will abandon processing of the rest of the message, and respond with DBSERVER_CLIENT_CMD_FAILED:
packint(1) fail_code string str
This occurs in the following scenarios:
- id is -1 for commands other than CREATE and CREATE_MODIFY, or id being any value other than -1 for CREATE, will return CONTAINER_ERR_DOESNT_EXIST
- Parse errors for the container in str will return CONTAINER_ERR_CANT_COMPLETE_SERIOUS
- An attempt to create an Ent on an account without free character slots will return CONTAINER_ERR_CANT_COMPLETE
- An attempt to create an Ent where the character name cannot be parsed will return CONTAINER_ERR_CANT_COMPLETE
- For DbList other than maps, a container that exists must not be locked to a link other than this one, or it will return CONTAINER_ERR_ALREADY_LOCKED
- For DbList other than maps, and commands other than CREATE_MODIFY, the container must be locked or it will return CONTAINER_ERR_NOT_LOCKED
- If the container does not exist for whatever reason (after processing creation), it will return CONTAINER_ERR_DOESNT_EXIST
Applying container updates
str will be treated as a diff if notdiff is 0, or as a full copy of the container if notdiff is 1.
If the container does not have a template, then the string supplied always treated as a complete replacement, and the content of the container is simply set to this value, then special column processing is run.
If the container has a template, and notdiff is 1, then a diff will be computed from the current value of the template to the string supplied, and then processing will continue as if a diff had been sent.
If the container has a template, then the string will be parsed into a line list, and then merged into the current line list. Next, special column processing is run. The computed updates are then added to the queue of sql writes, and if the container has an update callback, it is called (this is probably a bug: it will be called twice).
Special columns processing begins by calling the update callback. It then runs through a list of commands, which identify fields in the line list by name. The values of these fields will be written into some address inside the DbContainer struct, as identified by the command. In the particular case of CMD_MEMBER, special tracking is done of memberships, which may result in sending notifications to servers that requested them with DBCLIENT_REGISTER_CONTAINER_SERVER_NOTIFY.
Special hackery
If the command is CREATE and the DbList is Ents (creating a player), then the player name will be uniquified (by appending or incrementing a number).
If the DbList is maps, and there is a map name in str, and a container with that name exists, then id is ignored and the container with that name is updated instead.
If the DbList is Ents and the container exists, and str contains a MapId field, then it must be equal to the map_id in the Ent or the server will assert (!!!).
If debugdiff is set, then the debugdiff_str field must be precisely equal to the observed diff to the container after the operation, or the server will assert (!!!).
If the command is CREATE and the DbList is Teamups, Supergroups, Taskforces, or Leagues, and the DbList is being stored in sql, then an sql barrier will be generated (all workers will synchronise).
If the DbList is maps, and the container is not being deleted, then dbserver will ask a launcher to start a MapServer if it does not have a link from a MapServer on this container.
DBCLIENT_CONTAINER_RELAY
packint(1) cmd packint(1) list_id packint(1) cid packint(1) user_cmd packint(1) user_data ... more data that dbserver does not parse
If list_id is not recognised, or no server has that DbList locked, then dbserver will respond with DBSERVER_CONTAINER_RECEIPT:
packint(1) cmd packint(1) list_id packint(1) cid packint(1) user_cmd packint(1) user_data packint(1) error_code string error_msg
where error_code will be CONTAINER_ERR_CANT_COMPLETE.
Otherwise, dbserver will forward the message to the server which has locked that DbList, as DBSERVER_CONTAINER_RELAY:
packint(1) cmd packint(1) list_id packint(1) cid packint(1) user_cmd packint(1) user_data packint(1) lock_id ... everything else from the DBCLIENT_CONTAINER_RELAY is copied here
This is used for MapServer to send messages to RaidServer.
DBCLIENT_CONTAINER_RECEIPT
packint(1) lock_id ... more data that dbserver does not parse
dbserver finds the MapServer connection corresponding to lock_id and proxies the message to that MapServer as DBSERVER_CONTAINER_RECEIPT:
... all the data from the input message
This is used by RaidServer to acknowledge messages from MapServer.
DBCLIENT_CONTAINER_REFLECT
packint(1) list_id packint(1) cmd packint(1) target_count repeated target_count times: packint(1) target_list packint(1) target_cid packint(1) target_dbid packint(1) del packint(1) count repeated count times: packint(1) id optionally repeated count times: string data
data is present only when cmd is not CONTAINER_CMD_DELETE
If cmd is CONTAINER_CMD_CREATE_MODIFY, then dbserver will update each container id with the corresponding data, which is a full copy of the new container value. If cmd is CONTAINER_CMD_DELETE, then dbserver will delete each container id. No locking is checked for these updates.
dbserver now assembles a list of MapServers that these containers will be reflected to. The list is composed by going through the target block, and for each one:
- target_list is a list_id, target_cid is a container ID in that list
- If this target is a group container, and it is loaded, then the current MapServer for every loaded and connected member of that group is included
- If this target is an Ent, then its current MapServer is included
- If target_list is CONTAINER_MAPS and target_cid is -1, every MapServer is included
- If this target is a map, then its current MapServer is included
- If target_list is REFLECT_LOCKID then target_cid is a lock_id, not a container id, and the relevant MapServer is included
For each identified MapServer, dbserver sends it a DBSERVER_CONTAINER_REFLECT, with the same format as the input packet. The target list is changed to be the actual targets, discarding anything that could not be resolved to a MapServer.
DBCLIENT_REQ_CONTAINER_STATUS
packint(1) user_data packint(1) list_id packint(1) count repeated count times: packint(1) id
If id is -1 then it means all active containers. If it is -2 then it means all containers. The concept of active means something different for different container types. Notably, the map for a connected MapServer, and an Ent that is connected to a MapServer, will both be active.
dbserver responds with DBSERVER_CONTAINER_STATUS:
packint(1) user_data packint(1) list_id packint(1) count repeated count times: packint(1) exists string status
where status will be either a DbList-specific status string, or "%3d Active %d locked %d", populated with container id, active status, and locked status.
DBCLIENT_REQUEST_MAP_XFER
packint(1) map_id string mapinfo packint(1) find_best_map packint(1) entity_id bits(1) have_extra_data optional autobits extra_crc optional zipped extra_data
The extra_crc and extra_data fields are present only if have_extra_data is not 0. If this happens, dbserver will respond with an error. This appears to be a removed feature.
If mapinfo is not empty, then it identifies an instanced map. Otherwise, map_id identifies a specific map.
dbserver might override map_id to a different value in some scenarios (relating to Praetorian progression).
If find_best_map is 1, then dbserver will look for a clone of the map and select one based on the number of players currently on it.
If the map is instanced or static, a MapServer will be started for it.
The entity entity_id will be added to the list of entities waiting for this map, and when that MapServer is ready (possibly immediately), dbserver will send DBSERVER_MAP_XFER_READY to the MapServer which send the transfer request:
packint(1) entity_id packint(1) new_map_id
DBCLIENT_MAP_XFER
packint(1) map_id packint(1) count repeated count times: packint(1) entity_id
Each entity in the list is processed separately.
dbserver might override map_id to a different value in some scenarios (relating to Praetorian progression).
If the map_id is the one where the entity is currently present, then dbserver responds with DBSERVER_MAP_XFER_FAIL:
packint(1) entity_id string error_message
Otherwise, the entity container is unlocked, as the originated MapServer is giving up ownership of this entity, and the map transfer process begins.
The entity container is updated with "MapId" set to the map id, and if the map is static, then also "StaticMapId" is set to the map id.
The entity is then locked to the MapServer for the new map id, and a DBSERVER_CONTAINERS is sent to that MapServer with the entity container.
Notifications are sent for the entity.
If the account for this entity has a loyalty status, then DBSERVER_ACCOUNTSERVER_LOYALTY is sent to the new MapServer:
autobits entity_id bits(128) loyalty
DBCLIENT_CONTAINER_ACK
packint(1) list_id packint(1) count repeated count times: packint(1) id packint(1) cookie
If list_id is not CONTAINER_ENTS, the dbserver will treat it as an EntCon type anyway and probably crash (!!!).
MapServer only sends this message in response to DBSERVER_CONTAINERS for entities.
If cookie is 0, the entity will be deleted. If cookie is 1, the entity will be unloaded.
If this is part of a map transfer flow, then dbserver will send a DBSERVER_MAP_XFER_OK to the MapServer. If this is part of a login flow, then dbserver will send DBGAMESERVER_MAP_CONNECT to the game client (possibly via QueueServer). Either way, the message will contain:
packint(1) entity_id packint(1) map_id packint(1) ip packint(1) ip packint(1) udp_port packint(1) tcp_port packint(1) cookie
where ip is the same both times. ip, udp_port, and tcp_port are the connection information for the game client to connect to the new MapServer. cookie is copied from the input message.
After this, the entity is marked as active, and its logging in status is cleared.
DBCLIENT_TEST_MAP_XFER
packint(1) list_id // must be CONTAINER_ENTS packint(1) map_id packint(1) count // not used packint(1) entity_id
dbserver sends DBSERVER_TEST_MAP_XFER to the MapServer where the entity is currently located, with a body identical to the message received.
DBCLIENT_SEND_DOORS
packint(1) map_id packint(1) count repeated count times: string door_info
dbserver finds the map map_id, and marks it as running.
If this map is not static, then dbserver continues as if count is 0 (no doors are sent), regardless of the data sent.
If the map has a base map, then that map is used instead for the remained of this message.
If door info was sent, each one is parsed in turn. dbserver scans existing doors to see if any are in approximately the same location. If none are found, then this door is added to the door containers. Any door containers that are not included in this list are deleted.
If any changes were made to door containers, then every eligible MapServer will be sent the door list; otherwise, only the MapServer which sent this request will be updated (if eligible). A MapServer is eligible for a door update if its map is static, or a supergroup base. A door list is sent in a DBSERVER_SEND_DOORS message:
packint(1) count zipped data
where data is a zipped copy of all the door containers in text format.
DBCLIENT_SAVELISTS
This message has no body and receives no response. dbserver will write all the door containers to a flat file.
DBCLIENT_ADDDEL_MEMBERS
DBCLIENT_PLAYER_DISCONNECT
DBCLIENT_SEND_MSG
DBCLIENT_REQ_GROUP_NAMES
DBCLIENT_REQ_ENT_NAMES
DBCLIENT_CONTAINER_FIND_BY_ELEMENT
DBCLIENT_SHUTDOWN
DBCLIENT_WHO
DBCLIENT_SERVER_STATS_UPDATE
DBCLIENT_RELAY_CMD
DBCLIENT_RELAY_CMD_BYENT
DBCLIENT_RELAY_CMD_TOGROUP
DBCLIENT_REQ_ONLINE_ENTS
DBCLIENT_REQ_ONLINE_ENT_COMMENTS
DBCLIENT_PLAYER_KICKED
DBCLIENT_REQ_CUSTOM_DATA
DBCLIENT_EXECUTE_SQL
DBCLIENT_DISCONNECT_MAPSERVER
DBCLIENT_PLAYER_RENAME
DBCLIENT_PLAYER_CHANGETYPE
DBCLIENT_PLAYER_CHANGESUBTYPE
DBCLIENT_PLAYER_CHANGEPRAETORIANPROGRESS
DBCLIENT_PLAYER_CHANGEINFLUENCETYPE
DBCLIENT_DEPRECATED
DBCLIENT_REQ_ARENA_ADDRESS
DBCLIENT_REQ_SG_ELDEST_ON
DBCLIENT_REQ_SG_CHANNEL_INVITE
DBCLIENT_SGRP_STATSADJ
DBCLIENT_DESTROY_BASE
DBCLIENT_MISSION_PLAYER_COUNT
DBCLIENT_SEND_STATSERVER_CMD
DBCLIENT_REQUEST_SHUTDOWN
DBCLIENT_EMERGENCY_SHUTDOWN
DBCLIENT_OFFLINE_CHAR
DBCLIENT_RESTORE_DELETED_CHAR
DBCLIENT_LIST_DELETED_CHARS
DBCLIENT_BACKUP
DBCLIENT_BACKUP_SEARCH
DBCLIENT_BACKUP_APPLY
DBCLIENT_BACKUP_VIEW
DBCLIENT_REQ_SOME_ONLINE_ENTS
DBCLIENT_OVERRIDE_START_ZONE
DBCLIENT_AUCTION_REQ_INV
DBCLIENT_AUCTION_REQ_HISTINFO
DBCLIENT_AUCTION_XACT_REQ
DBCLIENT_AUCTION_XACT_UPDATE
DBCLIENT_AUCTION_PURGE_FAKE
DBCLIENT_AUCTION_XACT_MULTI_REQ
DBCLIENT_MININGDATA_RELAY
DBCLIENT_SEND_AUCTIONSERVER_CMD
DBCLIENT_ACCOUNTSERVER_CMD
DBCLIENT_ACCOUNTSERVER_SHARDXFER
DBCLIENT_ACCOUNTSERVER_ORDERRENAME
DBCLIENT_GET_PLAYNC_AUTH_KEY
DBCLIENT_ACCOUNTSERVER_CHARCOUNT
DBCLIENT_RENAME_RESPONSE
DBCLIENT_CHECK_NAME_RESPONSE
DBCLIENT_ACCOUNTSERVER_GET_INVENTORY
DBCLIENT_ACCOUNTSERVER_CHANGE_INV
DBCLIENT_ACCOUNTSERVER_UPDATE_EMAIL_STATS
DBCLIENT_ACCOUNTSERVER_CERTIFICATION_TEST
DBCLIENT_ACCOUNTSERVER_CERTIFICATION_GRANT
DBCLIENT_ACCOUNTSERVER_CERTIFICATION_CLAIM
DBCLIENT_ACCOUNTSERVER_CERTIFICATION_REFUND
DBCLIENT_ACCOUNTSERVER_MULTI_GAME_TRANSACTION
DBCLIENT_ACCOUNTSERVER_TRANSACTION_FINISH
DBCLIENT_ACCOUNTSERVER_RECOVER_UNSAVED
DBCLIENT_ACCOUNTSERVER_LOYALTY_CHANGE
DBCLIENT_ACCOUNTSERVER_LOYALTY_EARNED_CHANGE
DBCLIENT_ACCOUNTSERVER_LOYALTY_RESET
DBCLIENT_MISSIONSERVER_COMMAND
DBCLIENT_MISSIONSERVER_PUBLISHARC
DBCLIENT_MISSIONSERVER_SEARCHPAGE
DBCLIENT_MISSIONSERVER_ARCINFO
DBCLIENT_MISSIONSERVER_BANSTATUS
DBCLIENT_MISSIONSERVER_ALLARCS
DBCLIENT_MISSIONSERVER_ARCDATA
DBCLIENT_MISSIONSERVER_ARCDATA_OTHERUSER
DBCLIENT_MISSIONSERVER_INVENTORY
DBCLIENT_MISSIONSERVER_CLAIM_TICKETS
DBCLIENT_MISSIONSERVER_BUY_ITEM
DBCLIENT_ACCOUNTSERVER_ORDERRESPEC
DBCLIENT_DELETE_PLAYER
DBCLIENT_QUEUE_FOR_EVENTS
DBCLIENT_REMOVE_FROM_QUEUE
DBCLIENT_EVENT_READY_ACK
DBCLIENT_EVENT_RESPONSE
DBCLIENT_MAP_ID
DBCLIENT_TURNSTILE_PING
DBCLIENT_DEBUG_SHARD_XFER_OUT
DBCLIENT_DEBUG_SHARD_XFER_BACK
DBCLIENT_GROUP_UPDATE
DBCLIENT_EVENTHISTORY_FIND
DBCLIENT_CLOSE_INSTANCE
DBCLIENT_REJOIN_INSTANCE
DBCLIENT_PLAYER_LEAVE
DBCLIENT_MAP_WEEKLY_TF_ADD_TOKEN
DBCLIENT_MAP_WEEKLY_TF_REMOVE_TOKEN
DBCLIENT_MAP_WEEKLY_TF_SET_EPOCH_TIME
DBCLIENT_TEST_LOGGING
DBCLIENT_INCARNATETRIAL_COMPLETE
DBCLIENT_QUEUE_FOR_SPECIFIC_MISSION_INSTANCE
DBCLIENT_TS_ADD_BAN_DBID
DBCLIENT_MAP_SET_MARTY_STATUS
DBCLIENT_GRANT_CHARSLOT
DBCLIENT_PLAYER_UNLOCK
DBCLIENT_ACCOUNT_ADJUST_SERVER_SLOTS
DBCLIENT_UNLOCK_CHARACTER_RESPONSE
DBCLIENT_DEBUG_SET_VIP
DBSERVER_CONTAINERS
packint(1) user_data packint(1) list_id packint(1) count repeated count times: packint(1) id packint(1) has_error packint(1) is_map_xfer packint(1) is_static_map packint(1) locked packint(1) is_deleting packint(1) demand_loaded packint(1) member_count repeated member_count times: packint(1) member_id string text
If has_error is 1, then the block for this container is replaced by:
packint(1) map_id packint(1) has_error packint(1) error_code
The error_code will be CONTAINER_ERR_DOESNT_EXIST if the container was not found or not loaded, and CONTAINER_ERR_ALREADY_LOCKED if this was an attempt to lock the container and another link already has this container locked. In all cases, errors are on a per-container basis, and the rest of the request will be processed.
This message is used to send containers to the MapServer. The contents of the container is represented in the text string.
user_data will either be 0, or a value sent by the client that requested these containers. It is used by clients to identify responses.
locked will be 1 if the container has now been locked to this link, and 0 if the locking state is unchanged.
If the container is a group, then a member_id list will be sent. Otherwise, member_count will be 0.
is_map_xfer will be 0 unless the container is an Ent.
is_static_map will be 0 unless the container is a Map.
launcher
This service is used for launchers to connect to dbserver and receive instructions on what processes to start. It forms a primitive job scheduler, attempting to start processes on launchers which have spare capacity.
LAUNCHERQUERY_STARTPROCESS
LAUNCHERQUERY_GAMEVERSION
LAUNCHERQUERY_CONTROL
LAUNCHERANSWER_PROCESSES
LAUNCHERANSWER_LOCALONLY
LAUNCHERANSWER_GAMEVERSION
LAUNCHERANSWER_PROCESS_CLOSED
LAUNCHERANSWER_PROCESS_CRASHED
mission
This service is used for the MissionServer to connect to dbserver. Only one MissionServer is allowed to connect.
MISSION_SERVER_MESSAGEENTITY
MISSION_SERVER_SEARCHPAGE
MISSION_SERVER_ARCINFO
MISSION_SERVER_ARCDATA
MISSION_SERVER_SENDPETITION
MISSION_SERVER_COMMENT
MISSION_SERVER_INVENTORY
MISSION_SERVER_CLAIM_TICKETS
MISSION_SERVER_ITEM_BOUGHT
MISSION_SERVER_OVERFLOW_GRANTED
MISSION_SERVER_ALLARCS
MISSION_SERVER_BANSTATUS
MISSION_SERVER_ARCDATA_OTHERUSER
queue
This service is used for the QueueServer to connect to dbserver. Only one connection is allowed.
The use of the QueueServer is optional. When it is used, game clients connect to QueueServer instead of dbserver, and QueueServer proxies all the usual Client-to-dbserver messages.
Proxied messages for clients, sent from dbserver to QueueServer, will be prefixed with these fields to identify the client they are for:
string client_name autobits link_id
Proxies messages from clients, send from QueueServer to dbserver, will be sent in QUEUECLIENT_CLIENTCOMMAND messages.
QUEUESERVER_SVR_CONNECT
QUEUESERVER_SVR_ERROR
QUEUESERVER_SVR_ENQUEUESTATUS
QUEUESERVER_SVR_UPDATE
QUEUESERVER_SVR_REMOVECLIENT
QUEUESERVER_SVR_SET_LOG_LEVELS
QUEUESERVER_SVR_TEST_LOG_LEVELS
QUEUECLIENT_CONNECT
QUEUECLIENT_UPDATE_REQUEST
QUEUECLIENT_CLIENTCOMMAND
QUEUECLIENT_CLIENTPLAY
QUEUECLIENT_REMOVECLIENT
stat
This service is used for StatServer to connect. It is used to identify the StatServer in order to send messages to it. It supports the same messages as the db service, and is not otherwise different.