Petr Mrázek 2012-03-18 04:48:02 +01:00
commit 293eb53677
30 changed files with 1243 additions and 251 deletions

@ -44,6 +44,7 @@ include/VersionInfoFactory.h
include/Virtual.h include/Virtual.h
include/RemoteClient.h include/RemoteClient.h
include/RemoteServer.h include/RemoteServer.h
include/RemoteTools.h
) )
SET(MAIN_HEADERS_WINDOWS SET(MAIN_HEADERS_WINDOWS
@ -63,6 +64,7 @@ VersionInfoFactory.cpp
Virtual.cpp Virtual.cpp
RemoteClient.cpp RemoteClient.cpp
RemoteServer.cpp RemoteServer.cpp
RemoteTools.cpp
) )
SET(MAIN_SOURCES_WINDOWS SET(MAIN_SOURCES_WINDOWS
@ -216,8 +218,7 @@ ENDIF()
ADD_LIBRARY(dfhack SHARED ${PROJECT_SOURCES}) ADD_LIBRARY(dfhack SHARED ${PROJECT_SOURCES})
ADD_DEPENDENCIES(dfhack generate_headers) ADD_DEPENDENCIES(dfhack generate_headers)
ADD_LIBRARY(dfhack-client SHARED RemoteClient.cpp ColorText.cpp MiscUtils.cpp ADD_LIBRARY(dfhack-client SHARED RemoteClient.cpp ColorText.cpp MiscUtils.cpp ${PROJECT_PROTO_SRCS})
proto/CoreProtocol.pb.cc)
ADD_DEPENDENCIES(dfhack-client dfhack) ADD_DEPENDENCIES(dfhack-client dfhack)
ADD_EXECUTABLE(dfhack-run dfhack-run.cpp) ADD_EXECUTABLE(dfhack-run dfhack-run.cpp)

@ -164,57 +164,92 @@ void virtual_identity::Init(Core *core)
*/ */
} }
std::string DFHack::bitfieldToString(const void *p, int size, const bitfield_item_info *items) bool DFHack::findBitfieldField(unsigned *idx, const std::string &name,
unsigned size, const bitfield_item_info *items)
{ {
std::string res; for (unsigned i = 0; i < size; i++) {
const char *data = (const char*)p; if (items[i].name && items[i].name == name)
{
*idx = i;
return true;
}
}
for (int i = 0; i < size; i++) { return false;
unsigned v; }
if (items[i].size > 1) { void DFHack::setBitfieldField(void *p, unsigned idx, unsigned size, int value)
unsigned pdv = *(unsigned*)&data[i/8]; {
v = (pdv >> (i%8)) & ((1 << items[i].size)-1); uint8_t *data = ((uint8_t*)p) + (idx/8);
} else { unsigned shift = idx%8;
v = (data[i/8]>>(i%8)) & 1; uint32_t mask = ((1<<size)-1) << shift;
} uint32_t vmask = ((value << shift) & mask);
if (v) { #define ACCESS(type) *(type*)data = type((*(type*)data & ~mask) | vmask)
if (!res.empty())
res += ' ';
if (items[i].name) if (!(mask & ~0xFFU)) ACCESS(uint8_t);
res += items[i].name; else if (!(mask & ~0xFFFFU)) ACCESS(uint16_t);
else else ACCESS(uint32_t);
res += stl_sprintf("UNK_%d", i);
#undef ACCESS
}
int DFHack::getBitfieldField(const void *p, unsigned idx, unsigned size)
{
const uint8_t *data = ((const uint8_t*)p) + (idx/8);
unsigned shift = idx%8;
uint32_t mask = ((1<<size)-1) << shift;
#define ACCESS(type) return int((*(type*)data & mask) >> shift)
if (!(mask & ~0xFFU)) ACCESS(uint8_t);
else if (!(mask & ~0xFFFFU)) ACCESS(uint16_t);
else ACCESS(uint32_t);
#undef ACCESS
}
void DFHack::bitfieldToString(std::vector<std::string> *pvec, const void *p,
unsigned size, const bitfield_item_info *items)
{
for (unsigned i = 0; i < size; i++) {
int value = getBitfieldField(p, i, std::min(1,items[i].size));
if (value) {
std::string name = format_key(items[i].name, i);
if (items[i].size > 1) if (items[i].size > 1)
res += stl_sprintf("=%u", v); name += stl_sprintf("=%u", value);
pvec->push_back(name);
} }
if (items[i].size > 1) if (items[i].size > 1)
i += items[i].size-1; i += items[i].size-1;
} }
return res;
} }
int DFHack::findBitfieldField_(const std::string &name, int size, const bitfield_item_info *items) int DFHack::findEnumItem(const std::string &name, int size, const char *const *items)
{ {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
if (items[i].name && items[i].name == name) if (items[i] && items[i] == name)
return i; return i;
} }
return -1; return -1;
} }
int DFHack::findEnumItem_(const std::string &name, int size, const char *const *items) void DFHack::flagarrayToString(std::vector<std::string> *pvec, const void *p,
int bytes, int base, int size, const char *const *items)
{ {
for (int i = 0; i < size; i++) { for (unsigned i = 0; i < bytes*8; i++) {
if (items[i] && items[i] == name) int value = getBitfieldField(p, i, 1);
return i;
if (value)
{
int ridx = int(i) - base;
const char *name = (ridx >= 0 && ridx < size) ? items[ridx] : NULL;
pvec->push_back(format_key(name, i));
}
} }
return -1;
} }

@ -36,6 +36,8 @@ distribution.
#include <ctype.h> #include <ctype.h>
#include <stdarg.h> #include <stdarg.h>
#include <sstream>
std::string stl_sprintf(const char *fmt, ...) { std::string stl_sprintf(const char *fmt, ...) {
va_list lst; va_list lst;
va_start(lst, fmt); va_start(lst, fmt);
@ -82,6 +84,20 @@ bool split_string(std::vector<std::string> *out,
return out->size() > 1; return out->size() > 1;
} }
std::string join_strings(const std::string &separator, const std::vector<std::string> &items)
{
std::stringstream ss;
for (size_t i = 0; i < items.size(); i++)
{
if (i)
ss << separator;
ss << items[i];
}
return ss.str();
}
std::string toUpper(const std::string &str) std::string toUpper(const std::string &str)
{ {
std::string rv(str.size(),' '); std::string rv(str.size(),' ');

@ -112,7 +112,7 @@ RemoteClient::~RemoteClient()
delete p_default_output; delete p_default_output;
} }
bool DFHack::readFullBuffer(CSimpleSocket *socket, void *buf, int size) bool readFullBuffer(CSimpleSocket *socket, void *buf, int size)
{ {
if (!socket->IsSocketValid()) if (!socket->IsSocketValid())
return false; return false;
@ -324,22 +324,20 @@ bool RemoteFunctionBase::bind(color_ostream &out, RemoteClient *client,
return client->bind(out, this, name, proto); return client->bind(out, this, name, proto);
} }
bool DFHack::sendRemoteMessage(CSimpleSocket *socket, int16_t id, const MessageLite *msg, int *psz) bool sendRemoteMessage(CSimpleSocket *socket, int16_t id, const MessageLite *msg, bool size_ready)
{ {
int size = msg->ByteSize(); int size = size_ready ? msg->GetCachedSize() : msg->ByteSize();
int fullsz = size + sizeof(RPCMessageHeader); int fullsz = size + sizeof(RPCMessageHeader);
if (psz)
*psz = size;
std::auto_ptr<uint8_t> data(new uint8_t[fullsz]); std::auto_ptr<uint8_t> data(new uint8_t[fullsz]);
RPCMessageHeader *hdr = (RPCMessageHeader*)data.get(); RPCMessageHeader *hdr = (RPCMessageHeader*)data.get();
hdr->id = id; hdr->id = id;
hdr->size = size; hdr->size = size;
if (!msg->SerializeToArray(data.get() + sizeof(RPCMessageHeader), size)) uint8_t *pstart = data.get() + sizeof(RPCMessageHeader);
return false; uint8_t *pend = msg->SerializeWithCachedSizesToArray(pstart);
assert((pend - pstart) == size);
return (socket->Send(data.get(), fullsz) == fullsz); return (socket->Send(data.get(), fullsz) == fullsz);
} }
@ -361,7 +359,16 @@ command_result RemoteFunctionBase::execute(color_ostream &out,
return CR_LINK_FAILURE; return CR_LINK_FAILURE;
} }
if (!sendRemoteMessage(p_client->socket, id, input)) int send_size = input->ByteSize();
if (send_size > RPCMessageHeader::MAX_MESSAGE_SIZE)
{
out.printerr("In call to %s::%s: message too large: %d.\n",
this->proto.c_str(), this->name.c_str(), send_size);
return CR_LINK_FAILURE;
}
if (!sendRemoteMessage(p_client->socket, id, input, true))
{ {
out.printerr("In call to %s::%s: I/O error in send.\n", out.printerr("In call to %s::%s: I/O error in send.\n",
this->proto.c_str(), this->name.c_str()); this->proto.c_str(), this->name.c_str());
@ -388,7 +395,7 @@ command_result RemoteFunctionBase::execute(color_ostream &out,
if (header.id == RPC_REPLY_FAIL) if (header.id == RPC_REPLY_FAIL)
return header.size == CR_OK ? CR_FAILURE : command_result(header.size); return header.size == CR_OK ? CR_FAILURE : command_result(header.size);
if (header.size < 0 || header.size > 2*1048576) if (header.size < 0 || header.size > RPCMessageHeader::MAX_MESSAGE_SIZE)
{ {
out.printerr("In call to %s::%s: invalid received size %d.\n", out.printerr("In call to %s::%s: invalid received size %d.\n",
this->proto.c_str(), this->name.c_str(), header.size); this->proto.c_str(), this->name.c_str(), header.size);

@ -46,6 +46,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdint.h> #include <stdint.h>
#include "RemoteServer.h" #include "RemoteServer.h"
#include "RemoteTools.h"
#include "PassiveSocket.h" #include "PassiveSocket.h"
#include "PluginManager.h" #include "PluginManager.h"
#include "MiscUtils.h" #include "MiscUtils.h"
@ -65,76 +67,10 @@ using dfproto::CoreTextNotification;
using dfproto::CoreTextFragment; using dfproto::CoreTextFragment;
using google::protobuf::MessageLite; using google::protobuf::MessageLite;
CoreService::CoreService() { bool readFullBuffer(CSimpleSocket *socket, void *buf, int size);
suspend_depth = 0; bool sendRemoteMessage(CSimpleSocket *socket, int16_t id,
const ::google::protobuf::MessageLite *msg, bool size_ready);
// These 2 methods must be first, so that they get id 0 and 1
addMethod("BindMethod", &CoreService::BindMethod);
addMethod("RunCommand", &CoreService::RunCommand);
// Add others here:
addMethod("CoreSuspend", &CoreService::CoreSuspend);
addMethod("CoreResume", &CoreService::CoreResume);
}
CoreService::~CoreService()
{
while (suspend_depth-- > 0)
Core::getInstance().Resume();
}
command_result CoreService::BindMethod(color_ostream &stream,
const dfproto::CoreBindRequest *in,
dfproto::CoreBindReply *out)
{
ServerFunctionBase *fn = connection()->findFunction(stream, in->plugin(), in->method());
if (!fn)
{
stream.printerr("RPC method not found: %s::%s\n",
in->plugin().c_str(), in->method().c_str());
return CR_FAILURE;
}
if (fn->p_in_template->GetTypeName() != in->input_msg() ||
fn->p_out_template->GetTypeName() != in->output_msg())
{
stream.printerr("Requested wrong signature for RPC method: %s::%s\n",
in->plugin().c_str(), in->method().c_str());
return CR_FAILURE;
}
out->set_assigned_id(fn->getId());
return CR_OK;
}
command_result CoreService::RunCommand(color_ostream &stream,
const dfproto::CoreRunCommandRequest *in)
{
std::string cmd = in->command();
std::vector<std::string> args;
for (int i = 0; i < in->arguments_size(); i++)
args.push_back(in->arguments(i));
return Core::getInstance().plug_mgr->InvokeCommand(stream, cmd, args);
}
command_result CoreService::CoreSuspend(color_ostream &stream, const EmptyMessage*, IntMessage *cnt)
{
Core::getInstance().Suspend();
cnt->set_value(++suspend_depth);
return CR_OK;
}
command_result CoreService::CoreResume(color_ostream &stream, const EmptyMessage*, IntMessage *cnt)
{
if (suspend_depth <= 0)
return CR_WRONG_USAGE;
Core::getInstance().Resume();
cnt->set_value(--suspend_depth);
return CR_OK;
}
RPCService::RPCService() RPCService::RPCService()
{ {
@ -252,7 +188,7 @@ void ServerConnection::connection_ostream::flush_proxy()
buffer.clear(); buffer.clear();
if (!sendRemoteMessage(owner->socket, RPC_REPLY_TEXT, &msg)) if (!sendRemoteMessage(owner->socket, RPC_REPLY_TEXT, &msg, false))
{ {
owner->in_error = true; owner->in_error = true;
Core::printerr("Error writing text into client socket.\n"); Core::printerr("Error writing text into client socket.\n");
@ -312,7 +248,7 @@ void ServerConnection::threadFn(void *arg)
if (header.id == RPC_REQUEST_QUIT) if (header.id == RPC_REQUEST_QUIT)
break; break;
if (header.size < 0 || header.size > 2*1048576) if (header.size < 0 || header.size > RPCMessageHeader::MAX_MESSAGE_SIZE)
{ {
out.printerr("In RPC server: invalid received size %d.\n", header.size); out.printerr("In RPC server: invalid received size %d.\n", header.size);
break; break;
@ -347,6 +283,8 @@ void ServerConnection::threadFn(void *arg)
} }
else else
{ {
buf.reset();
reply = fn->out(); reply = fn->out();
res = fn->execute(me->stream); res = fn->execute(me->stream);
} }
@ -356,16 +294,23 @@ void ServerConnection::threadFn(void *arg)
if (me->in_error) if (me->in_error)
break; break;
me->stream.flush();
//out.print("Answer %d:%d\n", res, reply); //out.print("Answer %d:%d\n", res, reply);
// Send reply // Send reply
int out_size = 0; int out_size = (reply ? reply->ByteSize() : 0);
if (out_size > RPCMessageHeader::MAX_MESSAGE_SIZE)
{
me->stream.printerr("In call to %s: reply too large: %d.\n",
(fn ? fn->name : "UNKNOWN"), out_size);
res = CR_LINK_FAILURE;
}
me->stream.flush();
if (res == CR_OK && reply) if (res == CR_OK && reply)
{ {
if (!sendRemoteMessage(me->socket, RPC_REPLY_RESULT, reply, &out_size)) if (!sendRemoteMessage(me->socket, RPC_REPLY_RESULT, reply, true))
{ {
out.printerr("In RPC server: I/O error in send result.\n"); out.printerr("In RPC server: I/O error in send result.\n");
break; break;
@ -373,9 +318,6 @@ void ServerConnection::threadFn(void *arg)
} }
else else
{ {
if (reply)
out_size = reply->ByteSize();
header.id = RPC_REPLY_FAIL; header.id = RPC_REPLY_FAIL;
header.size = res; header.size = res;
@ -389,7 +331,8 @@ void ServerConnection::threadFn(void *arg)
// Cleanup // Cleanup
if (fn) if (fn)
{ {
fn->reset(out_size > 32768 || in_size > 32768); fn->reset((fn->flags & SF_CALLED_ONCE) ||
(out_size > 128*1024 || in_size > 32*1024));
} }
} }

@ -0,0 +1,488 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2011 Petr Mrázek <peterix@gmail.com>
A thread-safe logging console with a line editor for windows.
Based on linenoise win32 port,
copyright 2010, Jon Griffiths <jon_p_griffiths at yahoo dot com>.
All rights reserved.
Based on linenoise, copyright 2010, Salvatore Sanfilippo <antirez at gmail dot com>.
The original linenoise can be found at: http://github.com/antirez/linenoise
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Redis nor the names of its contributors may be used
to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <istream>
#include <string>
#include <stdint.h>
#include "RemoteTools.h"
#include "PluginManager.h"
#include "MiscUtils.h"
#include "modules/Materials.h"
#include "modules/Translation.h"
#include "modules/Units.h"
#include "DataDefs.h"
#include "df/ui.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"
#include "df/creature_raw.h"
#include "df/plant_raw.h"
#include "df/historical_figure.h"
#include "df/historical_entity.h"
#include "df/squad.h"
#include "df/squad_position.h"
#include "BasicApi.pb.h"
#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <memory>
using namespace DFHack;
using namespace df::enums;
using namespace dfproto;
using google::protobuf::MessageLite;
void DFHack::strVectorToRepeatedField(RepeatedPtrField<std::string> *pf,
const std::vector<std::string> &vec)
{
for (size_t i = 0; i < vec.size(); ++i)
*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_ints(info->mutable_flags(), mat->flags);
if (!mat->prefix.empty())
info->set_name_prefix(mat->prefix);
if (!mask || mask->states_size() == 0)
{
df::matter_state state = matter_state::Solid;
int temp = (mask && mask->has_temperature()) ? mask->temperature() : 10015;
if (temp >= mat->heat.melting_point)
state = matter_state::Liquid;
if (temp >= mat->heat.boiling_point)
state = matter_state::Gas;
info->add_state_color(mat->state_color[state]);
info->add_state_name(mat->state_name[state]);
info->add_state_adj(mat->state_adj[state]);
}
else
{
for (int i = 0; i < mask->states_size(); i++)
{
info->add_state_color(mat->state_color[i]);
info->add_state_name(mat->state_name[i]);
info->add_state_adj(mat->state_adj[i]);
}
}
if (mask && mask->reaction())
{
for (size_t i = 0; i < mat->reaction_class.size(); i++)
info->add_reaction_class(*mat->reaction_class[i]);
for (size_t i = 0; i < mat->reaction_product.id.size(); i++)
{
auto ptr = info->add_reaction_product();
ptr->set_id(*mat->reaction_product.id[i]);
ptr->set_type(mat->reaction_product.material.mat_type[i]);
ptr->set_index(mat->reaction_product.material.mat_index[i]);
}
}
}
void DFHack::describeMaterial(BasicMaterialInfo *info, const MaterialInfo &mat,
const BasicMaterialInfoMask *mask)
{
assert(mat.isValid());
info->set_type(mat.type);
info->set_index(mat.index);
describeMaterial(info, mat.material, mask);
switch (mat.mode) {
case MaterialInfo::Inorganic:
info->set_token(mat.inorganic->id);
if (mask && mask->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_histfig_id(mat.index);
info->set_creature_id(mat.figure->race);
}
else
info->set_creature_id(mat.index);
break;
case MaterialInfo::Plant:
info->set_plant_id(mat.index);
break;
}
}
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 *, ListEnumsOut *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(ListMaterialsOut *out, int type, int index, const BasicMaterialInfoMask *mask)
{
MaterialInfo info(type, index);
if (info.isValid())
describeMaterial(out->add_value(), info, mask);
}
static command_result ListMaterials(color_ostream &stream,
const ListMaterialsIn *in, ListMaterialsOut *out)
{
CoreSuspender suspend;
auto mask = in->has_mask() ? &in->mask() : NULL;
for (int i = 0; i < in->id_list_size(); i++)
{
auto &elt = in->id_list(i);
listMaterial(out, elt.type(), elt.index(), mask);
}
if (in->builtin())
{
for (int i = 0; i < MaterialInfo::NUM_BUILTIN; i++)
listMaterial(out, i, -1, mask);
}
if (in->inorganic())
{
auto &vec = df::inorganic_raw::get_vector();
for (size_t i = 0; i < vec.size(); i++)
listMaterial(out, 0, i, mask);
}
if (in->creatures())
{
auto &vec = df::creature_raw::get_vector();
for (size_t i = 0; i < vec.size(); i++)
{
auto praw = vec[i];
for (size_t j = 0; j < praw->material.size(); j++)
listMaterial(out, MaterialInfo::CREATURE_BASE+j, i, mask);
}
}
if (in->plants())
{
auto &vec = df::plant_raw::get_vector();
for (size_t i = 0; i < vec.size(); i++)
{
auto praw = vec[i];
for (size_t j = 0; j < praw->material.size(); j++)
listMaterial(out, MaterialInfo::PLANT_BASE+j, i, mask);
}
}
return out->value_size() ? CR_OK : CR_NOT_FOUND;
}
static command_result ListUnits(color_ostream &stream,
const ListUnitsIn *in, ListUnitsOut *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;
}
static command_result ListSquads(color_ostream &stream,
const ListSquadsIn *in, ListSquadsOut *out)
{
auto entity = df::historical_entity::find(df::global::ui->group_id);
if (!entity)
return CR_NOT_FOUND;
for (size_t i = 0; i < entity->squads.size(); i++)
{
auto squad = df::squad::find(entity->squads[i]);
if (!squad)
continue;
auto item = out->add_value();
item->set_squad_id(squad->id);
if (squad->name.has_name)
describeName(item->mutable_name(), &squad->name);
if (!squad->alias.empty())
item->set_alias(squad->alias);
for (size_t j = 0; j < squad->positions.size(); j++)
item->add_members(squad->positions[j]->occupant);
}
return CR_OK;
}
CoreService::CoreService() {
suspend_depth = 0;
// These 2 methods must be first, so that they get id 0 and 1
addMethod("BindMethod", &CoreService::BindMethod);
addMethod("RunCommand", &CoreService::RunCommand);
// Add others here:
addMethod("CoreSuspend", &CoreService::CoreSuspend);
addMethod("CoreResume", &CoreService::CoreResume);
addFunction("ListEnums", ListEnums, SF_CALLED_ONCE);
addFunction("ListMaterials", ListMaterials, SF_CALLED_ONCE);
addFunction("ListUnits", ListUnits);
addFunction("ListSquads", ListSquads);
}
CoreService::~CoreService()
{
while (suspend_depth-- > 0)
Core::getInstance().Resume();
}
command_result CoreService::BindMethod(color_ostream &stream,
const dfproto::CoreBindRequest *in,
dfproto::CoreBindReply *out)
{
ServerFunctionBase *fn = connection()->findFunction(stream, in->plugin(), in->method());
if (!fn)
{
stream.printerr("RPC method not found: %s::%s\n",
in->plugin().c_str(), in->method().c_str());
return CR_FAILURE;
}
if (fn->p_in_template->GetTypeName() != in->input_msg() ||
fn->p_out_template->GetTypeName() != in->output_msg())
{
stream.printerr("Requested wrong signature for RPC method: %s::%s\n",
in->plugin().c_str(), in->method().c_str());
return CR_FAILURE;
}
out->set_assigned_id(fn->getId());
return CR_OK;
}
command_result CoreService::RunCommand(color_ostream &stream,
const dfproto::CoreRunCommandRequest *in)
{
std::string cmd = in->command();
std::vector<std::string> args;
for (int i = 0; i < in->arguments_size(); i++)
args.push_back(in->arguments(i));
return Core::getInstance().plug_mgr->InvokeCommand(stream, cmd, args);
}
command_result CoreService::CoreSuspend(color_ostream &stream, const EmptyMessage*, IntMessage *cnt)
{
Core::getInstance().Suspend();
cnt->set_value(++suspend_depth);
return CR_OK;
}
command_result CoreService::CoreResume(color_ostream &stream, const EmptyMessage*, IntMessage *cnt)
{
if (suspend_depth <= 0)
return CR_WRONG_USAGE;
Core::getInstance().Resume();
cnt->set_value(--suspend_depth);
return CR_OK;
}

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

@ -142,7 +142,7 @@ namespace DFHack
Core(); Core();
class Private; struct Private;
Private *d; Private *d;
bool Init(); bool Init();

@ -25,6 +25,7 @@ distribution.
#pragma once #pragma once
#include <string> #include <string>
#include <sstream>
#include <vector> #include <vector>
#include <map> #include <map>
@ -36,6 +37,10 @@ distribution.
#undef interface #undef interface
#endif #endif
/*
* Definitions of DFHack namespace structs used by generated headers.
*/
namespace DFHack namespace DFHack
{ {
class virtual_class {}; class virtual_class {};
@ -153,6 +158,10 @@ inline int linear_index(const DFHack::enum_list_attr<const char*> &lst, const st
return -1; return -1;
} }
/*
* Definitions of df namespace structs used by generated headers.
*/
namespace df namespace df
{ {
using DFHack::virtual_ptr; using DFHack::virtual_ptr;
@ -213,8 +222,20 @@ namespace df
namespace enums {} namespace enums {}
} }
/*
* Templates for access to enum and bitfield traits.
*/
DFHACK_EXPORT std::string join_strings(const std::string &separator, const std::vector<std::string> &items);
namespace DFHack { namespace DFHack {
// Enums /*
* Enum trait tools.
*/
/**
* Return the next item in the enum, wrapping to the first one at the end.
*/
template<class T> template<class T>
inline typename df::enum_traits<T>::enum_type next_enum_item(T v) { inline typename df::enum_traits<T>::enum_type next_enum_item(T v) {
typedef df::enum_traits<T> traits; typedef df::enum_traits<T> traits;
@ -223,55 +244,194 @@ namespace DFHack {
return (iv < traits::last_item_value) ? T(iv+1) : traits::first_item; return (iv < traits::last_item_value) ? T(iv+1) : traits::first_item;
} }
/**
* Check if the value is valid for its enum type.
*/
template<class T> template<class T>
inline bool is_valid_enum_item(T v) { inline bool is_valid_enum_item(T v) {
return df::enum_traits<T>::is_valid(v); return df::enum_traits<T>::is_valid(v);
} }
/**
* Return the enum item key string pointer, or NULL if none.
*/
template<class T> template<class T>
inline const char *enum_item_raw_key(T val) { inline const char *enum_item_raw_key(T val) {
typedef df::enum_traits<T> traits; typedef df::enum_traits<T> traits;
return traits::is_valid(val) ? traits::key_table[val - traits::first_item_value] : NULL; return traits::is_valid(val) ? traits::key_table[val - traits::first_item_value] : NULL;
} }
/**
* Return the enum item key string pointer, or "?" if none.
*/
template<class T> template<class T>
inline const char *enum_item_key_str(T val) { inline const char *enum_item_key_str(T val) {
return ifnull(enum_item_raw_key(val), "?"); return ifnull(enum_item_raw_key(val), "?");
} }
DFHACK_EXPORT int findEnumItem_(const std::string &name, int size, const char *const *items); template<class BaseType>
std::string format_key(const char *keyname, BaseType val) {
if (keyname) return std::string(keyname);
std::stringstream ss; ss << "?" << val << "?"; return ss.str();
}
/**
* Return the enum item key string, or ?123? (using the numeric value) if unknown.
*/
template<class T>
inline std::string enum_item_key(T val) {
typedef typename df::enum_traits<T>::base_type base_type;
return format_key<base_type>(enum_item_raw_key(val), base_type(val));
}
DFHACK_EXPORT int findEnumItem(const std::string &name, int size, const char *const *items);
/**
* Find an enum item by key string. Returns success code.
*/
template<class T> template<class T>
inline bool find_enum_item(T *var, const std::string &name) { inline bool find_enum_item(T *var, const std::string &name) {
typedef df::enum_traits<T> traits; typedef df::enum_traits<T> traits;
int size = traits::last_item_value-traits::first_item_value+1; int size = traits::last_item_value-traits::first_item_value+1;
int idx = findEnumItem_(name, size, traits::key_table); int idx = findEnumItem(name, size, traits::key_table);
if (idx < 0) return false; if (idx < 0) return false;
*var = T(traits::first_item_value+idx); *var = T(traits::first_item_value+idx);
return true; return true;
} }
DFHACK_EXPORT int findBitfieldField_(const std::string &name, int size, const bitfield_item_info *items); /*
* Bitfield tools.
*/
DFHACK_EXPORT bool findBitfieldField(unsigned *idx, const std::string &name,
unsigned size, const bitfield_item_info *items);
DFHACK_EXPORT void setBitfieldField(void *p, unsigned idx, unsigned size, int value);
DFHACK_EXPORT int getBitfieldField(const void *p, unsigned idx, unsigned size);
/**
* Find a bitfield item by key string. Returns success code.
*/
template<class T>
inline bool find_bitfield_field(unsigned *idx, const std::string &name, const T* = NULL) {
typedef df::bitfield_traits<T> traits;
return findBitfieldField(&idx, name, traits::bit_count, traits::bits);
}
/**
* Find a bitfield item by key and set its value. Returns success code.
*/
template<class T>
inline bool set_bitfield_field(T *bitfield, const std::string &name, int value)
{
typedef df::bitfield_traits<T> traits;
unsigned idx;
if (!findBitfieldField(&idx, name, traits::bit_count, traits::bits)) return false;
setBitfieldField(&bitfield->whole, idx, traits::bits[idx].size, value);
return true;
}
/**
* Find a bitfield item by key and retrieve its value. Returns success code.
*/
template<class T> template<class T>
inline int findBitfieldField(const std::string &name) { inline bool get_bitfield_field(int *value, const T &bitfield, const std::string &name)
{
typedef df::bitfield_traits<T> traits; typedef df::bitfield_traits<T> traits;
return findBitfieldField_(name, traits::bit_count, traits::bits); unsigned idx;
if (!findBitfieldField(&idx, name, traits::bit_count, traits::bits)) return false;
*value = getBitfieldField(&bitfield.whole, idx, traits::bits[idx].size);
return true;
} }
DFHACK_EXPORT std::string bitfieldToString(const void *p, int size, const bitfield_item_info *items); DFHACK_EXPORT void bitfieldToString(std::vector<std::string> *pvec, const void *p,
unsigned size, const bitfield_item_info *items);
/**
* Represent bitfield bits as strings in a vector.
*/
template<class T> template<class T>
inline std::string bitfieldToString(const T &val) { inline void bitfield_to_string(std::vector<std::string> *pvec, const T &val) {
typedef df::bitfield_traits<T> traits; typedef df::bitfield_traits<T> traits;
return bitfieldToString(&val.whole, traits::bit_count, traits::bits); bitfieldToString(pvec, &val.whole, traits::bit_count, traits::bits);
}
/**
* Represent bitfield bits as a string, using sep as join separator.
*/
template<class T>
inline std::string bitfield_to_string(const T &val, const std::string &sep = " ") {
std::vector<std::string> tmp;
bitfield_to_string<T>(&tmp, val);
return join_strings(sep, tmp);
}
/*
* BitArray tools
*/
/**
* Find a flag array item by key string. Returns success code.
*/
template<class T>
inline bool find_flagarray_field(unsigned *idx, const std::string &name, const BitArray<T>*) {
T tmp;
if (!find_enum_item(&tmp, name) || tmp < 0) return false;
*idx = unsigned(tmp);
return true;
}
/**
* Find a flag array item by key and set its value. Returns success code.
*/
template<class T>
inline bool set_flagarray_field(BitArray<T> *bitfield, const std::string &name, int value)
{
T tmp;
if (!find_enum_item(&tmp, name) || tmp < 0) return false;
bitfield->set(tmp, value!=0);
return true;
}
/**
* Find a flag array item by key and retrieve its value. Returns success code.
*/
template<class T>
inline bool get_flagarray_field(int *value, const BitArray<T> &bitfield, const std::string &name)
{
T tmp;
if (!find_enum_item(&tmp, name) || tmp < 0) return false;
*value = (bitfield->is_set(tmp) ? 1 : 0);
return true;
}
DFHACK_EXPORT void flagarrayToString(std::vector<std::string> *pvec, const void *p,
int bytes, int base, int size, const char *const *items);
/**
* Represent flag array bits as strings in a vector.
*/
template<class T>
inline void flagarray_to_string(std::vector<std::string> *pvec, const BitArray<T> &val) {
typedef df::enum_traits<T> traits;
int size = traits::last_item_value-traits::first_item_value+1;
flagarrayToString(pvec, val.bits, val.size,
(int)traits::first_item_value, size, traits::key_table);
} }
}
/**
* Represent flag array bits as a string, using sep as join separator.
*/
template<class T>
inline std::string bitfield_to_string(const BitArray<T> &val, const std::string &sep = " ") {
std::vector<std::string> tmp;
flagarray_to_string<T>(&tmp, val);
return join_strings(sep, tmp);
}
}
#define ENUM_ATTR(enum,attr,val) (df::enum_traits<df::enum>::attrs(val).attr) #define ENUM_ATTR(enum,attr,val) (df::enum_traits<df::enum>::attrs(val).attr)
#define ENUM_ATTR_STR(enum,attr,val) DFHack::ifnull(ENUM_ATTR(enum,attr,val),"?") #define ENUM_ATTR_STR(enum,attr,val) DFHack::ifnull(ENUM_ATTR(enum,attr,val),"?")
#define ENUM_KEY_STR(enum,val) (DFHack::enum_item_key_str<df::enum>(val)) #define ENUM_KEY_STR(enum,val) (DFHack::enum_item_key<df::enum>(val))
#define ENUM_FIRST_ITEM(enum) (df::enum_traits<df::enum>::first_item) #define ENUM_FIRST_ITEM(enum) (df::enum_traits<df::enum>::first_item)
#define ENUM_LAST_ITEM(enum) (df::enum_traits<df::enum>::last_item) #define ENUM_LAST_ITEM(enum) (df::enum_traits<df::enum>::last_item)
@ -280,6 +440,10 @@ namespace DFHack {
#define FOR_ENUM_ITEMS(enum,iter) \ #define FOR_ENUM_ITEMS(enum,iter) \
for(df::enum iter = ENUM_FIRST_ITEM(enum); iter <= ENUM_LAST_ITEM(enum); iter = df::enum(1+int(iter))) for(df::enum iter = ENUM_FIRST_ITEM(enum); iter <= ENUM_LAST_ITEM(enum); iter = df::enum(1+int(iter)))
/*
* Include mandatory generated headers.
*/
// Global object pointers // Global object pointers
#include "df/global_objects.h" #include "df/global_objects.h"

@ -253,6 +253,7 @@ Link *linked_list_insert_after(Link *pos, Link *link)
DFHACK_EXPORT bool split_string(std::vector<std::string> *out, DFHACK_EXPORT bool split_string(std::vector<std::string> *out,
const std::string &str, const std::string &separator, const std::string &str, const std::string &separator,
bool squash_empty = false); bool squash_empty = false);
DFHACK_EXPORT std::string join_strings(const std::string &separator, const std::vector<std::string> &items);
DFHACK_EXPORT std::string toUpper(const std::string &str); DFHACK_EXPORT std::string toUpper(const std::string &str);
DFHACK_EXPORT std::string toLower(const std::string &str); DFHACK_EXPORT std::string toLower(const std::string &str);

@ -66,6 +66,8 @@ namespace DFHack
}; };
struct RPCMessageHeader { struct RPCMessageHeader {
static const int MAX_MESSAGE_SIZE = 8*1048756;
int16_t id; int16_t id;
int32_t size; int32_t size;
}; };
@ -220,10 +222,6 @@ namespace DFHack
} }
}; };
bool readFullBuffer(CSimpleSocket *socket, void *buf, int size);
bool sendRemoteMessage(CSimpleSocket *socket, int16_t id,
const ::google::protobuf::MessageLite *msg, int *psz = NULL);
class DFHACK_EXPORT RemoteClient class DFHACK_EXPORT RemoteClient
{ {
friend class RemoteFunctionBase; friend class RemoteFunctionBase;

@ -34,12 +34,22 @@ class CSimpleSocket;
namespace DFHack namespace DFHack
{ {
class DFHACK_EXPORT ServerConnection; class Plugin;
class CoreService;
class ServerConnection;
class DFHACK_EXPORT RPCService; class DFHACK_EXPORT RPCService;
enum ServerFunctionFlags {
// The function is expected to be called only once per client,
// so always delete all cached buffers after processing.
SF_CALLED_ONCE = 1
};
class DFHACK_EXPORT ServerFunctionBase : public RPCFunctionBase { class DFHACK_EXPORT ServerFunctionBase : public RPCFunctionBase {
public: public:
const char *const name; const char *const name;
const int flags;
virtual command_result execute(color_ostream &stream) = 0; virtual command_result execute(color_ostream &stream) = 0;
@ -48,8 +58,9 @@ namespace DFHack
protected: protected:
friend class RPCService; friend class RPCService;
ServerFunctionBase(const message_type *in, const message_type *out, RPCService *owner, const char *name) ServerFunctionBase(const message_type *in, const message_type *out,
: RPCFunctionBase(in, out), name(name), owner(owner), id(-1) RPCService *owner, const char *name, int flags)
: RPCFunctionBase(in, out), name(name), flags(flags), owner(owner), id(-1)
{} {}
RPCService *owner; RPCService *owner;
@ -64,8 +75,8 @@ namespace DFHack
In *in() { return static_cast<In*>(RPCFunctionBase::in()); } In *in() { return static_cast<In*>(RPCFunctionBase::in()); }
Out *out() { return static_cast<Out*>(RPCFunctionBase::out()); } Out *out() { return static_cast<Out*>(RPCFunctionBase::out()); }
ServerFunction(RPCService *owner, const char *name, function_type fptr) ServerFunction(RPCService *owner, const char *name, int flags, function_type fptr)
: ServerFunctionBase(&In::default_instance(), &Out::default_instance(), owner, name), : ServerFunctionBase(&In::default_instance(), &Out::default_instance(), owner, name, flags),
fptr(fptr) {} fptr(fptr) {}
virtual command_result execute(color_ostream &stream) { return fptr(stream, in(), out()); } virtual command_result execute(color_ostream &stream) { return fptr(stream, in(), out()); }
@ -81,8 +92,8 @@ namespace DFHack
In *in() { return static_cast<In*>(RPCFunctionBase::in()); } In *in() { return static_cast<In*>(RPCFunctionBase::in()); }
VoidServerFunction(RPCService *owner, const char *name, function_type fptr) VoidServerFunction(RPCService *owner, const char *name, int flags, function_type fptr)
: ServerFunctionBase(&In::default_instance(), &EmptyMessage::default_instance(), owner, name), : ServerFunctionBase(&In::default_instance(), &EmptyMessage::default_instance(), owner, name, flags),
fptr(fptr) {} fptr(fptr) {}
virtual command_result execute(color_ostream &stream) { return fptr(stream, in()); } virtual command_result execute(color_ostream &stream) { return fptr(stream, in()); }
@ -99,8 +110,8 @@ namespace DFHack
In *in() { return static_cast<In*>(RPCFunctionBase::in()); } In *in() { return static_cast<In*>(RPCFunctionBase::in()); }
Out *out() { return static_cast<Out*>(RPCFunctionBase::out()); } Out *out() { return static_cast<Out*>(RPCFunctionBase::out()); }
ServerMethod(RPCService *owner, const char *name, function_type fptr) ServerMethod(RPCService *owner, const char *name, int flags, function_type fptr)
: ServerFunctionBase(&In::default_instance(), &Out::default_instance(), owner, name), : ServerFunctionBase(&In::default_instance(), &Out::default_instance(), owner, name, flags),
fptr(fptr) {} fptr(fptr) {}
virtual command_result execute(color_ostream &stream) { virtual command_result execute(color_ostream &stream) {
@ -118,8 +129,8 @@ namespace DFHack
In *in() { return static_cast<In*>(RPCFunctionBase::in()); } In *in() { return static_cast<In*>(RPCFunctionBase::in()); }
VoidServerMethod(RPCService *owner, const char *name, function_type fptr) VoidServerMethod(RPCService *owner, const char *name, int flags, function_type fptr)
: ServerFunctionBase(&In::default_instance(), &EmptyMessage::default_instance(), owner, name), : ServerFunctionBase(&In::default_instance(), &EmptyMessage::default_instance(), owner, name, flags),
fptr(fptr) {} fptr(fptr) {}
virtual command_result execute(color_ostream &stream) { virtual command_result execute(color_ostream &stream) {
@ -130,8 +141,6 @@ namespace DFHack
function_type fptr; function_type fptr;
}; };
class Plugin;
class DFHACK_EXPORT RPCService { class DFHACK_EXPORT RPCService {
friend class ServerConnection; friend class ServerConnection;
friend class Plugin; friend class Plugin;
@ -153,19 +162,21 @@ namespace DFHack
template<typename In, typename Out> template<typename In, typename Out>
void addFunction( void addFunction(
const char *name, const char *name,
command_result (*fptr)(color_ostream &out, const In *input, Out *output) command_result (*fptr)(color_ostream &out, const In *input, Out *output),
int flags = 0
) { ) {
assert(!owner); assert(!owner);
functions.push_back(new ServerFunction<In,Out>(this, name, fptr)); functions.push_back(new ServerFunction<In,Out>(this, name, flags, fptr));
} }
template<typename In> template<typename In>
void addFunction( void addFunction(
const char *name, const char *name,
command_result (*fptr)(color_ostream &out, const In *input) command_result (*fptr)(color_ostream &out, const In *input),
int flags = 0
) { ) {
assert(!owner); assert(!owner);
functions.push_back(new VoidServerFunction<In>(this, name, fptr)); functions.push_back(new VoidServerFunction<In>(this, name, flags, fptr));
} }
protected: protected:
@ -174,40 +185,25 @@ namespace DFHack
template<typename Svc, typename In, typename Out> template<typename Svc, typename In, typename Out>
void addMethod( void addMethod(
const char *name, const char *name,
command_result (Svc::*fptr)(color_ostream &out, const In *input, Out *output) command_result (Svc::*fptr)(color_ostream &out, const In *input, Out *output),
int flags = 0
) { ) {
assert(!owner); assert(!owner);
functions.push_back(new ServerMethod<Svc,In,Out>(this, name, fptr)); functions.push_back(new ServerMethod<Svc,In,Out>(this, name, flags, fptr));
} }
template<typename Svc, typename In> template<typename Svc, typename In>
void addMethod( void addMethod(
const char *name, const char *name,
command_result (Svc::*fptr)(color_ostream &out, const In *input) command_result (Svc::*fptr)(color_ostream &out, const In *input),
int flags = 0
) { ) {
assert(!owner); assert(!owner);
functions.push_back(new VoidServerMethod<Svc,In>(this, name, fptr)); functions.push_back(new VoidServerMethod<Svc,In>(this, name, flags, fptr));
} }
}; };
class CoreService : public RPCService { class ServerConnection {
int suspend_depth;
public:
CoreService();
~CoreService();
command_result BindMethod(color_ostream &stream,
const dfproto::CoreBindRequest *in,
dfproto::CoreBindReply *out);
command_result RunCommand(color_ostream &stream,
const dfproto::CoreRunCommandRequest *in);
// For batching
command_result CoreSuspend(color_ostream &stream, const EmptyMessage*, IntMessage *cnt);
command_result CoreResume(color_ostream &stream, const EmptyMessage*, IntMessage *cnt);
};
class DFHACK_EXPORT ServerConnection {
class connection_ostream : public buffered_color_ostream { class connection_ostream : public buffered_color_ostream {
ServerConnection *owner; ServerConnection *owner;
@ -237,7 +233,7 @@ namespace DFHack
ServerFunctionBase *findFunction(color_ostream &out, const std::string &plugin, const std::string &name); ServerFunctionBase *findFunction(color_ostream &out, const std::string &plugin, const std::string &name);
}; };
class DFHACK_EXPORT ServerMain { class ServerMain {
CPassiveSocket *socket; CPassiveSocket *socket;
tthread::thread *thread; tthread::thread *thread;

@ -0,0 +1,143 @@
/*
https://github.com/peterix/dfhack
Copyright (c) 2009-2011 Petr Mrázek (peterix@gmail.com)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product documentation
would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
*/
#pragma once
#include "Pragma.h"
#include "Export.h"
#include "RemoteServer.h"
#include "DataDefs.h"
#include "Basic.pb.h"
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,
const std::vector<std::string> &vec);
/**
* Represent bitfield bits as a repeated string field.
*/
template<class T>
inline void bitfield_to_string(RepeatedPtrField<std::string> *pf, const T &val) {
std::vector<std::string> tmp;
bitfield_to_string<T>(&tmp, val);
strVectorToRepeatedField(pf, tmp);
}
/**
* Represent flagarray bits as a repeated string field.
*/
template<class T>
inline void flagarray_to_string(RepeatedPtrField<std::string> *pf, const BitArray<T> &val) {
std::vector<std::string> tmp;
flagarray_to_string<T>(&tmp, val);
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;
using dfproto::BasicMaterialInfoMask;
DFHACK_EXPORT void describeMaterial(BasicMaterialInfo *info, df::material *mat,
const BasicMaterialInfoMask *mask = NULL);
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 {
int suspend_depth;
public:
CoreService();
~CoreService();
command_result BindMethod(color_ostream &stream,
const dfproto::CoreBindRequest *in,
dfproto::CoreBindReply *out);
command_result RunCommand(color_ostream &stream,
const dfproto::CoreRunCommandRequest *in);
// For batching
command_result CoreSuspend(color_ostream &stream, const EmptyMessage*, IntMessage *cnt);
command_result CoreResume(color_ostream &stream, const EmptyMessage*, IntMessage *cnt);
};
}

@ -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); DFHACK_EXPORT bool copyName(df::language_name * address, df::language_name * target);
// translate a name using the loaded dictionaries // 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 #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 RemoveOwnedItemByIdx(const uint32_t index, int32_t id);
DFHACK_EXPORT bool RemoveOwnedItemByPtr(df::unit * unit, int32_t id); DFHACK_EXPORT bool RemoveOwnedItemByPtr(df::unit * unit, int32_t id);
DFHACK_EXPORT df::language_name *GetVisibleName(df::unit *unit);
} }
} }
#endif #endif

@ -159,11 +159,11 @@ static void print_job_item_details(color_ostream &out, df::job *job, unsigned id
} }
if (item->flags1.whole) if (item->flags1.whole)
out << " flags1: " << bitfieldToString(item->flags1) << endl; out << " flags1: " << bitfield_to_string(item->flags1) << endl;
if (item->flags2.whole) if (item->flags2.whole)
out << " flags2: " << bitfieldToString(item->flags2) << endl; out << " flags2: " << bitfield_to_string(item->flags2) << endl;
if (item->flags3.whole) if (item->flags3.whole)
out << " flags3: " << bitfieldToString(item->flags3) << endl; out << " flags3: " << bitfield_to_string(item->flags3) << endl;
if (!item->reaction_class.empty()) if (!item->reaction_class.empty())
out << " reaction class: " << item->reaction_class << endl; out << " reaction class: " << item->reaction_class << endl;
@ -178,7 +178,7 @@ void DFHack::printJobDetails(color_ostream &out, df::job *job)
out.color(job->flags.bits.suspend ? Console::COLOR_DARKGREY : Console::COLOR_GREY); out.color(job->flags.bits.suspend ? Console::COLOR_DARKGREY : Console::COLOR_GREY);
out << "Job " << job->id << ": " << ENUM_KEY_STR(job_type,job->job_type); out << "Job " << job->id << ": " << ENUM_KEY_STR(job_type,job->job_type);
if (job->flags.whole) if (job->flags.whole)
out << " (" << bitfieldToString(job->flags) << ")"; out << " (" << bitfield_to_string(job->flags) << ")";
out << endl; out << endl;
out.reset_color(); out.reset_color();
@ -192,7 +192,7 @@ void DFHack::printJobDetails(color_ostream &out, df::job *job)
{ {
out << " material: " << mat.toString(); out << " material: " << mat.toString();
if (job->material_category.whole) if (job->material_category.whole)
out << " (" << bitfieldToString(job->material_category) << ")"; out << " (" << bitfield_to_string(job->material_category) << ")";
out << endl; out << endl;
} }
@ -201,7 +201,7 @@ void DFHack::printJobDetails(color_ostream &out, df::job *job)
ItemTypeInfo iinfo(itype, job->item_subtype); ItemTypeInfo iinfo(itype, job->item_subtype);
out << " item: " << iinfo.toString() out << " item: " << iinfo.toString()
<< " (" << bitfieldToString(job->item_category) << ")" << endl; << " (" << bitfield_to_string(job->item_category) << ")" << endl;
} }
if (job->hist_figure_id >= 0) if (job->hist_figure_id >= 0)

@ -505,11 +505,8 @@ bool DFHack::parseJobMaterialCategory(df::job_material_category *cat, const std:
for (size_t i = 0; i < items.size(); i++) for (size_t i = 0; i < items.size(); i++)
{ {
int id = findBitfieldField<df::job_material_category>(items[i]); if (!set_bitfield_field(cat, items[i], 1))
if (id < 0)
return false; return false;
cat->whole |= (1 << id);
} }
return true; return true;
@ -524,11 +521,8 @@ bool DFHack::parseJobMaterialCategory(df::dfhack_material_category *cat, const s
for (size_t i = 0; i < items.size(); i++) for (size_t i = 0; i < items.size(); i++)
{ {
int id = findBitfieldField<df::dfhack_material_category>(items[i]); if (!set_bitfield_field(cat, items[i], 1))
if (id < 0)
return false; return false;
cat->whole |= (1 << id);
} }
return true; return true;

@ -91,29 +91,31 @@ void addNameWord (string &out, const string &word)
out.append(upper); 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 out;
string word; string word;
if (!name->first_name.empty()) if (!onlyLastPart) {
addNameWord(out, name->first_name); if (!name->first_name.empty())
addNameWord(out, name->first_name);
if (!name->nickname.empty()) if (!name->nickname.empty())
{
word = "`" + name->nickname + "'";
switch (d_init ? d_init->nickname_dwarf : d_init_nickname::CENTRALIZE)
{ {
case d_init_nickname::REPLACE_ALL: word = "`" + name->nickname + "'";
out = word; switch (d_init ? d_init->nickname_dwarf : d_init_nickname::CENTRALIZE)
return out; {
case d_init_nickname::REPLACE_FIRST: case d_init_nickname::REPLACE_ALL:
out = ""; out = word;
break; return out;
case d_init_nickname::CENTRALIZE: case d_init_nickname::REPLACE_FIRST:
break; out = "";
break;
case d_init_nickname::CENTRALIZE:
break;
}
addNameWord(out, word);
} }
addNameWord(out, word);
} }
if (!inEnglish) if (!inEnglish)

@ -48,6 +48,10 @@ using namespace std;
#include "df/world.h" #include "df/world.h"
#include "df/ui.h" #include "df/ui.h"
#include "df/unit_inventory_item.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 namespace DFHack;
using df::global::world; using df::global::world;
@ -522,3 +526,28 @@ void Units::CopyNameTo(df::unit * creature, df::language_name * target)
Translation::copyName(&creature->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;
}

@ -0,0 +1,114 @@
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;
};
message BasicMaterialInfo {
required int32 type = 1;
required sint32 index = 2;
required string token = 3;
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 histfig_id = 8 [default = -1];
optional string name_prefix = 9 [default = ""];
repeated fixed32 state_color = 10;
repeated string state_name = 11;
repeated string state_adj = 12;
message Product {
required string id = 1;
required int32 type = 2;
required sint32 index = 3;
};
repeated string reaction_class = 13;
repeated Product reaction_product = 14;
repeated int32 inorganic_flags = 15;
};
message BasicMaterialInfoMask {
enum StateType {
Solid = 0;
Liquid = 1;
Gas = 2;
Powder = 3;
Paste = 4;
Pressed = 5;
};
repeated StateType states = 1;
optional int32 temperature = 4 [default = 10015];
optional bool flags = 2 [default = false];
optional bool reaction = 3 [default = false];
};
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 SkillInfo {
required int32 id = 1;
required int32 level = 2;
required int32 experience = 3;
};
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;
repeated SkillInfo 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];
};
message BasicSquadInfo {
required int32 squad_id = 1;
optional NameInfo name = 2;
optional string alias = 3;
repeated sint32 members = 4;
};

@ -0,0 +1,45 @@
package dfproto;
option optimize_for = LITE_RUNTIME;
import "Basic.proto";
message ListEnumsOut {
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 ListMaterialsIn {
optional BasicMaterialInfoMask mask = 1;
repeated BasicMaterialId id_list = 2;
optional bool builtin = 3;
optional bool inorganic = 4;
optional bool creatures = 5;
optional bool plants = 6;
};
message ListMaterialsOut {
repeated BasicMaterialInfo value = 1;
};
message ListUnitsIn {
optional BasicUnitInfoMask mask = 1;
repeated int32 id_list = 2;
optional int32 race = 3;
optional int32 civ_id = 4;
};
message ListUnitsOut {
repeated BasicUnitInfo value = 1;
};
message ListSquadsIn {}
message ListSquadsOut {
repeated BasicSquadInfo value = 1;
}

@ -72,18 +72,23 @@ MACRO(DFHACK_PLUGIN)
ADD_LIBRARY(${PLUGIN_NAME} MODULE ${PLUGIN_SOURCES}) ADD_LIBRARY(${PLUGIN_NAME} MODULE ${PLUGIN_SOURCES})
IDE_FOLDER(${PLUGIN_NAME} "Plugins") IDE_FOLDER(${PLUGIN_NAME} "Plugins")
LIST(LENGTH PLUGIN_PROTOBUFS NUM_PROTO) LIST(LENGTH PLUGIN_PROTOBUFS NUM_PROTO)
IF(NUM_PROTO) IF(NUM_PROTO)
TARGET_LINK_LIBRARIES(${PLUGIN_NAME} dfhack protobuf-lite ${PLUGIN_LINK_LIBRARIES}) TARGET_LINK_LIBRARIES(${PLUGIN_NAME} dfhack protobuf-lite ${PLUGIN_LINK_LIBRARIES})
IF(UNIX)
SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES COMPILE_FLAGS "-include Export.h")
ELSE()
SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES COMPILE_FLAGS "/FI\"Export.h\"")
ENDIF()
ELSE() ELSE()
TARGET_LINK_LIBRARIES(${PLUGIN_NAME} dfhack ${PLUGIN_LINK_LIBRARIES}) TARGET_LINK_LIBRARIES(${PLUGIN_NAME} dfhack ${PLUGIN_LINK_LIBRARIES})
ENDIF() ENDIF()
IF(UNIX) IF(UNIX)
SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.so PREFIX "") SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.so PREFIX "")
SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES COMPILE_FLAGS "-include Export.h")
ELSE() ELSE()
SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.dll) SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES SUFFIX .plug.dll)
SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES COMPILE_FLAGS "/FI\"Export.h\"")
ENDIF() ENDIF()
install(TARGETS ${PLUGIN_NAME} install(TARGETS ${PLUGIN_NAME}

@ -245,13 +245,13 @@ command_result df_dumpmats (color_ostream &out, vector<string> &parameters)
FOR_ENUM_ITEMS(material_flags, i) FOR_ENUM_ITEMS(material_flags, i)
{ {
if (mat->flags.is_set(i)) if (mat->flags.is_set(i))
out.print("\t[%s]\n", ENUM_KEY_STR(material_flags, i)); out.print("\t[%s]\n", ENUM_KEY_STR(material_flags, i).c_str());
} }
if (mat->extract_storage != item_type::BARREL) if (mat->extract_storage != item_type::BARREL)
out.print("\t[EXTRACT_STORAGE:%s]\n", ENUM_KEY_STR(item_type, mat->extract_storage)); out.print("\t[EXTRACT_STORAGE:%s]\n", ENUM_KEY_STR(item_type, mat->extract_storage).c_str());
if (mat->butcher_special_type != item_type::NONE || mat->butcher_special_subtype != -1) if (mat->butcher_special_type != item_type::NONE || mat->butcher_special_subtype != -1)
out.print("\t[BUTCHER_SPECIAL:%s:%s]\n", ENUM_KEY_STR(item_type, mat->butcher_special_type), (mat->butcher_special_subtype == -1) ? "NONE" : "?"); out.print("\t[BUTCHER_SPECIAL:%s:%s]\n", ENUM_KEY_STR(item_type, mat->butcher_special_type).c_str(), (mat->butcher_special_subtype == -1) ? "NONE" : "?");
if (mat->meat_name[0].size() || mat->meat_name[1].size() || mat->meat_name[2].size()) if (mat->meat_name[0].size() || mat->meat_name[1].size() || mat->meat_name[2].size())
out.print("\t[MEAT_NAME:%s:%s:%s]\n", mat->meat_name[0].c_str(), mat->meat_name[1].c_str(), mat->meat_name[2].c_str()); out.print("\t[MEAT_NAME:%s:%s:%s]\n", mat->meat_name[0].c_str(), mat->meat_name[1].c_str(), mat->meat_name[2].c_str());
if (mat->block_name[0].size() || mat->block_name[1].size()) if (mat->block_name[0].size() || mat->block_name[1].size())

@ -38,7 +38,9 @@ static command_result feature(color_ostream &out, vector <string> &parameters)
df::feature_init *feature_init = world->cur_savegame.map_features[i]; df::feature_init *feature_init = world->cur_savegame.map_features[i];
string name; string name;
feature_init->getName(&name); feature_init->getName(&name);
out.print("Feature #%i (\"%s\", type %s) is %s\n", i, name.c_str(), ENUM_KEY_STR(feature_type, feature_init->getType()), feature_init->flags.is_set(feature_init_flags::Discovered) ? "discovered" : "hidden"); out.print("Feature #%i (\"%s\", type %s) is %s\n",
i, name.c_str(), ENUM_KEY_STR(feature_type, feature_init->getType()).c_str(),
feature_init->flags.is_set(feature_init_flags::Discovered) ? "discovered" : "hidden");
} }
} }
else if(cmd == "show") else if(cmd == "show")
@ -60,7 +62,8 @@ static command_result feature(color_ostream &out, vector <string> &parameters)
feature_init->flags.set(feature_init_flags::Discovered); feature_init->flags.set(feature_init_flags::Discovered);
string name; string name;
feature_init->getName(&name); feature_init->getName(&name);
out.print("Feature #%i (\"%s\", type %s) is now discovered\n", i, name.c_str(), ENUM_KEY_STR(feature_type, feature_init->getType())); out.print("Feature #%i (\"%s\", type %s) is now discovered\n",
i, name.c_str(), ENUM_KEY_STR(feature_type, feature_init->getType()).c_str());
} }
else if(cmd == "hide") else if(cmd == "hide")
{ {
@ -81,7 +84,8 @@ static command_result feature(color_ostream &out, vector <string> &parameters)
feature_init->flags.clear(feature_init_flags::Discovered); feature_init->flags.clear(feature_init_flags::Discovered);
string name; string name;
feature_init->getName(&name); feature_init->getName(&name);
out.print("Feature #%i (\"%s\", type %s) is now hidden\n", i, name.c_str(), ENUM_KEY_STR(feature_type, feature_init->getType())); out.print("Feature #%i (\"%s\", type %s) is now hidden\n",
i, name.c_str(), ENUM_KEY_STR(feature_type, feature_init->getType()).c_str());
} }
else return CR_WRONG_USAGE; else return CR_WRONG_USAGE;

@ -146,7 +146,7 @@ static command_result job_material_in_job(color_ostream &out, MaterialInfo &new_
if (new_mat.getCraftClass() != old_class) if (new_mat.getCraftClass() != old_class)
{ {
out.printerr("New material %s does not satisfy requirement: %s\n", out.printerr("New material %s does not satisfy requirement: %s\n",
new_mat.toString().c_str(), ENUM_KEY_STR(craft_material_class, old_class)); new_mat.toString().c_str(), ENUM_KEY_STR(craft_material_class, old_class).c_str());
return CR_FAILURE; return CR_FAILURE;
} }
@ -277,7 +277,7 @@ static command_result job_duplicate(color_ostream &out, vector <string> & parame
job->job_type != job_type::CollectSand && job->job_type != job_type::CollectSand &&
job->job_type != job_type::CollectClay)) job->job_type != job_type::CollectClay))
{ {
out.printerr("Cannot duplicate job %s\n", ENUM_KEY_STR(job_type,job->job_type)); out.printerr("Cannot duplicate job %s\n", ENUM_KEY_STR(job_type,job->job_type).c_str());
return CR_FAILURE; return CR_FAILURE;
} }

@ -175,15 +175,15 @@ command_result df_probe (color_ostream &out, vector <string> & parameters)
df::tiletype_special special = tileSpecial(tiletype); df::tiletype_special special = tileSpecial(tiletype);
df::tiletype_variant variant = tileVariant(tiletype); df::tiletype_variant variant = tileVariant(tiletype);
out.print("%-10s: %4d %s\n","Class" ,shape, out.print("%-10s: %4d %s\n","Class" ,shape,
ENUM_KEY_STR(tiletype_shape, shape)); ENUM_KEY_STR(tiletype_shape, shape).c_str());
out.print("%-10s: %4d %s\n","Material" , out.print("%-10s: %4d %s\n","Material" ,
material, ENUM_KEY_STR(tiletype_material, material)); material, ENUM_KEY_STR(tiletype_material, material).c_str());
out.print("%-10s: %4d %s\n","Special" , out.print("%-10s: %4d %s\n","Special" ,
special, ENUM_KEY_STR(tiletype_special, special)); special, ENUM_KEY_STR(tiletype_special, special).c_str());
out.print("%-10s: %4d %s\n" ,"Variant" , out.print("%-10s: %4d %s\n" ,"Variant" ,
variant, ENUM_KEY_STR(tiletype_variant, variant)); variant, ENUM_KEY_STR(tiletype_variant, variant).c_str());
out.print("%-10s: %s\n" ,"Direction", out.print("%-10s: %s\n" ,"Direction",
tileDirection(tiletype).getStr()); tileDirection(tiletype).getStr());
out.print("\n"); out.print("\n");
out.print("temperature1: %d U\n",mc.temperature1At(cursor)); out.print("temperature1: %d U\n",mc.temperature1At(cursor));
@ -300,34 +300,38 @@ command_result df_bprobe (color_ostream &out, vector <string> & parameters)
continue; continue;
string name; string name;
building.origin->getName(&name); building.origin->getName(&name);
out.print("Building %i - \"%s\" - type %s", building.origin->id, name.c_str(), ENUM_KEY_STR(building_type, building.type)); out.print("Building %i - \"%s\" - type %s",
building.origin->id, name.c_str(),
ENUM_KEY_STR(building_type, building.type).c_str());
switch (building.type) switch (building.type)
{ {
case building_type::Civzone: case building_type::Civzone:
out.print(", subtype %s", ENUM_KEY_STR(civzone_type, building.civzone_type)); out.print(", subtype %s", ENUM_KEY_STR(civzone_type, building.civzone_type).c_str());
break; break;
case building_type::Furnace: case building_type::Furnace:
out.print(", subtype %s", ENUM_KEY_STR(furnace_type, building.furnace_type)); out.print(", subtype %s", ENUM_KEY_STR(furnace_type, building.furnace_type).c_str());
if (building.furnace_type == furnace_type::Custom) if (building.furnace_type == furnace_type::Custom)
out.print(", custom type %i (%s)", building.custom_type, world->raws.buildings.all[building.custom_type]->code.c_str()); out.print(", custom type %i (%s)", building.custom_type,
world->raws.buildings.all[building.custom_type]->code.c_str());
break; break;
case building_type::Workshop: case building_type::Workshop:
out.print(", subtype %s", ENUM_KEY_STR(workshop_type, building.workshop_type)); out.print(", subtype %s", ENUM_KEY_STR(workshop_type, building.workshop_type).c_str());
if (building.workshop_type == workshop_type::Custom) if (building.workshop_type == workshop_type::Custom)
out.print(", custom type %i (%s)", building.custom_type, world->raws.buildings.all[building.custom_type]->code.c_str()); out.print(", custom type %i (%s)", building.custom_type,
world->raws.buildings.all[building.custom_type]->code.c_str());
break; break;
case building_type::Construction: case building_type::Construction:
out.print(", subtype %s", ENUM_KEY_STR(construction_type, building.construction_type)); out.print(", subtype %s", ENUM_KEY_STR(construction_type, building.construction_type).c_str());
break; break;
case building_type::Shop: case building_type::Shop:
out.print(", subtype %s", ENUM_KEY_STR(shop_type, building.shop_type)); out.print(", subtype %s", ENUM_KEY_STR(shop_type, building.shop_type).c_str());
break; break;
case building_type::SiegeEngine: case building_type::SiegeEngine:
out.print(", subtype %s", ENUM_KEY_STR(siegeengine_type, building.siegeengine_type)); out.print(", subtype %s", ENUM_KEY_STR(siegeengine_type, building.siegeengine_type).c_str());
break; break;
case building_type::Trap: case building_type::Trap:
out.print(", subtype %s", ENUM_KEY_STR(trap_type, building.trap_type)); out.print(", subtype %s", ENUM_KEY_STR(trap_type, building.trap_type).c_str());
break; break;
default: default:
if (building.subtype != -1) if (building.subtype != -1)

@ -2,14 +2,14 @@ package dfproto;
option optimize_for = LITE_RUNTIME; option optimize_for = LITE_RUNTIME;
message RenameSquadRq { message RenameSquadIn {
required int32 squad_id = 1; required int32 squad_id = 1;
optional string nickname = 2; optional string nickname = 2;
optional string alias = 3; optional string alias = 3;
} }
message RenameUnitRq { message RenameUnitIn {
required int32 unit_id = 1; required int32 unit_id = 1;
optional string nickname = 2; optional string nickname = 2;

@ -122,7 +122,7 @@ void setUnitNickname(df::unit *unit, const std::string &nick)
} }
} }
static command_result RenameSquad(color_ostream &stream, const RenameSquadRq *in) static command_result RenameSquad(color_ostream &stream, const RenameSquadIn *in)
{ {
CoreSuspender suspend; CoreSuspender suspend;
@ -138,7 +138,7 @@ static command_result RenameSquad(color_ostream &stream, const RenameSquadRq *in
return CR_OK; return CR_OK;
} }
static command_result RenameUnit(color_ostream &stream, const RenameUnitRq *in) static command_result RenameUnit(color_ostream &stream, const RenameUnitIn *in)
{ {
CoreSuspender suspend; CoreSuspender suspend;

@ -235,16 +235,16 @@ command_result df_showmood (color_ostream &out, vector <string> & parameters)
else else
out.print("%s unknown body parts (%s:%s:%s)", out.print("%s unknown body parts (%s:%s:%s)",
mat_name.c_str(), mat_name.c_str(),
bitfieldToString(item->flags1).c_str(), bitfield_to_string(item->flags1).c_str(),
bitfieldToString(item->flags2).c_str(), bitfield_to_string(item->flags2).c_str(),
bitfieldToString(item->flags3).c_str()); bitfield_to_string(item->flags3).c_str());
} }
else else
out.print("indeterminate %s item (%s:%s:%s)", out.print("indeterminate %s item (%s:%s:%s)",
mat_name.c_str(), mat_name.c_str(),
bitfieldToString(item->flags1).c_str(), bitfield_to_string(item->flags1).c_str(),
bitfieldToString(item->flags2).c_str(), bitfield_to_string(item->flags2).c_str(),
bitfieldToString(item->flags3).c_str()); bitfield_to_string(item->flags3).c_str());
break; break;
default: default:
{ {
@ -252,9 +252,9 @@ command_result df_showmood (color_ostream &out, vector <string> & parameters)
out.print("item %s material %s flags (%s:%s:%s)", out.print("item %s material %s flags (%s:%s:%s)",
itinfo.toString().c_str(), mat_name.c_str(), itinfo.toString().c_str(), mat_name.c_str(),
bitfieldToString(item->flags1).c_str(), bitfield_to_string(item->flags1).c_str(),
bitfieldToString(item->flags2).c_str(), bitfield_to_string(item->flags2).c_str(),
bitfieldToString(item->flags3).c_str()); bitfield_to_string(item->flags3).c_str());
break; break;
} }
} }

@ -502,7 +502,7 @@ static bool recover_job(color_ostream &out, ProtectedJob *pj)
if (!pj->holder) if (!pj->holder)
{ {
out.printerr("Forgetting job %d (%s): holder building lost.", out.printerr("Forgetting job %d (%s): holder building lost.",
pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type)); pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type).c_str());
forget_job(out, pj); forget_job(out, pj);
return true; return true;
} }
@ -511,7 +511,7 @@ static bool recover_job(color_ostream &out, ProtectedJob *pj)
if (pj->holder->jobs.size() >= 10) if (pj->holder->jobs.size() >= 10)
{ {
out.printerr("Forgetting job %d (%s): holder building has too many jobs.", out.printerr("Forgetting job %d (%s): holder building has too many jobs.",
pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type)); pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type).c_str());
forget_job(out, pj); forget_job(out, pj);
return true; return true;
} }
@ -534,7 +534,7 @@ static bool recover_job(color_ostream &out, ProtectedJob *pj)
deleteJobStruct(recovered); deleteJobStruct(recovered);
out.printerr("Inconsistency: job %d (%s) already in list.", out.printerr("Inconsistency: job %d (%s) already in list.",
pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type)); pj->id, ENUM_KEY_STR(job_type, pj->job_copy->job_type).c_str());
return true; return true;
} }
@ -1283,7 +1283,7 @@ static void update_jobs_by_constraints(color_ostream &out)
if (ct->material.isValid()) if (ct->material.isValid())
info = ct->material.toString() + " " + info; info = ct->material.toString() + " " + info;
else if (ct->mat_mask.whole) else if (ct->mat_mask.whole)
info = bitfieldToString(ct->mat_mask) + " " + info; info = bitfield_to_string(ct->mat_mask) + " " + info;
if (is_running != ct->is_active) if (is_running != ct->is_active)
{ {
@ -1337,7 +1337,7 @@ static std::string shortJobDescription(df::job *job)
if (mat.isValid()) if (mat.isValid())
rv += " [" + mat.toString() + "]"; rv += " [" + mat.toString() + "]";
else if (mat_mask.whole) else if (mat_mask.whole)
rv += " [" + bitfieldToString(mat_mask) + "]"; rv += " [" + bitfield_to_string(mat_mask) + "]";
return rv; return rv;
} }