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 static std::vector<std::pair<std::string, collectorHook>> collector_hooks;
65 void assets_init() {
66  manager = new AssetsManager();
67 }
68 
72 void assets_free() {
73  delete manager;
74  manager = nullptr;
75 }
76 
80 size_t nroftreasures = 0;
81 
93 static void check_treasurelist(treasure *t, const treasurelist *tl) {
94  if (t->item == NULL && t->name == NULL)
95  LOG(llevError, "Treasurelist %s has element with no name or archetype\n", tl->name);
96  if (t->chance >= 100 && t->next_yes && (t->next || t->next_no))
97  LOG(llevError, "Treasurelist %s has element that has 100%% generation, next_yes field as well as next or next_no\n", tl->name);
98  if (t->name && strcmp(t->name, "NONE"))
99  find_treasurelist(t->name);
100  if (t->next)
101  check_treasurelist(t->next, tl);
102  if (t->next_yes)
103  check_treasurelist(t->next_yes, tl);
104  if (t->next_no)
105  check_treasurelist(t->next_no, tl);
106 }
107 
113 void assets_collect(const char* datadir, int what) {
114  LOG(llevInfo, "Starting to collect assets from %s\n", datadir);
115 
116  AssetCollector collector;
117  if (what & ASSETS_TREASURES)
119  if (what & ASSETS_ARCHETYPES)
121  if (what & ASSETS_PNG)
122  collector.addLoader(new PngLoader(manager->faces(), manager->facesets()));
123  if (what & ASSETS_FACESETS)
124  collector.addLoader(new FacesetLoader(manager->facesets()));
125  if (what & ASSETS_FACES)
127  if (what & ASSETS_MESSAGES)
129  if (what & ASSETS_ARTIFACTS) {
131  }
132  if (what & ASSETS_FORMULAE) {
133  collector.addLoader(new WrapperLoader("/formulae", init_formulae));
134  collector.addLoader(new WrapperLoader(".formulae", init_formulae));
135  }
136  if (what & ASSETS_ATTACK_MESSAGES)
137  collector.addLoader(new WrapperLoader("/attackmess", init_attackmess));
138  if (what & ASSETS_QUESTS)
140  if (what & ASSETS_REGIONS)
141  collector.addLoader(new WrapperLoader("regions.reg", init_regions));
142  for (const auto& hook : collector_hooks) {
143  collector.addLoader(new WrapperLoader(hook.first, hook.second));
144  }
145  collector.addLoader(new TarLoader(&collector));
146  collector.collect(datadir);
147 
148  if (what & ASSETS_ARTIFACTS) {
150  }
151 
152  LOG(llevInfo, "Finished collecting assets from %s\n", datadir);
153 }
154 
158 static void check_generators(void) {
159  int abort = 0;
160 
161  manager->archetypes()->each([&abort] (const auto& arch) {
162  if (!QUERY_FLAG(&arch->clone, FLAG_GENERATOR))
163  return;
164 
165  if (!QUERY_FLAG(&arch->clone, FLAG_CONTENT_ON_GEN) && arch->clone.other_arch == NULL) {
166  LOG(llevError, "Fatal: %s is generator without content_on_gen but lacks other_arch.\n", arch->name);
167  abort = 1;
168  return;
169  }
170  if (QUERY_FLAG(&arch->clone, FLAG_CONTENT_ON_GEN) && arch->clone.inv == NULL) {
171  LOG(llevError, "Fatal: %s is generator with content_on_gen but lacks inventory.\n", arch->name);
172  abort = 1;
173  return;
174  }
175  });
176 
177  if (abort)
179 }
180 
185 void check_summoned(void) {
186  manager->archetypes()->each([] (const auto& arch) {
187  if (arch->clone.type == SPELL && arch->clone.subtype == SP_SUMMON_GOLEM && arch->clone.other_arch) {
188  if (arch->clone.other_arch->clone.move_type == 0) {
189  LOG(llevError, "Summonable archetype %s [%s] has no move_type defined!\n", arch->clone.other_arch->name, arch->clone.other_arch->clone.name);
190  fatal(SEE_LAST_ERROR);
191  }
192  }
193  });
194 }
195 
202 static void check_spells(void) {
203  int abort = 0;
204 
205  manager->archetypes()->each([&abort] (const auto& arch) {
206  if (arch->clone.type == SPELL && arch->clone.skill) {
207  auto skill = manager->archetypes()->first([&arch] (const archetype *skill) {
208  return skill->clone.type == SKILL && arch->clone.skill == skill->clone.name;
209  });
210  if (!skill) {
211  LOG(llevError, "Spell %s has improper associated skill %s\n", arch->name, arch->clone.skill);
212  abort = 1;
213  }
214  }
215  });
216 
217  for (size_t i = 0; i < sizeof(spell_mapping) / sizeof(spell_mapping[0]); i++) {
219  LOG(llevError, "Unable to find spell mapping %s (%zu)\n", spell_mapping[i], i);
220  abort = 1;
221  }
222  }
223 
224  if (abort)
226 }
227 
233  check_spells();
234  check_summoned();
235  manager->treasures()->each([] (auto list) {
236  if (list->items) {
237  check_treasurelist(list->items, list);
238  }
239  });
240  check_recipes();
241  check_formulae();
242 }
243 
254  if (!strcmp(name, "none"))
255  return NULL;
256  return manager->treasures()->get(name);
257 }
258 
260  return nroftreasures;
261 }
263  return manager->treasures()->count();
264 }
265 
267  return manager->archetypes()->next(current);
268 }
269 
271  return manager->archetypes()->get(name);
272 }
273 
275  return manager->archetypes()->find(name);
276 }
277 
279  return manager->animations()->get(name);
280 }
281 
283  return manager->animations()->find(name);
284 }
285 
286 const Face *find_face(const char *name) {
287  return manager->faces()->get(name);
288 }
289 
290 const Face *try_find_face(const char *name, const Face *error) {
291  auto found = manager->faces()->find(name);
292  if (found)
293  return found;
294  return error;
295 }
296 
297 size_t get_faces_count() {
298  return manager->faces()->count();
299 }
300 
302  manager->faces()->each(*op);
303 }
304 
306  manager->archetypes()->each(*op);
307 }
308 
310  return manager;
311 }
312 
319 const Face *get_face_by_id(uint16_t id) {
320  return manager->faces()->findById(id);
321 }
322 
328 const GeneralMessage *get_message_from_identifier(const char *identifier) {
329  return manager->messages()->find(identifier);
330 }
331 
333  return manager->facesets()->findById(id);
334 }
335 
336 template<class T>
337 static void do_pack(AssetWriter<T> *writer, AssetsCollection<T> *assets, StringBuffer *buf) {
338  assets->each([writer, buf] (T *asset) {
339  writer->write(asset, buf);
340  });
341  delete writer;
342 }
343 
345  ArtifactWriter writer;
347  while (list) {
348  for (const auto item : list->items) {
349  writer.write(item, buf);
350  }
351  list = list->next;
352  }
353 }
354 
356  FormulaeWriter writer;
358  while (list) {
359  writer.write(list, buf);
360  list = list->next;
361  }
362 }
363 
364 static void build_filename(const char *name, const char *prefix, char *dest, size_t max) {
365  auto dot = strrchr(name, '.');
366  // If name has no '.', then just name.prefix
367  if (!dot) {
368  snprintf(dest, max, "%s.%s", name, prefix);
369  return;
370  }
371 
372  // filename for name.111 is name.prefix.111.png
373  memset(dest, 0, max);
374  dot++;
375 
376  snprintf(dest, max, "%.*s%s.%s.png", (int)(dot - name), name, prefix, dot);
377 }
378 
386 static void add_to_tar(mtar_t *tar, void *data, size_t len, const char *filename) {
387  mtar_header_t h;
388  memset(&h, 0, sizeof(h));
389  strncpy(h.name, filename, sizeof(h.name));
390  h.size = len;
391  h.type = MTAR_TREG;
392  h.mode = 0664;
393  h.mtime = time(NULL);
394  /* Build raw header and write */
395  if (MTAR_ESUCCESS != mtar_write_header(tar, &h)) {
396  LOG(llevError, "Failed to write tar header for %s\n", filename);
398  }
399  if (MTAR_ESUCCESS != mtar_write_data(tar, data, len)) {
400  LOG(llevError, "Failed to write tar data for %s\n", filename);
402  }
403 }
404 
409 static void pack_images(mtar_t *tar) {
410  manager->faces()->each([&tar] (const auto face) {
411  manager->facesets()->each([&tar, &face] (const auto fs) {
412  if (!fs->prefix || fs->allocated <= face->number || !fs->faces[face->number].datalen) {
413  return;
414  }
415  char filename[500];
416  build_filename(face->name, fs->prefix, filename, sizeof(filename));
417  add_to_tar(tar, fs->faces[face->number].data, fs->faces[face->number].datalen, filename);
418  });
419  });
420 }
421 
422 void assets_pack(const char *what, const char *filename) {
423 #define MAX_PACK 100
424  char *split[MAX_PACK];
425  char *dup = strdup_local(what);
426  size_t count = split_string(dup, split, MAX_PACK, '+');
427  if (count == 0) {
428  LOG(llevError, "Invalid pack type %s\n", what);
430  }
431  bool isTar = (count > 1) || (strcmp(split[0], "images") == 0);
432  mtar_t tar;
433  if (isTar) {
434  if (MTAR_ESUCCESS != mtar_open(&tar, filename, "w")) {
435  LOG(llevError, "Failed to open tar file %s\n", filename);
437  }
438  }
439 
440  for (size_t t = 0; t < count; t++) {
441  const char *type = split[t];
442  const char *name = nullptr;
443 
445  if (strcmp(type, "treasures") == 0) {
447  name = "crossfire.trs";
448  } else if (strcmp(type, "faces") == 0) {
449  do_pack(new FaceWriter(), manager->faces(), buf);
451  name = "crossfire.face";
452  } else if (strcmp(type, "archs") == 0) {
454  name = "crossfire.arc";
455  } else if (strcmp(type, "messages") == 0) {
457  name = "messages";
458  } else if (strcmp(type, "facesets") == 0) {
460  name = "image_info";
461  } else if (strcmp(type, "artifacts") == 0) {
463  name = "artifacts";
464  } else if (strcmp(type, "formulae") == 0) {
466  name = "formulae";
467  } else if (strcmp(type, "quests") == 0) {
468  do_pack(new QuestWriter(), manager->quests(), buf);
469  name = "crossfire.quests";
470  } else if (strcmp(type, "images") == 0) {
471  pack_images(&tar);
473  continue; // Already stored in tar.
474  } else {
475  LOG(llevError, "Invalid asset type '%s'\n", type);
477  }
478 
479  size_t length = stringbuffer_length(buf);
480  char *data = stringbuffer_finish(buf);
481 
482  if (isTar) {
483  add_to_tar(&tar, data, length, name);
484  } else {
485  FILE *out = fopen(filename, "w+");
486  if (!out) {
487  LOG(llevError, "Failed to open file '%s'\n", filename);
489  }
490  if (fwrite(static_cast<void*>(data), 1, length, out) != length) {
491  LOG(llevError, "Failed to write all data for %s!\n", filename);
492  fclose(out);
494  }
495  fclose(out);
496  }
497  free(data);
498  }
499 
500  if (isTar) {
501  if (MTAR_ESUCCESS != mtar_finalize(&tar)) {
502  LOG(llevError, "Failed to finalize tar file %s\n", filename);
504  }
505  if (MTAR_ESUCCESS != mtar_close(&tar)) {
506  LOG(llevError, "Failed to closed tar file %s\n", filename);
508  }
509  }
510  free(dup);
511 }
512 
514  manager->archetypes()->each([] (archetype *arch) {
515  object *op = &arch->clone;
516  if (op->speed < 0) {
517  op->speed_left = op->speed_left - RANDOM() % 100 / 100.0;
518  op->speed = -op->speed; // Make this always positive
519  }
520  });
521 }
522 
524  quest_definition *quest;
525 
526  quest = quest_get_by_code(code);
527  if (!quest) {
528  LOG(llevError, "quest %s required but not found!\n", code);
529  return NULL;
530  }
531  return quest;
532 }
533 
535  return manager->quests()->find(code);
536 }
537 
543 void quest_for_each(quest_op op, void *user) {
544  manager->quests()->each([&op, &user] (auto q) { op(q, user); });
545 }
546 
547 size_t quests_count(bool includeSystem) {
548  return includeSystem ? manager->quests()->count() : manager->quests()->visibleCount();
549 }
550 
551 void load_assets(void) {
553  assets_end_load();
554 }
555 
557  collector_hooks.push_back(std::make_pair(name, hook));
558 }
FLAG_CONTENT_ON_GEN
#define FLAG_CONTENT_ON_GEN
Definition: define.h:352
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:337
global.h
settings
struct Settings settings
Global settings.
Definition: init.cpp:139
stringbuffer_length
size_t stringbuffer_length(StringBuffer *sb)
Return the current length of the buffer.
Definition: stringbuffer.cpp:213
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:543
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
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:371
archetypes_for_each
void archetypes_for_each(arch_op op)
Definition: assets.cpp:305
get_next_archetype
archetype * get_next_archetype(archetype *current)
Definition: assets.cpp:266
AssetsManager.h
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
Settings::datadir
const char * datadir
Read only data files.
Definition: global.h:249
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:36435
QuestWriter.h
init_attackmess
void init_attackmess(BufferReader *reader, const char *filename)
Initializes the attack messages.
Definition: init.cpp:563
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:253
find_faceset
face_sets * find_faceset(int id)
Definition: assets.cpp:332
face_op
void(* face_op)(const Face *)
Definition: assets.h:46
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:333
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:72
check_generators
static void check_generators(void)
Check all generators have the other_arch set or something in inventory.
Definition: assets.cpp:158
check_treasurelist
static void check_treasurelist(treasure *t, const treasurelist *tl)
Checks if a treasure if valid.
Definition: assets.cpp:93
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:286
buf
StringBuffer * buf
Definition: readable.cpp:1565
getManager
AssetsManager * getManager()
Definition: assets.cpp:309
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
assets_add_collector_hook
void assets_add_collector_hook(const char *name, collectorHook hook)
Definition: assets.cpp:556
collector_hooks
static std::vector< std::pair< std::string, collectorHook > > collector_hooks
Collect hooks, as (filename, function) pairs.
Definition: assets.cpp:60
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:364
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
collectorHook
std::function< void(BufferReader *, const char *)> collectorHook
Definition: assets.h:35
quests_count
size_t quests_count(bool includeSystem)
Definition: assets.cpp:547
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:185
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:355
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:513
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:409
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:319
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:534
AssetsManager::facesets
Facesets * facesets()
Get facesets.
Definition: AssetsManager.h:65
check_spells
static void check_spells(void)
This ensures:
Definition: assets.cpp:202
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:328
ASSETS_REGIONS
#define ASSETS_REGIONS
Definition: assets.h:31
ASSETS_ALL
#define ASSETS_ALL
Definition: assets.h:32
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
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
try_find_animation
Animations * try_find_animation(const char *name)
Definition: assets.cpp:282
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:523
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:386
QuestLoader.h
MTAR_TREG
@ MTAR_TREG
Definition: microtar.h:29
llevInfo
@ llevInfo
Information.
Definition: logger.h:12
FLAG_GENERATOR
#define FLAG_GENERATOR
Will generate type ob->stats.food.
Definition: define.h:235
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:262
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:270
FormulaeWriter
Definition: FormulaeWriter.h:19
PngLoader.h
assets.h
ASSETS_PNG
#define ASSETS_PNG
Definition: assets.h:25
artifact_post_load
void artifact_post_load()
Definition: artifact.cpp:680
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:278
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:301
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:274
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:290
assets_pack
void assets_pack(const char *what, const char *filename)
Pack the specified assets in a file.
Definition: assets.cpp:422
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:344
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:113
nroftreasures
size_t nroftreasures
Number of treasure items, for malloc info.
Definition: assets.cpp:80
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:45
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
load_assets
void load_assets(void)
Definition: assets.cpp:551
get_faces_count
size_t get_faces_count()
Definition: assets.cpp:297
face_sets
Information about one face set.
Definition: image.h:17
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:65
assets_number_of_treasures
size_t assets_number_of_treasures()
Definition: assets.cpp:259
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:231
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