Crossfire Server, Trunk  1.75.0
assets.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 2020 the Crossfire Development Team
5  *
6  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
7  * welcome to redistribute it under certain conditions. For details, please
8  * see COPYING and LICENSE.
9  *
10  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
11  */
12 
18 #ifndef WIN32 /* ---win32 exclude headers */
19 #include <sys/stat.h>
20 #include "autoconf.h"
21 #endif
22 
23 #include "global.h"
24 #include "compat.h"
25 #include "assets.h"
26 #include "AssetsManager.h"
27 #include "AssetCollector.h"
28 #include "TreasureLoader.h"
29 #include "ArchetypeLoader.h"
30 #include "PngLoader.h"
31 #include "FacesetLoader.h"
32 #include "FaceLoader.h"
33 #include "WrapperLoader.h"
34 #include "MessageLoader.h"
35 #include "QuestLoader.h"
36 #include "ArtifactLoader.h"
37 #include "Faces.h"
38 #include <string.h>
39 
40 #include <set>
41 #include <unordered_map>
42 #include <memory>
43 
44 #include "AssetWriter.h"
45 #include "TreasureWriter.h"
46 #include "FaceWriter.h"
47 #include "AnimationWriter.h"
48 #include "ArchetypeWriter.h"
49 #include "MessageWriter.h"
50 #include "image.h"
51 #include "FacesetWriter.h"
52 #include "ArtifactWriter.h"
53 #include "FormulaeWriter.h"
54 #include "QuestWriter.h"
55 
56 #include "microtar.h"
57 #include "TarLoader.h"
58 
59 static AssetsManager *manager = nullptr;
60 
64 void assets_init() {
65  manager = new AssetsManager();
66 }
67 
71 void assets_free() {
72  delete manager;
73  manager = nullptr;
74 }
75 
79 size_t nroftreasures = 0;
80 
92 static void check_treasurelist(treasure *t, const treasurelist *tl) {
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"))
98  find_treasurelist(t->name);
99  if (t->next)
100  check_treasurelist(t->next, tl);
101  if (t->next_yes)
102  check_treasurelist(t->next_yes, tl);
103  if (t->next_no)
104  check_treasurelist(t->next_no, tl);
105 }
106 
112 void assets_collect(const char* datadir, int what) {
113  LOG(llevInfo, "Starting to collect assets from %s\n", datadir);
114 
115  AssetCollector collector;
116  if (what & ASSETS_TREASURES)
118  if (what & ASSETS_ARCHETYPES)
120  if (what & ASSETS_PNG)
121  collector.addLoader(new PngLoader(manager->faces(), manager->facesets()));
122  if (what & ASSETS_FACESETS)
123  collector.addLoader(new FacesetLoader(manager->facesets()));
124  if (what & ASSETS_FACES)
126  if (what & ASSETS_MESSAGES)
128  if (what & ASSETS_ARTIFACTS) {
130  }
131  if (what & ASSETS_FORMULAE) {
132  collector.addLoader(new WrapperLoader("/formulae", init_formulae));
133  collector.addLoader(new WrapperLoader(".formulae", init_formulae));
134  }
135  if (what & ASSETS_ATTACK_MESSAGES)
136  collector.addLoader(new WrapperLoader("/attackmess", init_attackmess));
137  if (what & ASSETS_QUESTS)
139  if (what & ASSETS_REGIONS)
140  collector.addLoader(new WrapperLoader("regions.reg", init_regions));
141  for (const auto& hook : settings.collector_hooks) {
142  collector.addLoader(new WrapperLoader(hook.first, hook.second));
143  }
144  collector.addLoader(new TarLoader(&collector));
145  collector.collect(datadir);
146 
147  LOG(llevInfo, "Finished collecting assets from %s\n", datadir);
148 }
149 
153 static void check_generators(void) {
154  int abort = 0;
155 
156  manager->archetypes()->each([&abort] (const auto& arch) {
157  if (!QUERY_FLAG(&arch->clone, FLAG_GENERATOR))
158  return;
159 
160  if (!QUERY_FLAG(&arch->clone, FLAG_CONTENT_ON_GEN) && arch->clone.other_arch == NULL) {
161  LOG(llevError, "Fatal: %s is generator without content_on_gen but lacks other_arch.\n", arch->name);
162  abort = 1;
163  return;
164  }
165  if (QUERY_FLAG(&arch->clone, FLAG_CONTENT_ON_GEN) && arch->clone.inv == NULL) {
166  LOG(llevError, "Fatal: %s is generator with content_on_gen but lacks inventory.\n", arch->name);
167  abort = 1;
168  return;
169  }
170  });
171 
172  if (abort)
174 }
175 
180 void check_summoned(void) {
181  manager->archetypes()->each([] (const auto& arch) {
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);
186  }
187  }
188  });
189 }
190 
197 static void check_spells(void) {
198  int abort = 0;
199 
200  manager->archetypes()->each([&abort] (const auto& arch) {
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;
204  });
205  if (!skill) {
206  LOG(llevError, "Spell %s has improper associated skill %s\n", arch->name, arch->clone.skill);
207  abort = 1;
208  }
209  }
210  });
211 
212  for (size_t i = 0; i < sizeof(spell_mapping) / sizeof(spell_mapping[0]); i++) {
214  LOG(llevError, "Unable to find spell mapping %s (%zu)\n", spell_mapping[i], i);
215  abort = 1;
216  }
217  }
218 
219  if (abort)
221 }
222 
228  check_spells();
229  check_summoned();
230  manager->treasures()->each([] (auto list) {
231  if (list->items) {
232  check_treasurelist(list->items, list);
233  }
234  });
235  check_recipes();
236  check_formulae();
237 }
238 
249  if (!strcmp(name, "none"))
250  return NULL;
251  return manager->treasures()->get(name);
252 }
253 
255  return nroftreasures;
256 }
258  return manager->treasures()->count();
259 }
260 
262  return manager->archetypes()->next(current);
263 }
264 
266  return manager->archetypes()->get(name);
267 }
268 
270  return manager->archetypes()->find(name);
271 }
272 
274  return manager->animations()->get(name);
275 }
276 
278  return manager->animations()->find(name);
279 }
280 
281 const Face *find_face(const char *name) {
282  return manager->faces()->get(name);
283 }
284 
285 const Face *try_find_face(const char *name, const Face *error) {
286  auto found = manager->faces()->find(name);
287  if (found)
288  return found;
289  return error;
290 }
291 
292 size_t get_faces_count() {
293  return manager->faces()->count();
294 }
295 
297  manager->faces()->each(*op);
298 }
299 
301  manager->archetypes()->each(*op);
302 }
303 
305  return manager;
306 }
307 
314 const Face *get_face_by_id(uint16_t id) {
315  return manager->faces()->findById(id);
316 }
317 
323 const GeneralMessage *get_message_from_identifier(const char *identifier) {
324  return manager->messages()->find(identifier);
325 }
326 
328  return manager->facesets()->findById(id);
329 }
330 
331 template<class T>
332 static void do_pack(AssetWriter<T> *writer, AssetsCollection<T> *assets, StringBuffer *buf) {
333  assets->each([writer, buf] (T *asset) {
334  writer->write(asset, buf);
335  });
336  delete writer;
337 }
338 
340  ArtifactWriter writer;
342  while (list) {
343  for (const auto item : list->items) {
344  writer.write(item, buf);
345  }
346  list = list->next;
347  }
348 }
349 
351  FormulaeWriter writer;
353  while (list) {
354  writer.write(list, buf);
355  list = list->next;
356  }
357 }
358 
359 static void build_filename(const char *name, const char *prefix, char *dest, size_t max) {
360  auto dot = strrchr(name, '.');
361  // If name has no '.', then just name.prefix
362  if (!dot) {
363  snprintf(dest, max, "%s.%s", name, prefix);
364  return;
365  }
366 
367  // filename for name.111 is name.prefix.111.png
368  memset(dest, 0, max);
369  dot++;
370 
371  snprintf(dest, max, "%.*s%s.%s.png", (int)(dot - name), name, prefix, dot);
372 }
373 
381 static void add_to_tar(mtar_t *tar, void *data, size_t len, const char *filename) {
382  mtar_header_t h;
383  memset(&h, 0, sizeof(h));
384  strncpy(h.name, filename, sizeof(h.name));
385  h.size = len;
386  h.type = MTAR_TREG;
387  h.mode = 0664;
388  h.mtime = time(NULL);
389  /* Build raw header and write */
390  if (MTAR_ESUCCESS != mtar_write_header(tar, &h)) {
391  LOG(llevError, "Failed to write tar header for %s\n", filename);
393  }
394  if (MTAR_ESUCCESS != mtar_write_data(tar, data, len)) {
395  LOG(llevError, "Failed to write tar data for %s\n", filename);
397  }
398 }
399 
404 static void pack_images(mtar_t *tar) {
405  manager->faces()->each([&tar] (const auto face) {
406  manager->facesets()->each([&tar, &face] (const auto fs) {
407  if (!fs->prefix || fs->allocated <= face->number || !fs->faces[face->number].datalen) {
408  return;
409  }
410  char filename[500];
411  build_filename(face->name, fs->prefix, filename, sizeof(filename));
412  add_to_tar(tar, fs->faces[face->number].data, fs->faces[face->number].datalen, filename);
413  });
414  });
415 }
416 
417 void assets_pack(const char *what, const char *filename) {
418 #define MAX_PACK 100
419  char *split[MAX_PACK];
420  char *dup = strdup_local(what);
421  size_t count = split_string(dup, split, MAX_PACK, '+');
422  if (count == 0) {
423  LOG(llevError, "Invalid pack type %s\n", what);
425  }
426  bool isTar = (count > 1) || (strcmp(split[0], "images") == 0);
427  mtar_t tar;
428  if (isTar) {
429  if (MTAR_ESUCCESS != mtar_open(&tar, filename, "w")) {
430  LOG(llevError, "Failed to open tar file %s\n", filename);
432  }
433  }
434 
435  for (size_t t = 0; t < count; t++) {
436  const char *type = split[t];
437  const char *name = nullptr;
438 
440  if (strcmp(type, "treasures") == 0) {
442  name = "crossfire.trs";
443  } else if (strcmp(type, "faces") == 0) {
444  do_pack(new FaceWriter(), manager->faces(), buf);
446  name = "crossfire.face";
447  } else if (strcmp(type, "archs") == 0) {
449  name = "crossfire.arc";
450  } else if (strcmp(type, "messages") == 0) {
452  name = "messages";
453  } else if (strcmp(type, "facesets") == 0) {
455  name = "image_info";
456  } else if (strcmp(type, "artifacts") == 0) {
458  name = "artifacts";
459  } else if (strcmp(type, "formulae") == 0) {
461  name = "formulae";
462  } else if (strcmp(type, "quests") == 0) {
463  do_pack(new QuestWriter(), manager->quests(), buf);
464  name = "crossfire.quests";
465  } else if (strcmp(type, "images") == 0) {
466  pack_images(&tar);
468  continue; // Already stored in tar.
469  } else {
470  LOG(llevError, "Invalid asset type '%s'\n", type);
472  }
473 
474  size_t length = stringbuffer_length(buf);
475  char *data = stringbuffer_finish(buf);
476 
477  if (isTar) {
478  add_to_tar(&tar, data, length, name);
479  } else {
480  FILE *out = fopen(filename, "w+");
481  if (!out) {
482  LOG(llevError, "Failed to open file '%s'\n", filename);
484  }
485  if (fwrite(static_cast<void*>(data), 1, length, out) != length) {
486  LOG(llevError, "Failed to write all data for %s!\n", filename);
487  fclose(out);
489  }
490  fclose(out);
491  }
492  free(data);
493  }
494 
495  if (isTar) {
496  if (MTAR_ESUCCESS != mtar_finalize(&tar)) {
497  LOG(llevError, "Failed to finalize tar file %s\n", filename);
499  }
500  if (MTAR_ESUCCESS != mtar_close(&tar)) {
501  LOG(llevError, "Failed to closed tar file %s\n", filename);
503  }
504  }
505  free(dup);
506 }
507 
509  manager->archetypes()->each([] (archetype *arch) {
510  object *op = &arch->clone;
511  if (op->speed < 0) {
512  op->speed_left = op->speed_left - RANDOM() % 100 / 100.0;
513  op->speed = -op->speed; // Make this always positive
514  }
515  });
516 }
517 
519  quest_definition *quest;
520 
521  quest = quest_get_by_code(code);
522  if (!quest) {
523  LOG(llevError, "quest %s required but not found!\n", code);
524  return NULL;
525  }
526  return quest;
527 }
528 
530  return manager->quests()->find(code);
531 }
532 
538 void quest_for_each(quest_op op, void *user) {
539  manager->quests()->each([&op, &user] (auto q) { op(q, user); });
540 }
541 
542 size_t quests_count(bool includeSystem) {
543  return includeSystem ? manager->quests()->count() : manager->quests()->visibleCount();
544 }
AssetsCollection::count
size_t count() const
Get the number of assets.
Definition: AssetsCollection.h:80
Face
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
do_pack
static void do_pack(AssetWriter< T > *writer, AssetsCollection< T > *assets, StringBuffer *buf)
Definition: assets.cpp:332
global.h
settings
struct Settings settings
Server settings.
Definition: init.cpp:139
stringbuffer_length
size_t stringbuffer_length(StringBuffer *sb)
Return the current length of the buffer.
Definition: stringbuffer.cpp:218
GeneralMessage
One general message, from the lib/messages file.
Definition: book.h:44
get_formulalist
recipelist * get_formulalist(int i)
Gets a formula list by ingredients count.
Definition: recipe.cpp:98
FormulaeWriter.h
AssetWriter.h
ArchetypeWriter.h
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
ASSETS_FACESETS
#define ASSETS_FACESETS
Definition: assets.h:23
quest_for_each
void quest_for_each(quest_op op, void *user)
Iterate over all quests.
Definition: assets.cpp:538
ArchetypeWriter
Definition: ArchetypeWriter.h:19
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
AssetsManager::messages
Messages * messages()
Get messages.
Definition: AssetsManager.h:59
FLAG_GENERATOR
#define FLAG_GENERATOR
Will generate type ob->stats.food.
Definition: define.h:248
strdup_local
#define strdup_local
Definition: compat.h:29
quest_op
void(* quest_op)(const quest_definition *, void *)
Definition: quest.h:50
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
archetypes_for_each
void archetypes_for_each(arch_op op)
Definition: assets.cpp:300
get_next_archetype
archetype * get_next_archetype(archetype *current)
Definition: assets.cpp:261
AssetsManager.h
FLAG_CONTENT_ON_GEN
#define FLAG_CONTENT_ON_GEN
Definition: define.h:365
mtar_header_t::type
unsigned type
Definition: microtar.h:43
init_regions
void init_regions(BufferReader *reader, const char *filename)
Reads/parses the region file, and copies into a linked list of region structs.
Definition: region.cpp:310
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:57
object::speed
float speed
Frequency of object 'moves' relative to server tick rate.
Definition: object.h:337
if
if(!(yy_init))
Definition: loader.cpp:36428
QuestWriter.h
init_attackmess
void init_attackmess(BufferReader *reader, const char *filename)
Initializes the attack messages.
Definition: init.cpp:570
mtar_t
Definition: microtar.h:51
MessageWriter.h
Faces::findById
const Face * findById(uint16_t id)
Definition: Faces.cpp:44
ASSETS_MESSAGES
#define ASSETS_MESSAGES
Definition: assets.h:26
mtar_header_t::size
unsigned size
Definition: microtar.h:41
AssetsManager::animations
AllAnimations * animations()
Get animations.
Definition: AssetsManager.h:49
find_treasurelist
treasurelist * find_treasurelist(const char *name)
Search for the given treasurelist by name.
Definition: assets.cpp:248
find_faceset
face_sets * find_faceset(int id)
Definition: assets.cpp:327
face_op
void(* face_op)(const Face *)
Definition: assets.h:43
ArtifactWriter.h
FaceWriter
Definition: FaceWriter.h:19
time
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
Definition: arch-handbook.txt:206
FaceWriter.h
TreasureLoader
Definition: TreasureLoader.h:25
MAX_PACK
#define MAX_PACK
Settings::assets_tracker
class AssetsTracker * assets_tracker
If not NULL, called each time an asset is defined.
Definition: global.h:336
TreasureLoader.h
mtar_header_t::mtime
unsigned mtime
Definition: microtar.h:42
SEE_LAST_ERROR
@ SEE_LAST_ERROR
Definition: define.h:52
Quests::visibleCount
size_t visibleCount() const
Definition: Quests.h:24
assets_free
void assets_free()
Free all assets-related memory.
Definition: assets.cpp:71
check_generators
static void check_generators(void)
Check all generators have the other_arch set or something in inventory.
Definition: assets.cpp:153
check_treasurelist
static void check_treasurelist(treasure *t, const treasurelist *tl)
Checks if a treasure if valid.
Definition: assets.cpp:92
check_recipes
bool check_recipes()
Ensure that all recipes have a valid artifact, and that archetypes are correct.
Definition: recipe.cpp:147
find_face
const Face * find_face(const char *name)
Definition: assets.cpp:281
buf
StringBuffer * buf
Definition: readable.cpp:1565
getManager
AssetsManager * getManager()
Definition: assets.cpp:304
AssetsCollection::find
T * find(const Key &name)
Get a named asset if it exists.
Definition: AssetsCollection.h:108
AssetCollector::collect
void collect(const std::string &directory)
Recurse in the specified directory, finding all files and calling loaders to process them.
Definition: AssetCollector.cpp:54
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
AnimationWriter
Definition: AnimationWriter.h:19
FacesetLoader
Definition: FacesetLoader.h:21
ASSETS_QUESTS
#define ASSETS_QUESTS
Definition: assets.h:30
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.cpp:76
mtar_header_t::name
char name[100]
Definition: microtar.h:44
mtar_close
int mtar_close(mtar_t *tar)
Definition: microtar.cpp:211
AnimationWriter.h
mtar_open
int mtar_open(mtar_t *tar, const char *filename, const char *mode)
Definition: microtar.cpp:177
QuestLoader
Definition: QuestLoader.h:24
recipelist
List of recipes with a certain number of ingredients.
Definition: recipe.h:37
AssetsCollection
Collection of assets identified by a unique name.
Definition: AssetsCollection.h:55
AssetsManager::treasures
Treasures * treasures()
Get treasures.
Definition: AssetsManager.h:54
ASSETS_FACES
#define ASSETS_FACES
Definition: assets.h:21
ArchetypeLoader
Definition: ArchetypeLoader.h:22
microtar.h
treasurelist
treasurelist represents one logical group of items to be generated together.
Definition: treasure.h:85
split_string
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.
Definition: utils.cpp:473
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
check_formulae
bool check_formulae(void)
Check if formula don't have the same index.
Definition: recipe.cpp:292
ASSETS_ARCHETYPES
#define ASSETS_ARCHETYPES
Definition: assets.h:20
treasurelist::name
sstring name
Usually monster-name/combination.
Definition: treasure.h:86
build_filename
static void build_filename(const char *name, const char *prefix, char *dest, size_t max)
Definition: assets.cpp:359
mtar_finalize
int mtar_finalize(mtar_t *tar)
Definition: microtar.cpp:373
mtar_write_data
int mtar_write_data(mtar_t *tar, const void *data, unsigned size)
Definition: microtar.cpp:357
FacesetWriter
Definition: FacesetWriter.h:20
compat.h
FormulaeWriter::write
virtual void write(const recipelist *list, StringBuffer *buf)
Write the specified asset to the StringBuffer.
Definition: FormulaeWriter.cpp:52
AssetsManager::quests
Quests * quests()
Get quests.
Definition: AssetsManager.h:71
AssetsManager::faces
Faces * faces()
Get faces.
Definition: AssetsManager.h:39
quests_count
size_t quests_count(bool includeSystem)
Definition: assets.cpp:542
t
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn t
Definition: server-directories.txt:28
check_summoned
void check_summoned(void)
This checks all summonable items for move_type and other things.
Definition: assets.cpp:180
Facesets::findById
face_sets * findById(int id)
Attempt to find a faceset from its identifier.
Definition: Facesets.cpp:35
pack_formulae
static void pack_formulae(StringBuffer *buf)
Definition: assets.cpp:350
ArtifactWriter
Definition: ArtifactWriter.h:19
FacesetWriter.h
artifactlist
This represents all archetypes for one particular object type.
Definition: artifact.h:24
QuestWriter
Definition: QuestWriter.h:19
assets_finish_archetypes_for_play
void assets_finish_archetypes_for_play()
Definition: assets.cpp:508
AssetCollector::addLoader
void addLoader(AssetLoader *loader)
Register a loader to be called on found files.
Definition: AssetCollector.h:39
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
pack_images
static void pack_images(mtar_t *tar)
Pack all client-side images in the specified tar file.
Definition: assets.cpp:404
AssetsCollection::get
T * get(const Key &name)
Get a named asset.
Definition: AssetsCollection.h:89
AssetsCollection::each
void each(std::function< void(T *)> op)
Apply a function to each asset.
Definition: AssetsCollection.h:158
get_face_by_id
const Face * get_face_by_id(uint16_t id)
Get a face from its unique identifier.
Definition: assets.cpp:314
mtar_header_t
Definition: microtar.h:38
quest_get_by_code
quest_definition * quest_get_by_code(sstring code)
Find a quest from its code if it exists.
Definition: assets.cpp:529
AssetsManager::facesets
Facesets * facesets()
Get facesets.
Definition: AssetsManager.h:65
check_spells
static void check_spells(void)
This ensures:
Definition: assets.cpp:197
ASSETS_ATTACK_MESSAGES
#define ASSETS_ATTACK_MESSAGES
Definition: assets.h:29
AssetsCollection::next
T * next(T *current)
Allow browsing assets in a list-like manner.
Definition: AssetsCollection.h:139
image.h
get_message_from_identifier
const GeneralMessage * get_message_from_identifier(const char *identifier)
Find the message from its identifier.
Definition: assets.cpp:323
ASSETS_REGIONS
#define ASSETS_REGIONS
Definition: assets.h:31
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
ASSETS_ARTIFACTS
#define ASSETS_ARTIFACTS
Definition: assets.h:27
AssetsManager::archetypes
Archetypes * archetypes()
Get archetypes.
Definition: AssetsManager.h:44
ASSETS_TREASURES
#define ASSETS_TREASURES
Definition: assets.h:24
mtar_write_header
int mtar_write_header(mtar_t *tar, const mtar_header_t *h)
Definition: microtar.cpp:323
try_find_animation
Animations * try_find_animation(const char *name)
Definition: assets.cpp:277
StringBuffer
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.cpp:25
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
mtar_header_t::mode
unsigned mode
Definition: microtar.h:39
quest_find_by_code
quest_definition * quest_find_by_code(sstring code)
Find a quest from its code, logging if no matching quest.
Definition: assets.cpp:518
MessageLoader
Definition: MessageLoader.h:22
add_to_tar
static void add_to_tar(mtar_t *tar, void *data, size_t len, const char *filename)
Add a file to a .tar file.
Definition: assets.cpp:381
QuestLoader.h
MTAR_TREG
@ MTAR_TREG
Definition: microtar.h:29
llevInfo
@ llevInfo
Information.
Definition: logger.h:12
MessageWriter
Definition: MessageWriter.h:19
ArtifactLoader
Definition: ArtifactLoader.h:18
stringbuffer_delete
void stringbuffer_delete(StringBuffer *sb)
Totally delete a string buffer.
Definition: stringbuffer.cpp:71
Faces.h
AssetWriter::write
virtual void write(const T *asset, StringBuffer *buf)=0
Write the specified asset to the StringBuffer.
WrapperLoader.h
sstring
const typedef char * sstring
Definition: sstring.h:2
assets_number_of_treasurelists
size_t assets_number_of_treasurelists()
Definition: assets.cpp:257
Animations
This represents one animation.
Definition: face.h:25
AssetCollector
Assets collector, recursing in directories and calling loaders on found files.
Definition: AssetCollector.h:23
MTAR_ESUCCESS
@ MTAR_ESUCCESS
Definition: microtar.h:17
quest_definition
Definition of an in-game quest.
Definition: quest.h:37
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:265
FormulaeWriter
Definition: FormulaeWriter.h:19
spell_mapping
const char *const spell_mapping[SPELL_MAPPINGS]
This table is only necessary to convert objects that existed before the spell object conversion to th...
Definition: object.cpp:74
PngLoader.h
assets.h
ASSETS_PNG
#define ASSETS_PNG
Definition: assets.h:25
WrapperLoader
Loader calling a function for files ending with a specific string.
Definition: WrapperLoader.h:23
find_animation
Animations * find_animation(const char *name)
Definition: assets.cpp:273
FaceLoader.h
TreasureWriter
Definition: TreasureWriter.h:19
init_formulae
void init_formulae(BufferReader *reader, const char *filename)
Builds up the lists of formula from the file in the libdir.
Definition: recipe.cpp:166
first_artifactlist
artifactlist * first_artifactlist
First artifact.
Definition: init.cpp:109
data
====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
Definition: protocol.txt:379
ArchetypeLoader.h
FaceLoader
Definition: FaceLoader.h:23
faces_for_each
void faces_for_each(face_op op)
Definition: assets.cpp:296
TarLoader
Definition: TarLoader.h:8
skill
skill
Definition: arch-handbook.txt:585
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:269
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:285
assets_pack
void assets_pack(const char *what, const char *filename)
Pack the specified assets in a file.
Definition: assets.cpp:417
SP_SUMMON_GOLEM
#define SP_SUMMON_GOLEM
Definition: spells.h:86
AssetsManager
Represents all assets of the game.
Definition: AssetsManager.h:28
pack_artifacts
static void pack_artifacts(StringBuffer *buf)
Definition: assets.cpp:339
code
Crossfire Architecture the general intention is to enhance the enjoyability and playability of CF In this code
Definition: arch-handbook.txt:14
ArtifactLoader.h
TreasureWriter.h
MessageLoader.h
assets_collect
void assets_collect(const char *datadir, int what)
Collect all assets from the specified directory and all its subdirectories.
Definition: assets.cpp:112
nroftreasures
size_t nroftreasures
Number of treasure items, for malloc info.
Definition: assets.cpp:79
split
static std::vector< std::string > split(const std::string &field, const std::string &by)
Definition: mapper.cpp:2734
TarLoader.h
ArtifactWriter::write
virtual void write(const artifact *item, StringBuffer *buf)
Write the specified asset to the StringBuffer.
Definition: ArtifactWriter.cpp:18
arch_op
void(* arch_op)(archetype *)
Definition: assets.h:42
treasure
treasure is one element in a linked list, which together consist of a complete treasure-list.
Definition: treasure.h:63
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
Definition: INSTALL_WIN32.txt:50
PngLoader
Definition: PngLoader.h:22
get_faces_count
size_t get_faces_count()
Definition: assets.cpp:292
face_sets
Information about one face set.
Definition: image.h:17
Settings::collector_hooks
std::vector< std::pair< std::string, collectorHook > > collector_hooks
Collect hooks, as (filename, function) pairs.
Definition: global.h:334
SPELL
@ SPELL
Definition: object.h:219
each
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
Definition: server-directories.txt:48
manager
static AssetsManager * manager
Definition: assets.cpp:59
AssetWriter
Abstract writer of an asset to a StringBuffer.
Definition: AssetWriter.h:22
FacesetLoader.h
AssetCollector.h
assets_init
void assets_init()
Init assets-related variables.
Definition: assets.cpp:64
assets_number_of_treasures
size_t assets_number_of_treasures()
Definition: assets.cpp:254
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
autoconf.h
assets_end_load
void assets_end_load()
Called after collect is complete, to check various things.
Definition: assets.cpp:226
datadir
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
Definition: server-directories.txt:69
face
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
ASSETS_FORMULAE
#define ASSETS_FORMULAE
Definition: assets.h:28