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  LOG(llevInfo, "Finished collecting assets from %s\n", datadir);
149 }
150 
154 static void check_generators(void) {
155  int abort = 0;
156 
157  manager->archetypes()->each([&abort] (const auto& arch) {
158  if (!QUERY_FLAG(&arch->clone, FLAG_GENERATOR))
159  return;
160 
161  if (!QUERY_FLAG(&arch->clone, FLAG_CONTENT_ON_GEN) && arch->clone.other_arch == NULL) {
162  LOG(llevError, "Fatal: %s is generator without content_on_gen but lacks other_arch.\n", arch->name);
163  abort = 1;
164  return;
165  }
166  if (QUERY_FLAG(&arch->clone, FLAG_CONTENT_ON_GEN) && arch->clone.inv == NULL) {
167  LOG(llevError, "Fatal: %s is generator with content_on_gen but lacks inventory.\n", arch->name);
168  abort = 1;
169  return;
170  }
171  });
172 
173  if (abort)
175 }
176 
181 void check_summoned(void) {
182  manager->archetypes()->each([] (const auto& arch) {
183  if (arch->clone.type == SPELL && arch->clone.subtype == SP_SUMMON_GOLEM && arch->clone.other_arch) {
184  if (arch->clone.other_arch->clone.move_type == 0) {
185  LOG(llevError, "Summonable archetype %s [%s] has no move_type defined!\n", arch->clone.other_arch->name, arch->clone.other_arch->clone.name);
186  fatal(SEE_LAST_ERROR);
187  }
188  }
189  });
190 }
191 
198 static void check_spells(void) {
199  int abort = 0;
200 
201  manager->archetypes()->each([&abort] (const auto& arch) {
202  if (arch->clone.type == SPELL && arch->clone.skill) {
203  auto skill = manager->archetypes()->first([&arch] (const archetype *skill) {
204  return skill->clone.type == SKILL && arch->clone.skill == skill->clone.name;
205  });
206  if (!skill) {
207  LOG(llevError, "Spell %s has improper associated skill %s\n", arch->name, arch->clone.skill);
208  abort = 1;
209  }
210  }
211  });
212 
213  for (size_t i = 0; i < sizeof(spell_mapping) / sizeof(spell_mapping[0]); i++) {
215  LOG(llevError, "Unable to find spell mapping %s (%zu)\n", spell_mapping[i], i);
216  abort = 1;
217  }
218  }
219 
220  if (abort)
222 }
223 
229  check_spells();
230  check_summoned();
231  manager->treasures()->each([] (auto list) {
232  if (list->items) {
233  check_treasurelist(list->items, list);
234  }
235  });
236  check_recipes();
237  check_formulae();
238 }
239 
250  if (!strcmp(name, "none"))
251  return NULL;
252  return manager->treasures()->get(name);
253 }
254 
256  return nroftreasures;
257 }
259  return manager->treasures()->count();
260 }
261 
263  return manager->archetypes()->next(current);
264 }
265 
267  return manager->archetypes()->get(name);
268 }
269 
271  return manager->archetypes()->find(name);
272 }
273 
275  return manager->animations()->get(name);
276 }
277 
279  return manager->animations()->find(name);
280 }
281 
282 const Face *find_face(const char *name) {
283  return manager->faces()->get(name);
284 }
285 
286 const Face *try_find_face(const char *name, const Face *error) {
287  auto found = manager->faces()->find(name);
288  if (found)
289  return found;
290  return error;
291 }
292 
293 size_t get_faces_count() {
294  return manager->faces()->count();
295 }
296 
298  manager->faces()->each(*op);
299 }
300 
302  manager->archetypes()->each(*op);
303 }
304 
306  return manager;
307 }
308 
315 const Face *get_face_by_id(uint16_t id) {
316  return manager->faces()->findById(id);
317 }
318 
324 const GeneralMessage *get_message_from_identifier(const char *identifier) {
325  return manager->messages()->find(identifier);
326 }
327 
329  return manager->facesets()->findById(id);
330 }
331 
332 template<class T>
333 static void do_pack(AssetWriter<T> *writer, AssetsCollection<T> *assets, StringBuffer *buf) {
334  assets->each([writer, buf] (T *asset) {
335  writer->write(asset, buf);
336  });
337  delete writer;
338 }
339 
341  ArtifactWriter writer;
343  while (list) {
344  for (const auto item : list->items) {
345  writer.write(item, buf);
346  }
347  list = list->next;
348  }
349 }
350 
352  FormulaeWriter writer;
354  while (list) {
355  writer.write(list, buf);
356  list = list->next;
357  }
358 }
359 
360 static void build_filename(const char *name, const char *prefix, char *dest, size_t max) {
361  auto dot = strrchr(name, '.');
362  // If name has no '.', then just name.prefix
363  if (!dot) {
364  snprintf(dest, max, "%s.%s", name, prefix);
365  return;
366  }
367 
368  // filename for name.111 is name.prefix.111.png
369  memset(dest, 0, max);
370  dot++;
371 
372  snprintf(dest, max, "%.*s%s.%s.png", (int)(dot - name), name, prefix, dot);
373 }
374 
382 static void add_to_tar(mtar_t *tar, void *data, size_t len, const char *filename) {
383  mtar_header_t h;
384  memset(&h, 0, sizeof(h));
385  strncpy(h.name, filename, sizeof(h.name));
386  h.size = len;
387  h.type = MTAR_TREG;
388  h.mode = 0664;
389  h.mtime = time(NULL);
390  /* Build raw header and write */
391  if (MTAR_ESUCCESS != mtar_write_header(tar, &h)) {
392  LOG(llevError, "Failed to write tar header for %s\n", filename);
394  }
395  if (MTAR_ESUCCESS != mtar_write_data(tar, data, len)) {
396  LOG(llevError, "Failed to write tar data for %s\n", filename);
398  }
399 }
400 
405 static void pack_images(mtar_t *tar) {
406  manager->faces()->each([&tar] (const auto face) {
407  manager->facesets()->each([&tar, &face] (const auto fs) {
408  if (!fs->prefix || fs->allocated <= face->number || !fs->faces[face->number].datalen) {
409  return;
410  }
411  char filename[500];
412  build_filename(face->name, fs->prefix, filename, sizeof(filename));
413  add_to_tar(tar, fs->faces[face->number].data, fs->faces[face->number].datalen, filename);
414  });
415  });
416 }
417 
418 void assets_pack(const char *what, const char *filename) {
419 #define MAX_PACK 100
420  char *split[MAX_PACK];
421  char *dup = strdup_local(what);
422  size_t count = split_string(dup, split, MAX_PACK, '+');
423  if (count == 0) {
424  LOG(llevError, "Invalid pack type %s\n", what);
426  }
427  bool isTar = (count > 1) || (strcmp(split[0], "images") == 0);
428  mtar_t tar;
429  if (isTar) {
430  if (MTAR_ESUCCESS != mtar_open(&tar, filename, "w")) {
431  LOG(llevError, "Failed to open tar file %s\n", filename);
433  }
434  }
435 
436  for (size_t t = 0; t < count; t++) {
437  const char *type = split[t];
438  const char *name = nullptr;
439 
441  if (strcmp(type, "treasures") == 0) {
443  name = "crossfire.trs";
444  } else if (strcmp(type, "faces") == 0) {
445  do_pack(new FaceWriter(), manager->faces(), buf);
447  name = "crossfire.face";
448  } else if (strcmp(type, "archs") == 0) {
450  name = "crossfire.arc";
451  } else if (strcmp(type, "messages") == 0) {
453  name = "messages";
454  } else if (strcmp(type, "facesets") == 0) {
456  name = "image_info";
457  } else if (strcmp(type, "artifacts") == 0) {
459  name = "artifacts";
460  } else if (strcmp(type, "formulae") == 0) {
462  name = "formulae";
463  } else if (strcmp(type, "quests") == 0) {
464  do_pack(new QuestWriter(), manager->quests(), buf);
465  name = "crossfire.quests";
466  } else if (strcmp(type, "images") == 0) {
467  pack_images(&tar);
469  continue; // Already stored in tar.
470  } else {
471  LOG(llevError, "Invalid asset type '%s'\n", type);
473  }
474 
475  size_t length = stringbuffer_length(buf);
476  char *data = stringbuffer_finish(buf);
477 
478  if (isTar) {
479  add_to_tar(&tar, data, length, name);
480  } else {
481  FILE *out = fopen(filename, "w+");
482  if (!out) {
483  LOG(llevError, "Failed to open file '%s'\n", filename);
485  }
486  if (fwrite(static_cast<void*>(data), 1, length, out) != length) {
487  LOG(llevError, "Failed to write all data for %s!\n", filename);
488  fclose(out);
490  }
491  fclose(out);
492  }
493  free(data);
494  }
495 
496  if (isTar) {
497  if (MTAR_ESUCCESS != mtar_finalize(&tar)) {
498  LOG(llevError, "Failed to finalize tar file %s\n", filename);
500  }
501  if (MTAR_ESUCCESS != mtar_close(&tar)) {
502  LOG(llevError, "Failed to closed tar file %s\n", filename);
504  }
505  }
506  free(dup);
507 }
508 
510  manager->archetypes()->each([] (archetype *arch) {
511  object *op = &arch->clone;
512  if (op->speed < 0) {
513  op->speed_left = op->speed_left - RANDOM() % 100 / 100.0;
514  op->speed = -op->speed; // Make this always positive
515  }
516  });
517 }
518 
520  quest_definition *quest;
521 
522  quest = quest_get_by_code(code);
523  if (!quest) {
524  LOG(llevError, "quest %s required but not found!\n", code);
525  return NULL;
526  }
527  return quest;
528 }
529 
531  return manager->quests()->find(code);
532 }
533 
539 void quest_for_each(quest_op op, void *user) {
540  manager->quests()->each([&op, &user] (auto q) { op(q, user); });
541 }
542 
543 size_t quests_count(bool includeSystem) {
544  return includeSystem ? manager->quests()->count() : manager->quests()->visibleCount();
545 }
546 
547 void load_assets(void) {
549  assets_end_load();
550 }
551 
553  collector_hooks.push_back(std::make_pair(name, hook));
554 }
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:333
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: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:539
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:301
get_next_archetype
archetype * get_next_archetype(archetype *current)
Definition: assets.cpp:262
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
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:249
find_faceset
face_sets * find_faceset(int id)
Definition: assets.cpp:328
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:154
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:282
buf
StringBuffer * buf
Definition: readable.cpp:1565
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
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:552
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:360
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:543
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:181
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:351
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:509
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:405
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:315
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:530
AssetsManager::facesets
Facesets * facesets()
Get facesets.
Definition: AssetsManager.h:65
check_spells
static void check_spells(void)
This ensures:
Definition: assets.cpp:198
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:324
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
try_find_animation
Animations * try_find_animation(const char *name)
Definition: assets.cpp:278
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:519
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:382
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:258
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:266
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:274
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:297
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:270
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:286
assets_pack
void assets_pack(const char *what, const char *filename)
Pack the specified assets in a file.
Definition: assets.cpp:418
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:340
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:547
get_faces_count
size_t get_faces_count()
Definition: assets.cpp:293
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:255
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:227
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