Add a RPC call to retrieve unit info.

For performance reasons, material flag arrays are changed to use ints,
with enum item name mappings retrievable via a different RPC call.
develop
Alexander Gavrilov 2012-03-17 17:41:56 +04:00
parent 15ccfbb086
commit 368b92f81f
10 changed files with 340 additions and 28 deletions

@ -331,7 +331,7 @@ void ServerConnection::threadFn(void *arg)
// Cleanup
if (fn)
{
fn->reset(out_size > 32768 || in_size > 32768);
fn->reset(out_size > 128*1024 || in_size > 32*1024);
}
}

@ -50,8 +50,13 @@ POSSIBILITY OF SUCH DAMAGE.
#include "MiscUtils.h"
#include "modules/Materials.h"
#include "modules/Translation.h"
#include "modules/Units.h"
#include "DataDefs.h"
#include "df/unit.h"
#include "df/unit_soul.h"
#include "df/unit_skill.h"
#include "df/material.h"
#include "df/matter_state.h"
#include "df/inorganic_raw.h"
@ -80,15 +85,47 @@ void DFHack::strVectorToRepeatedField(RepeatedPtrField<std::string> *pf,
*pf->Add() = vec[i];
}
void DFHack::describeEnum(RepeatedPtrField<EnumItemName> *pf, int base,
int size, const char* const *names)
{
for (int i = 0; i < size; i++)
{
auto item = pf->Add();
item->set_value(base+i);
const char *key = names[i];
if (key)
item->set_name(key);
}
}
void DFHack::describeBitfield(RepeatedPtrField<EnumItemName> *pf,
int size, const bitfield_item_info *items)
{
for (int i = 0; i < size; i++)
{
auto item = pf->Add();
item->set_value(i);
const char *key = items[i].name;
if (key)
item->set_name(key);
if (items[i].size > 1)
{
item->set_bit_size(items[i].size);
i += items[i].size-1;
}
}
}
void DFHack::describeMaterial(BasicMaterialInfo *info, df::material *mat,
const BasicMaterialInfoMask *mask)
{
info->set_token(mat->id);
if (mask && mask->flags())
flagarray_to_string(info->mutable_flags(), mat->flags);
flagarray_to_ints(info->mutable_flags(), mat->flags);
info->set_name_prefix(mat->prefix);
if (!mat->prefix.empty())
info->set_name_prefix(mat->prefix);
if (!mask || mask->states_size() == 0)
{
@ -143,14 +180,14 @@ void DFHack::describeMaterial(BasicMaterialInfo *info, const MaterialInfo &mat,
case MaterialInfo::Inorganic:
info->set_token(mat.inorganic->id);
if (mask && mask->flags())
flagarray_to_string(info->mutable_inorganic_flags(), mat.inorganic->flags);
flagarray_to_ints(info->mutable_inorganic_flags(), mat.inorganic->flags);
break;
case MaterialInfo::Creature:
info->set_subtype(mat.subtype);
if (mat.figure)
{
info->set_hfig_id(mat.index);
info->set_histfig_id(mat.index);
info->set_creature_id(mat.figure->race);
}
else
@ -163,6 +200,89 @@ void DFHack::describeMaterial(BasicMaterialInfo *info, const MaterialInfo &mat,
}
}
void DFHack::describeName(NameInfo *info, df::language_name *name)
{
if (!name->first_name.empty())
info->set_first_name(name->first_name);
if (!name->nickname.empty())
info->set_nickname(name->nickname);
if (name->language >= 0)
info->set_language_id(name->language);
std::string lname = Translation::TranslateName(name, false, true);
if (!lname.empty())
info->set_last_name(lname);
lname = Translation::TranslateName(name, true, true);
if (!lname.empty())
info->set_english_name(lname);
}
void DFHack::describeUnit(BasicUnitInfo *info, df::unit *unit,
const BasicUnitInfoMask *mask)
{
info->set_unit_id(unit->id);
info->set_pos_x(unit->pos.x);
info->set_pos_y(unit->pos.y);
info->set_pos_z(unit->pos.z);
auto name = Units::GetVisibleName(unit);
if (name->has_name)
describeName(info->mutable_name(), name);
info->set_flags1(unit->flags1.whole);
info->set_flags2(unit->flags2.whole);
info->set_flags3(unit->flags3.whole);
info->set_race(unit->race);
info->set_caste(unit->caste);
if (unit->sex >= 0)
info->set_gender(unit->sex);
if (unit->civ_id >= 0)
info->set_civ_id(unit->civ_id);
if (unit->hist_figure_id >= 0)
info->set_histfig_id(unit->hist_figure_id);
if (mask && mask->labors())
{
for (int i = 0; i < sizeof(unit->status.labors)/sizeof(bool); i++)
if (unit->status.labors[i])
info->add_labors(i);
}
if (mask && mask->skills() && unit->status.current_soul)
{
auto &vec = unit->status.current_soul->skills;
for (size_t i = 0; i < vec.size(); i++)
{
auto skill = vec[i];
auto item = info->add_skills();
item->set_id(skill->id);
item->set_level(skill->rating);
item->set_experience(skill->experience);
}
}
}
static command_result ListEnums(color_ostream &stream,
const EmptyMessage *, ListEnumsRes *out)
{
#define ENUM(name) describe_enum<df::name>(out->mutable_##name());
#define BITFIELD(name) describe_bitfield<df::name>(out->mutable_##name());
ENUM(material_flags);
ENUM(inorganic_flags);
BITFIELD(unit_flags1);
BITFIELD(unit_flags2);
BITFIELD(unit_flags3);
ENUM(unit_labor);
ENUM(job_skill);
#undef ENUM
#undef BITFIELD
}
static void listMaterial(ListMaterialsRes *out, int type, int index, const BasicMaterialInfoMask *mask)
{
MaterialInfo info(type, index);
@ -223,6 +343,42 @@ static command_result ListMaterials(color_ostream &stream,
return out->value_size() ? CR_OK : CR_NOT_FOUND;
}
static command_result ListUnits(color_ostream &stream,
const ListUnitsRq *in, ListUnitsRes *out)
{
CoreSuspender suspend;
auto mask = in->has_mask() ? &in->mask() : NULL;
if (in->id_list_size() > 0)
{
for (int i = 0; i < in->id_list_size(); i++)
{
auto unit = df::unit::find(in->id_list(i));
if (unit)
describeUnit(out->add_value(), unit, mask);
}
}
else
{
auto &vec = df::unit::get_vector();
for (size_t i = 0; i < vec.size(); i++)
{
auto unit = vec[i];
if (in->has_race() && unit->race != in->race())
continue;
if (in->civ_id() && unit->civ_id != in->civ_id())
continue;
describeUnit(out->add_value(), unit, mask);
}
}
return out->value_size() ? CR_OK : CR_NOT_FOUND;
}
CoreService::CoreService() {
suspend_depth = 0;
@ -234,7 +390,9 @@ CoreService::CoreService() {
addMethod("CoreSuspend", &CoreService::CoreSuspend);
addMethod("CoreResume", &CoreService::CoreResume);
addFunction("ListEnums", ListEnums);
addFunction("ListMaterials", ListMaterials);
addFunction("ListUnits", ListUnits);
}
CoreService::~CoreService()

@ -117,7 +117,7 @@ namespace DFHack
bits[byte] ^= bit;
}
}
bool is_set (T index)
bool is_set (T index) const
{
uint32_t byte = index / 8;
if(byte < size)

@ -34,12 +34,15 @@ distribution.
namespace df
{
struct material;
struct unit;
struct language_name;
}
namespace DFHack
{
class MaterialInfo;
using google::protobuf::RepeatedField;
using google::protobuf::RepeatedPtrField;
DFHACK_EXPORT void strVectorToRepeatedField(RepeatedPtrField<std::string> *pf,
@ -65,6 +68,40 @@ namespace DFHack
strVectorToRepeatedField(pf, tmp);
}
/**
* Represent flagarray bits as a repeated int field.
*/
template<class T>
void flagarray_to_ints(RepeatedField<google::protobuf::int32> *pf, const BitArray<T> &val) {
for (int i = 0; i < val.size*8; i++)
if (val.is_set(T(i)))
pf->Add(i);
}
using dfproto::EnumItemName;
DFHACK_EXPORT void describeEnum(RepeatedPtrField<EnumItemName> *pf, int base,
int size, const char* const *names);
template<class T>
void describe_enum(RepeatedPtrField<EnumItemName> *pf)
{
typedef df::enum_traits<T> traits;
int base = traits::first_item;
int size = traits::last_item - base + 1;
describeEnum(pf, base, size, traits::key_table);
}
DFHACK_EXPORT void describeBitfield(RepeatedPtrField<EnumItemName> *pf,
int size, const bitfield_item_info *items);
template<class T>
void describe_bitfield(RepeatedPtrField<EnumItemName> *pf)
{
typedef df::bitfield_traits<T> traits;
describeBitfield(pf, traits::bit_count, traits::bits);
}
/////
using dfproto::BasicMaterialInfo;
@ -75,6 +112,16 @@ namespace DFHack
DFHACK_EXPORT void describeMaterial(BasicMaterialInfo *info, const MaterialInfo &mat,
const BasicMaterialInfoMask *mask = NULL);
using dfproto::NameInfo;
DFHACK_EXPORT void describeName(NameInfo *info, df::language_name *name);
using dfproto::BasicUnitInfo;
using dfproto::BasicUnitInfoMask;
DFHACK_EXPORT void describeUnit(BasicUnitInfo *info, df::unit *unit,
const BasicUnitInfoMask *mask = NULL);
/////
class CoreService : public RPCService {

@ -51,7 +51,8 @@ DFHACK_EXPORT bool readName(t_name & name, df::language_name * address);
DFHACK_EXPORT bool copyName(df::language_name * address, df::language_name * target);
// translate a name using the loaded dictionaries
DFHACK_EXPORT std::string TranslateName (const df::language_name * name, bool inEnglish = true);
DFHACK_EXPORT std::string TranslateName (const df::language_name * name, bool inEnglish = true,
bool onlyLastPart = false);
}
}
#endif

@ -192,6 +192,8 @@ DFHACK_EXPORT void CopyNameTo(df::unit *creature, df::language_name * target);
DFHACK_EXPORT bool RemoveOwnedItemByIdx(const uint32_t index, int32_t id);
DFHACK_EXPORT bool RemoveOwnedItemByPtr(df::unit * unit, int32_t id);
DFHACK_EXPORT df::language_name *GetVisibleName(df::unit *unit);
}
}
#endif

@ -91,29 +91,31 @@ void addNameWord (string &out, const string &word)
out.append(upper);
}
string Translation::TranslateName(const df::language_name * name, bool inEnglish)
string Translation::TranslateName(const df::language_name * name, bool inEnglish, bool onlyLastPart)
{
string out;
string word;
if (!name->first_name.empty())
addNameWord(out, name->first_name);
if (!onlyLastPart) {
if (!name->first_name.empty())
addNameWord(out, name->first_name);
if (!name->nickname.empty())
{
word = "`" + name->nickname + "'";
switch (d_init ? d_init->nickname_dwarf : d_init_nickname::CENTRALIZE)
if (!name->nickname.empty())
{
case d_init_nickname::REPLACE_ALL:
out = word;
return out;
case d_init_nickname::REPLACE_FIRST:
out = "";
break;
case d_init_nickname::CENTRALIZE:
break;
word = "`" + name->nickname + "'";
switch (d_init ? d_init->nickname_dwarf : d_init_nickname::CENTRALIZE)
{
case d_init_nickname::REPLACE_ALL:
out = word;
return out;
case d_init_nickname::REPLACE_FIRST:
out = "";
break;
case d_init_nickname::CENTRALIZE:
break;
}
addNameWord(out, word);
}
addNameWord(out, word);
}
if (!inEnglish)

@ -48,6 +48,10 @@ using namespace std;
#include "df/world.h"
#include "df/ui.h"
#include "df/unit_inventory_item.h"
#include "df/historical_entity.h"
#include "df/historical_figure.h"
#include "df/historical_figure_info.h"
#include "df/assumed_identity.h"
using namespace DFHack;
using df::global::world;
@ -522,3 +526,28 @@ void Units::CopyNameTo(df::unit * creature, df::language_name * target)
Translation::copyName(&creature->name, target);
}
df::language_name *Units::GetVisibleName(df::unit *unit)
{
df::historical_figure *figure = df::historical_figure::find(unit->hist_figure_id);
if (figure)
{
// v0.34.01: added the vampire's assumed identity
if (figure->info && figure->info->reputation)
{
auto identity = df::assumed_identity::find(figure->info->reputation->cur_identity);
if (identity)
{
auto id_hfig = df::historical_figure::find(identity->histfig_id);
if (id_hfig)
return &id_hfig->name;
return &identity->name;
}
}
}
return &unit->name;
}

@ -2,6 +2,12 @@ package dfproto;
option optimize_for = LITE_RUNTIME;
message EnumItemName {
required int32 value = 1;
optional string name = 2;
optional int32 bit_size = 3 [default = 1];
};
message BasicMaterialId {
required int32 type = 1;
required sint32 index = 2;
@ -10,14 +16,14 @@ message BasicMaterialId {
message BasicMaterialInfo {
required int32 type = 1;
required sint32 index = 2;
required string token = 3;
repeated string flags = 4;
repeated int32 flags = 4; // of material_flags
optional int32 subtype = 5 [default = -1];
optional int32 creature_id = 6 [default = -1];
optional int32 plant_id = 7 [default = -1];
optional int32 hfig_id = 8 [default = -1];
optional int32 histfig_id = 8 [default = -1];
optional string name_prefix = 9 [default = ""];
@ -33,7 +39,7 @@ message BasicMaterialInfo {
repeated string reaction_class = 13;
repeated Product reaction_product = 14;
repeated string inorganic_flags = 15;
repeated int32 inorganic_flags = 15;
};
message BasicMaterialInfoMask {
@ -49,6 +55,50 @@ message BasicMaterialInfoMask {
optional bool flags = 2 [default = false];
optional bool reaction = 3 [default = false];
optional int32 temperature = 4;
optional int32 temperature = 4 [default = 10015];
};
message NameInfo {
optional string first_name = 1;
optional string nickname = 2;
optional int32 language_id = 3 [default = -1];
optional string last_name = 4;
optional string english_name = 5;
};
message BasicUnitInfo {
required int32 unit_id = 1;
optional NameInfo name = 2;
required fixed32 flags1 = 3;
required fixed32 flags2 = 4;
required fixed32 flags3 = 5;
required int32 race = 6;
required int32 caste = 7;
optional int32 gender = 8 [default = -1];
optional int32 civ_id = 9 [default = -1];
optional int32 histfig_id = 10 [default = -1];
repeated int32 labors = 11;
message Skill {
required int32 id = 1;
required int32 level = 2;
required int32 experience = 3;
};
repeated Skill skills = 12;
required int32 pos_x = 13;
required int32 pos_y = 14;
required int32 pos_z = 15;
};
message BasicUnitInfoMask {
optional bool labors = 1 [default = false];
optional bool skills = 2 [default = false];
};

@ -4,6 +4,18 @@ option optimize_for = LITE_RUNTIME;
import "Basic.proto";
message ListEnumsRes {
repeated EnumItemName material_flags = 1;
repeated EnumItemName inorganic_flags = 2;
repeated EnumItemName unit_flags1 = 3;
repeated EnumItemName unit_flags2 = 4;
repeated EnumItemName unit_flags3 = 5;
repeated EnumItemName unit_labor = 6;
repeated EnumItemName job_skill = 7;
};
message ListMaterialsRq {
optional BasicMaterialInfoMask mask = 1;
repeated BasicMaterialId id_list = 2;
@ -15,3 +27,14 @@ message ListMaterialsRq {
message ListMaterialsRes {
repeated BasicMaterialInfo value = 1;
};
message ListUnitsRq {
optional BasicUnitInfoMask mask = 1;
repeated int32 id_list = 2;
optional int32 race = 3;
optional int32 civ_id = 4;
};
message ListUnitsRes {
repeated BasicUnitInfo value = 1;
};