--- deliantra/server/common/loader.C 2009/11/05 15:43:21 1.137 +++ deliantra/server/common/loader.C 2009/11/09 17:39:05 1.142 @@ -1072,7 +1072,7 @@ if (!arch) { LOG (llevError, "object refering to nonexistant archetype '%s'.\n", f.get_str ()); - arch = archetype::find ("earthwall"); + arch = archetype::find (shstr_earthwall); } assert (arch); //D maybe use exception handling of sorts? @@ -1108,9 +1108,9 @@ return op->parse_kv (f); } -// compare *op against *tmp and output differences +// compare *op against *arch and output differences static void -write_diff (object_freezer &f, object *op, object *tmp) +write_diff (object_freezer &f, object *op, object *arch) { static const keyword resist_save[NROFATTACKS] = { # define def(uc, lc, name, plus, change) KW_resist_ ## lc, @@ -1254,40 +1254,62 @@ * keys that match field names will be overwritten by the loader. */ for (key_value *kv = op->key_values; kv; kv = kv->next) - if (!tmp->key_values || tmp->kv (kv->key) != kv->value) + if (!arch->key_values || arch->kv (kv->key) != kv->value) f.put (kv->key, kv->value); - /* We don't need to worry about the arch's extra fields - they - * will get taken care of the copy_to method. - */ - if (op->uuid) - f.put (KW_uuid, op->uuid.c_str ()); + { + // highly optimised - this is often 25% of all data written + char *cur = f.force (sizeof ("uuid ") + UUID::MAX_LEN + 1); + char *ptr = cur; + + memcpy (ptr, "uuid ", sizeof ("uuid ") - 1); + ptr += sizeof ("uuid ") - 1; + ptr = op->uuid.append (ptr); + *ptr++ = '\n'; -#define CMP_OUT(v) if (expect_false (op->v != tmp->v)) f.put (KW_ ## v, op->v) -#define CMP_OUT2(k,v) if (expect_false (op->v != tmp->v)) f.put (KW_ ## k, op->v) + f.alloc (ptr - cur); + } - if (object *owner = op->owner) - f.put (KW_owner, static_cast(owner->ref ())); +#define CMP_OUT(v) if (expect_false (op->v != arch->v)) f.put (KW_ ## v, op->v) +#define CMP_OUT2(k,v) if (expect_false (op->v != arch->v)) f.put (KW_ ## k, op->v) + + CMP_OUT (x); + CMP_OUT (y); + + CMP_OUT (type); + CMP_OUT (subtype); + CMP_OUT (direction); CMP_OUT (name); CMP_OUT (name_pl); - CMP_OUT (custom_name); + + CMP_OUT (speed); + CMP_OUT (speed_left); + CMP_OUT (title); CMP_OUT (race); - CMP_OUT (skill); CMP_OUT (slaying); + CMP_OUT (skill); + CMP_OUT (tag); + CMP_OUT (custom_name); + + if (object *owner = op->owner) + f.put (KW_owner, static_cast(owner->ref ())); + + // memory, attacked_by, chosen_skill, spellitem, spell, current_weapon, arch not saved + CMP_OUT (other_arch); - if (op->msg != tmp->msg ) f.put (KW_msg , KW_endmsg , op->msg ); - if (op->lore != tmp->lore) f.put (KW_lore, KW_endlore, op->lore); + if (op->msg != arch->msg ) f.put (KW_msg , KW_endmsg , op->msg ); + if (op->lore != arch->lore) f.put (KW_lore, KW_endlore, op->lore); - if (op->face != tmp->face ) f.put (KW_face , op->face ? &faces [op->face ] : 0); - if (op->sound != tmp->sound ) f.put (KW_sound , op->sound ? &faces [op->sound ] : 0); - if (op->sound_destroy != tmp->sound_destroy) f.put (KW_sound_destroy, op->sound_destroy ? &faces [op->sound_destroy] : 0); + if (op->face != arch->face ) f.put (KW_face , op->face ? &faces [op->face ] : 0); + if (op->sound != arch->sound ) f.put (KW_sound , op->sound ? &faces [op->sound ] : 0); + if (op->sound_destroy != arch->sound_destroy) f.put (KW_sound_destroy, op->sound_destroy ? &faces [op->sound_destroy] : 0); - if (op->animation_id != tmp->animation_id) + if (op->animation_id != arch->animation_id) if (op->has_anim ()) f.put (KW_animation, op->anim ().name); else @@ -1313,7 +1335,7 @@ CMP_OUT2 (exp, stats.exp); CMP_OUT (perm_exp); - CMP_OUT (expmul); + //CMP_OUT (expmul); CMP_OUT2 (food, stats.food); CMP_OUT2 (dam, stats.dam); @@ -1321,21 +1343,15 @@ CMP_OUT2 (wc, stats.wc); CMP_OUT2 (ac, stats.ac); - CMP_OUT (x); - CMP_OUT (y); - CMP_OUT (speed); - CMP_OUT (speed_left); CMP_OUT2 (move_state, move_status); CMP_OUT (attack_movement); CMP_OUT (nrof); CMP_OUT (level); - CMP_OUT (direction); - CMP_OUT (type); - CMP_OUT (subtype); CMP_OUT (attacktype); + // using memcmp here seems to be a loss - us gcc vectorising? for (int i = 0; i < NROFATTACKS; i++) - if (expect_false (op->resist[i] != tmp->resist[i])) + if (expect_false (op->resist[i] != arch->resist[i])) f.put (resist_save[i], op->resist[i]); CMP_OUT (path_attuned); @@ -1384,14 +1400,29 @@ CMP_OUT (move_slow); CMP_OUT (move_slow_penalty); - if (op->flag != tmp->flag) - for (int i = 0; i <= NUM_FLAGS; i++) - if (expect_false (flag_names [i] && op->flag [i] != tmp->flag [i])) - f.put (flag_names [i], op->flag [i] ? "1" : "0"); + // obj_original is the only commonly differing flag between archetype + // and object, so special-case it here to be able to skip the loop + object::flags_t diff = op->flag ^ arch->flag; + + if (expect_true (diff.any ())) + { + if (expect_false (diff.reset (FLAG_OBJ_ORIGINAL).any ()) || 1) + { + // some other flags differ, too + for (int i = 0; i < NUM_FLAGS; i++) + if (expect_false (flag_names [i] && op->flag [i] != arch->flag [i])) + f.put (flag_names [i], op->flag [i] ? "1" : "0"); + } + else + { + // only obj_original differs + f.put (flag_names [FLAG_OBJ_ORIGINAL], op->flag [FLAG_OBJ_ORIGINAL] ? "1" : "0"); + } + } - // save body locations + // save body locations. gcc's memcmp does an abysmal job when used for (int i = 0; i < NUM_BODY_LOCATIONS; i++) - if (expect_false (op->slot[i].info != tmp->slot[i].info)) + if (expect_false (op->slot[i].info != arch->slot[i].info)) f.put (body_locations[i].save_name, op->slot[i].info); }