 |
Crossfire Server, Trunk
1.75.0
|
Go to the documentation of this file.
41 #include <unordered_map>
93 if (
t->item == NULL &&
t->name == NULL)
94 LOG(
llevError,
"Treasurelist %s has element with no name or archetype\n", tl->
name);
95 if (
t->chance >= 100 &&
t->next_yes && (
t->next ||
t->next_no))
96 LOG(
llevError,
"Treasurelist %s has element that has 100%% generation, next_yes field as well as next or next_no\n", tl->
name);
97 if (
t->name && strcmp(
t->name,
"NONE"))
161 LOG(llevError,
"Fatal: %s is generator without content_on_gen but lacks other_arch.\n", arch->name);
166 LOG(llevError,
"Fatal: %s is generator with content_on_gen but lacks inventory.\n", arch->name);
182 if (arch->clone.type ==
SPELL && arch->clone.subtype ==
SP_SUMMON_GOLEM && arch->clone.other_arch) {
183 if (arch->clone.other_arch->clone.move_type == 0) {
184 LOG(llevError,
"Summonable archetype %s [%s] has no move_type defined!\n", arch->clone.other_arch->name, arch->clone.other_arch->clone.name);
185 fatal(SEE_LAST_ERROR);
201 if (arch->clone.type ==
SPELL && arch->clone.skill) {
202 auto skill = manager->archetypes()->first([&arch] (const archetype *skill) {
203 return skill->clone.type == SKILL && arch->clone.skill == skill->clone.name;
206 LOG(
llevError,
"Spell %s has improper associated skill %s\n", arch->name, arch->clone.skill);
232 check_treasurelist(list->items, list);
249 if (!strcmp(
name,
"none"))
333 assets->
each([writer,
buf] (T *asset) {
343 for (
const auto item :
list->items) {
360 auto dot = strrchr(
name,
'.');
363 snprintf(dest, max,
"%s.%s",
name, prefix);
368 memset(dest, 0, max);
371 snprintf(dest, max,
"%.*s%s.%s.png", (
int)(dot -
name),
name, prefix, dot);
383 memset(&h, 0,
sizeof(h));
384 strncpy(h.
name, filename,
sizeof(h.
name));
391 LOG(
llevError,
"Failed to write tar header for %s\n", filename);
395 LOG(
llevError,
"Failed to write tar data for %s\n", filename);
407 if (!fs->prefix || fs->allocated <=
face->number || !fs->faces[
face->number].datalen) {
412 add_to_tar(tar, fs->faces[
face->number].data, fs->faces[
face->number].datalen, filename);
426 bool isTar = (count > 1) || (strcmp(
split[0],
"images") == 0);
430 LOG(
llevError,
"Failed to open tar file %s\n", filename);
435 for (
size_t t = 0;
t < count;
t++) {
437 const char *
name =
nullptr;
440 if (strcmp(
type,
"treasures") == 0) {
442 name =
"crossfire.trs";
443 }
else if (strcmp(
type,
"faces") == 0) {
446 name =
"crossfire.face";
447 }
else if (strcmp(
type,
"archs") == 0) {
449 name =
"crossfire.arc";
450 }
else if (strcmp(
type,
"messages") == 0) {
453 }
else if (strcmp(
type,
"facesets") == 0) {
456 }
else if (strcmp(
type,
"artifacts") == 0) {
459 }
else if (strcmp(
type,
"formulae") == 0) {
462 }
else if (strcmp(
type,
"quests") == 0) {
464 name =
"crossfire.quests";
465 }
else if (strcmp(
type,
"images") == 0) {
480 FILE *out = fopen(filename,
"w+");
485 if (fwrite(
static_cast<void*
>(
data), 1, length, out) != length) {
486 LOG(
llevError,
"Failed to write all data for %s!\n", filename);
497 LOG(
llevError,
"Failed to finalize tar file %s\n", filename);
501 LOG(
llevError,
"Failed to closed tar file %s\n", filename);
510 object *op = &arch->
clone;
512 op->speed_left = op->speed_left - RANDOM() % 100 / 100.0;
513 op->speed = -op->speed;
size_t count() const
Get the number of assets.
New face structure - this enforces the notion that data is face by face only - you can not change the...
static void do_pack(AssetWriter< T > *writer, AssetsCollection< T > *assets, StringBuffer *buf)
struct Settings settings
Server settings.
size_t stringbuffer_length(StringBuffer *sb)
Return the current length of the buffer.
One general message, from the lib/messages file.
recipelist * get_formulalist(int i)
Gets a formula list by ingredients count.
@ llevError
Error, serious thing.
void quest_for_each(quest_op op, void *user)
Iterate over all quests.
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Messages * messages()
Get messages.
#define FLAG_GENERATOR
Will generate type ob->stats.food.
void(* quest_op)(const quest_definition *, void *)
#define QUERY_FLAG(xyz, p)
void archetypes_for_each(arch_op op)
archetype * get_next_archetype(archetype *current)
#define FLAG_CONTENT_ON_GEN
void init_regions(BufferReader *reader, const char *filename)
Reads/parses the region file, and copies into a linked list of region structs.
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
float speed
Frequency of object 'moves' relative to server tick rate.
void init_attackmess(BufferReader *reader, const char *filename)
Initializes the attack messages.
const Face * findById(uint16_t id)
AllAnimations * animations()
Get animations.
treasurelist * find_treasurelist(const char *name)
Search for the given treasurelist by name.
face_sets * find_faceset(int id)
void(* face_op)(const Face *)
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
class AssetsTracker * assets_tracker
If not NULL, called each time an asset is defined.
size_t visibleCount() const
void assets_free()
Free all assets-related memory.
static void check_generators(void)
Check all generators have the other_arch set or something in inventory.
static void check_treasurelist(treasure *t, const treasurelist *tl)
Checks if a treasure if valid.
bool check_recipes()
Ensure that all recipes have a valid artifact, and that archetypes are correct.
const Face * find_face(const char *name)
AssetsManager * getManager()
T * find(const Key &name)
Get a named asset if it exists.
void collect(const std::string &directory)
Recurse in the specified directory, finding all files and calling loaders to process them.
Plugin animator file specs[Config] name
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
int mtar_close(mtar_t *tar)
int mtar_open(mtar_t *tar, const char *filename, const char *mode)
List of recipes with a certain number of ingredients.
Collection of assets identified by a unique name.
Treasures * treasures()
Get treasures.
treasurelist represents one logical group of items to be generated together.
size_t split_string(char *str, char *array[], size_t array_size, char sep)
Splits a string delimited by passed in sep value into characters into an array of strings.
object clone
An object from which to do object_copy()
bool check_formulae(void)
Check if formula don't have the same index.
#define ASSETS_ARCHETYPES
sstring name
Usually monster-name/combination.
static void build_filename(const char *name, const char *prefix, char *dest, size_t max)
int mtar_finalize(mtar_t *tar)
int mtar_write_data(mtar_t *tar, const void *data, unsigned size)
Quests * quests()
Get quests.
Faces * faces()
Get faces.
size_t quests_count(bool includeSystem)
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn t
void check_summoned(void)
This checks all summonable items for move_type and other things.
face_sets * findById(int id)
Attempt to find a faceset from its identifier.
static void pack_formulae(StringBuffer *buf)
This represents all archetypes for one particular object type.
void assets_finish_archetypes_for_play()
void addLoader(AssetLoader *loader)
Register a loader to be called on found files.
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
static void pack_images(mtar_t *tar)
Pack all client-side images in the specified tar file.
T * get(const Key &name)
Get a named asset.
void each(std::function< void(T *)> op)
Apply a function to each asset.
const Face * get_face_by_id(uint16_t id)
Get a face from its unique identifier.
quest_definition * quest_get_by_code(sstring code)
Find a quest from its code if it exists.
Facesets * facesets()
Get facesets.
static void check_spells(void)
This ensures:
#define ASSETS_ATTACK_MESSAGES
T * next(T *current)
Allow browsing assets in a list-like manner.
const GeneralMessage * get_message_from_identifier(const char *identifier)
Find the message from its identifier.
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Archetypes * archetypes()
Get archetypes.
int mtar_write_header(mtar_t *tar, const mtar_header_t *h)
Animations * try_find_animation(const char *name)
A buffer that will be expanded as content is added to it.
quest_definition * quest_find_by_code(sstring code)
Find a quest from its code, logging if no matching quest.
static void add_to_tar(mtar_t *tar, void *data, size_t len, const char *filename)
Add a file to a .tar file.
void stringbuffer_delete(StringBuffer *sb)
Totally delete a string buffer.
virtual void write(const T *asset, StringBuffer *buf)=0
Write the specified asset to the StringBuffer.
const typedef char * sstring
size_t assets_number_of_treasurelists()
This represents one animation.
Assets collector, recursing in directories and calling loaders on found files.
Definition of an in-game quest.
archetype * find_archetype(const char *name)
const char *const spell_mapping[SPELL_MAPPINGS]
This table is only necessary to convert objects that existed before the spell object conversion to th...
Loader calling a function for files ending with a specific string.
Animations * find_animation(const char *name)
void init_formulae(BufferReader *reader, const char *filename)
Builds up the lists of formula from the file in the libdir.
artifactlist * first_artifactlist
First artifact.
====Textual A command containing textual data has data fields separated by one ASCII space character. word::A sequence of ASCII characters that does not contain the space or nul character. This is to distinguish it from the _string_, which may contain space characters. Not to be confused with a machine word. int::A _word_ containing the textual representation of an integer. Not to be confused with any of the binary integers in the following section. Otherwise known as the "string value of integer data". Must be parsed, e.g. using `atoi()` to get the actual integer value. string::A sequence of ASCII characters. This must only appear at the end of a command, since spaces are used to separate fields of a textual message.=====Binary All multi-byte integers are transmitted in network byte order(MSB first). int8::1-byte(8-bit) integer int16::2-byte(16-bit) integer int32::4-byte(32-bit) integer lstring::A length-prefixed string, which consists of an `int8` followed by that many bytes of the actual string. This is used to transmit a string(that may contain spaces) in the middle of binary data. l2string::Like _lstring_, but is prefixed with an `int16` to support longer strings Implementation Notes ~~~~~~~~~~~~~~~~~~~~ - Typical implementations read two bytes to determine the length of the subsequent read for the actual message, then read and parse the data from each message according to the commands described below. To send a message, the sender builds the message in a buffer, counts the length of the message, sends the length, and finally sends the actual message. TIP:Incorrectly transmitting or receiving the `length` field can lead to apparent "no response" issues as the client or server blocks to read the entire length of the message. - Since the protocol is highly interactive, it may be useful to set `TCP_NODELAY` on both the client and server. - If you are using a language with a buffered output stream, remember to flush the stream after a complete message. - If the connection is lost(which will also happen if the output buffer overflowing), the player is saved and the server cleans up. This does open up some abuses, but there is no perfect solution here. - The server only reads data from the socket if the player has an action. This isn 't really good, since many of the commands below might not be actual commands for the player. The alternative is to look at the data, and if it is a player command and there isn 't time, store it away to be processed later. But this increases complexity, in that the server must start buffering the commands. Fortunately, for now, there are few such client commands. Commands -------- In the documentation below, `S->C` represents a message to the client from the server, and `C->S` represents a message to the server from the client. Commands are documented in a brief format like:C->S:version< csval >[scval[vinfo]] Fields are enclosed like `< this >`. Optional fields are denoted like `[this]`. Spaces that appear in the command are literal, i.e. the<< _version > > command above uses spaces to separate its fields, but the command below does not:C->S:accountlogin< name >< password > As described in<< _messages > >, if a command contains data, then the command is separated from the data by a literal space. Many of the commands below refer to 'object tags'. Whenever the server creates an object, it creates a unique tag for that object(starting at 1 when the server is first run, and ever increasing.) Tags are unique, but are not consistent between runs. Thus, the client can not store tags when it exits and hope to re-use them when it joins the server at a later time - tags are only valid for the current connection. The protocol commands are broken into various sections which based somewhat on what the commands are for(ie, item related commands, map commands, image commands, etc.) In this way, all the commands related to similar functionality is in the same place. Initialization ~~~~~~~~~~~~~~ version ^^^^^^^ C->S:version< csval >[scval[vinfo]] S->C:version< csval >[scval[vinfo]] Used by the client and server to exchange which version of the Crossfire protocol they understand. Neither send this in response to the other - they should both send this shortly after a connection is established. csval::int, version level of C->S communications scval::int, version level of S->C communications vinfo::string, that is purely for informative that general client/server info(ie, javaclient, x11client, winclient, sinix server, etc). It is purely of interest of server admins who can see what type of clients people are using.=====Version ID If a new command is added to the protocol in the C->S direction, then the version number in csval will get increased. Likewise, the same is true for the scval. The version are currently integers, in the form ABCD. A=1, and will likely for quite a while. This will only really change if needed from rollover of B. B represents major protocol changes - if B mismatches, the clients will be totally unusable. Such an example would be change of map or item sending commands(either new commands or new format.) C represents more minor but still significant changes - clients might still work together, but some features that used to work may now fail due to the mismatch. An example may be a change in the meaning of some field in some command - providing the field is the same size, it still should be decoded properly, but the meaning won 't be processed properly. D represents very minor changes or new commands. Things should work no worse if D does not match, however if they do match, some new features might be included. An example of the would be the C->S mark command to mark items. Server not understanding this just means that the server can not process it, and will ignore it.=====Handling As far as the client is concerned, its _scval_ must be at least equal to the server, and its _csval_ should not be newer than the server. The server does not care about the version command it receives right now - all it currently does is log mismatches. In theory, the server should keep track of what the client has, and adjust the commands it sends respectively in the S->C direction. The server is resilant enough that it won 't crash with a version mismatch(however, client may end up sending commands that the server just ignores). It is really up to the client to enforce versioning and quit if the versions don 't match. NOTE:Since all packets have the length as the first 2 bytes, all that either the client or server needs to be able to do is look at the first string and see if it understands it. If not, it knows how many bytes it can skip. As such, exact version matches should not be necessary for proper operation - however, both the client and server needs to be coded to handle such cases.=====History _scval_ and _vinfo_ were added in version 1020. Before then, there was only one version sent in the version command. NOTE:For the most part, this has been obsoleted by the setup command which always return status and whether it understood the command or not. However there are still some cases where using this versioning is useful - an example it the addition of the requestinfo/replyinfo commands - the client wants to wait for acknowledge of all the replyinfo commands it has issued before sending the addme command. However, if the server doesn 't understand these options, the client will never get a response. With the versioning, the client can look at the version and know if it should wait for a response or if the server will never send back. setup ^^^^^ C->S, S->C:setup< option1 >< value1 >< option2 >< value2 > ... Sent by the client to request protocol option changes. This can be at any point during the life of a connection, but usually sent at least once right after the<< _version > > command. The server responds with a message in the same format confirming what configuration options were set. The server only sends a setup command in response to one from the client. The sc_version should be updated in the server if commands have been obsoleted such that old clients may not be able to play. option::word, name of configuration option value::word, value of configuration option. May need further parsing according to the setup options below=====Setup Options There are really 2 set of setup commands here:. Those that control preferences of the client(how big is the map, what faceset to use, etc). . Those that describe capabilities of the client(client supports this protocol command or that) .Setup Options[options="autowidth,header"]|===========================|Command|Description|beat|Ask the server to enable heartbeat support. When heartbeat is enabled, the client must send the server a command every three seconds. If no commands need to be sent, use the `beat` no-op command. Clients that do not contact the server within the interval are assumed to have a temporary connection failure.|bot(0/1 value)|If set to 1, the client will not be considered a player when updating information to the metaserver. This is to avoid having a server with many bots appear more crowded than others.|darkness(0/1 value)|If set to 1(default), the server will send darkness information in the map protocol commands. If 0, the server will not include darkness, thus saving a minor amount of bandwidth. Since the client is free to ignore the darkness information, this does not allow the client to cheat. In the case of the old 'map' protocol command, turning darkness off will result in the masking faces not getting sent to the client.|extended_stats(0/1 value)|If set to 1, the server will send the CS_STAT_RACE_xxx and CS_STAT_BASE_xxx values too, so the client can display various status related to statistics. Default is 0.|facecache(0/1)|Determines if the client is caching images(1) or wants the images sent to it without caching them(0). Default is 0. This replaces the setfacemode command.|faceset(8 bit)|Faceset the client wishes to use. If the faceset is not valid, the server returns the faceset the client will be using(default 0).|loginmethod(8 bit)|Client sends this to server to note login support. This is basically used as a subset of the csversion/scversion to find out what level of login support the server and client support. Current defined values:0:no advanced support - only legacy login method 1:account based login(described more below) 2:new character creation support This list may grow - for example, advanced character creation could become a feature.|map2cmd:(1)|This indicates client support for the map2 protocol command. See the map2 protocol details above for the main differences. Obsolete:This is the only supported mode now, but many clients use it as a sanity check for protocol versions, so the server still replies. It doesn 't do anything with the data|mapsize(int x) X(int y)|Sets the map size to x X y. Note the spaces here are only for clarity - there should be no spaces when actually sent(it should be 11x11 or 25x25). The default map size unless changed is 11x11. The minimum map size the server will allow is 9x9(no technical reason this could be smaller, but I don 't think the game would be smaller). The maximum map size supported in the current protocol is 63x63. However, each server can have its maximum map size sent to most any value. If the client sends an invalid mapsize command or a mapsize of 0x0, the server will respond with a mapsize that is the maximum size the server supports. Thus, if the client wants to know the maximum map size, it can just do a 'mapsize 0x0' or 'mapsize' and it will get the maximum size back. The server will constrain the provided mapsize x &y to the configured minumum and maximums. For example, if the maximum map size is 25x25, the minimum map size is 9x9, and the client sends a 31x7 mapsize request, the mapsize will be set to 25x9 and the server will send back a mapsize 25x9 setup command. When the values are valid, the server will send back a mapsize XxY setup command. Note that this is from its parsed values, so it may not match stringwise with what the client sent, but will match 0 wise. For example, the client may send a 'mapsize 025X025' command, in which case the server will respond with a 'mapsize 25x25' command - the data is functionally the same. The server will send an updated map view when this command is sent.|notifications(int value)|Value indicating what notifications the client accepts. It is incremental, a value means "all notifications till this level". The following levels are supported:1:quest-related notifications("addquest" and "updquest") 2:knowledge-related notifications("addknowledge") 3:character status flags(overloaded, blind,...)|num_look_objects(int value)|The maximum number of objects shown in the ground view. If more objects are present, fake objects are created for selecting the previous/next group of items. Defaults to 50 if not set. The server may adjust the given value to a suitable one data
void faces_for_each(face_op op)
archetype * try_find_archetype(const char *name)
const Face * try_find_face(const char *name, const Face *error)
void assets_pack(const char *what, const char *filename)
Pack the specified assets in a file.
Represents all assets of the game.
static void pack_artifacts(StringBuffer *buf)
Crossfire Architecture the general intention is to enhance the enjoyability and playability of CF In this code
void assets_collect(const char *datadir, int what)
Collect all assets from the specified directory and all its subdirectories.
size_t nroftreasures
Number of treasure items, for malloc info.
static std::vector< std::string > split(const std::string &field, const std::string &by)
virtual void write(const artifact *item, StringBuffer *buf)
Write the specified asset to the StringBuffer.
void(* arch_op)(archetype *)
treasure is one element in a linked list, which together consist of a complete treasure-list.
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for but you habe then to change the pathes in the VC settings Go in Settings C and Settings Link and change the optional include and libs path to the new python installation path o except the maps ! You must download a map package and install them the share folder Its must look like doubleclick on crossfire32 dsw There are projects in your libcross lib and plugin_python You need to compile all Easiest way is to select the plugin_python ReleaseLog as active this will compile all others too Then in Visual C press< F7 > to compile If you don t have an appropriate compiler you can try to get the the VC copies the crossfire32 exe in the crossfire folder and the plugin_python dll in the crossfire share plugins folder we will remove it when we get time for it o Last showing lots of weird write to the Crossfire mailing list
Information about one face set.
std::vector< std::pair< std::string, collectorHook > > collector_hooks
Collect hooks, as (filename, function) pairs.
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn though Notes on Specific and settings file datadir Usually usr share crossfire Contains data that the server does not need to modify while such as the etc A default install will pack the and treasurelist definitions into a single or trs file each
static AssetsManager * manager
Abstract writer of an asset to a StringBuffer.
void assets_init()
Init assets-related variables.
size_t assets_number_of_treasures()
void assets_end_load()
Called after collect is complete, to check various things.
the server will also quite happily load unpacked files as long as they have the right file which is convenient if you want to edit your maps and archetypes live It also contains a few like which have hard coded names and are not identified by extension localdir Usually var crossfire Modern systems probably want var lib crossfire instead Contains data that the server does need to live apartment high the contents of player edited etc mapdir Usually maps Always relative to datadir or depending on context Relative to the datadir
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn though Notes on Specific and settings file datadir Usually usr share crossfire Contains data that the server does not need to modify while such as the etc A default install will pack the and treasurelist definitions into a single or trs file and the graphics into a face(metadata) and .tar(bitmaps) file