From a95028547981614e06ea7a6d22b853b85418cea3 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Wed, 15 Apr 2009 17:08:51 +0000 Subject: added info registry, list_info added network info transfer added info based buy menu and related game changes --- src/core/Makefile.am | 3 +- src/core/commandbuffer.cc | 33 +++++++- src/core/descriptions.cc | 27 +++++-- src/core/descriptions.h | 9 ++- src/core/gameconnection.cc | 22 ++++++ src/core/gameconnection.h | 3 + src/core/gameinterface.cc | 4 + src/core/gameinterface.h | 8 +- src/core/gameserver.cc | 5 ++ src/core/gameserver.h | 3 + src/core/info.cc | 183 +++++++++++++++++++++++++++++++++++++++++++++ src/core/info.h | 108 ++++++++++++++++++++++++++ src/core/net.h | 2 +- src/core/netconnection.cc | 33 +++++++- src/core/netconnection.h | 4 + src/core/netserver.cc | 30 +++++++- src/core/netserver.h | 4 + 17 files changed, 467 insertions(+), 14 deletions(-) create mode 100644 src/core/info.cc create mode 100644 src/core/info.h (limited to 'src/core') diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 317a99e..af59d00 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -3,7 +3,7 @@ INCLUDES = -I$(top_srcdir)/src libcore_la_SOURCES = application.cc commandbuffer.cc core.cc cvar.cc \ descriptions.cc entity.cc extension.cc func.cc gameconnection.cc gameinterface.cc \ - gameserver.cc loader.cc module.cc netclient.cc netconnection.cc netplayer.cc \ + gameserver.cc info.cc loader.cc module.cc netclient.cc netconnection.cc netplayer.cc \ netserver.cc parser.cc player.cc stats.cc timer.cc zone.cc libcore_la_LDFLAGS = -avoid-version -no-undefined libcore_la_LIBADD = $(top_builddir)/src/model/libmodel.la \ @@ -15,3 +15,4 @@ noinst_HEADERS = application.h commandbuffer.h core.h cvar.h entity.h func.h \ gameconnection.h gameinterface.h gameserver.h message.h module.h net.h netclient.h \ netconnection.h netserver.h player.h range.h stats.h timer.h parser.h descriptions.h \ extension.h loader.h +_SOURCES = info.h diff --git a/src/core/commandbuffer.cc b/src/core/commandbuffer.cc index 21002bd..84b63be 100644 --- a/src/core/commandbuffer.cc +++ b/src/core/commandbuffer.cc @@ -16,6 +16,7 @@ #include "core/commandbuffer.h" #include "core/gameconnection.h" #include "core/func.h" +#include "core/info.h" #include "core/cvar.h" #include "core/loader.h" #include "core/zone.h" @@ -23,6 +24,8 @@ namespace core { +std::stringstream CommandBuffer::cmdbuf(std::stringstream::in | std::stringstream::out); + void func_print(std::string const &args) { con_print << args << "\n"; @@ -38,6 +41,15 @@ void func_print_file(std::string const &args) CommandBuffer::print_file(filename); } +void func_list_info(std::string const &args) +{ + Info *info = Info::find(args); + if (info) + info->print(); + else + Info::list(); +} + void func_list_func(std::string const &args) { Func::list(); @@ -151,7 +163,19 @@ void func_exec(std::string const &args) CommandBuffer::exec_file(filename); } -std::stringstream CommandBuffer::cmdbuf(std::stringstream::in | std::stringstream::out); +void func_remote(std::string const &args) +{ + if (connection()) { + if ((args[0] == '\\') || (args[0] == '/')) { + connection()->forward(args.substr(1, args.size()-1)); + } else { + connection()->forward(args); + } + } else { + cmd() << args; + CommandBuffer::exec(); + } +} void CommandBuffer::init() { @@ -164,6 +188,9 @@ void CommandBuffer::init() func = Func::add("list_func", (FuncPtr)func_list_func); func->set_info("list functions"); + func = Func::add("list_info", (FuncPtr)func_list_info); + func->set_info("list infos"); + func = Func::add("list_var", (FuncPtr)func_list_var); func->set_info("list variables"); @@ -190,6 +217,9 @@ void CommandBuffer::init() func = Func::add("exec", (FuncPtr)func_exec); func->set_info("[filename] execute commands from file"); + + func = Func::add("remote", (FuncPtr)func_remote); + func->set_info("[command] send a command to the game server"); } void CommandBuffer::shutdown() @@ -200,6 +230,7 @@ void CommandBuffer::shutdown() Func::remove("toggle"); Func::remove("list_var"); Func::remove("list_func"); + Func::remove("list_info"); Func::remove("list_ent"); Func::remove("list_model"); Func::remove("list_module"); diff --git a/src/core/descriptions.cc b/src/core/descriptions.cc index fe37d2c..8c0f4ee 100644 --- a/src/core/descriptions.cc +++ b/src/core/descriptions.cc @@ -16,6 +16,7 @@ ButtonDescription::ButtonDescription() { button_model = 0; button_align = Center; + button_commandtype = CommandNone; } ButtonDescription::~ButtonDescription() @@ -27,8 +28,9 @@ void ButtonDescription::set_text(const std::string &text) button_text.assign(text); } -void ButtonDescription::set_command(const std::string &command) +void ButtonDescription::set_command(const std::string &command, const CommandType command_type) { + button_commandtype = command_type; button_command.assign(command); } @@ -85,9 +87,10 @@ void Descriptions::serialize(MenuDescription *menu, std::ostream & os) for (MenuDescription::Buttons::iterator it = menu-> buttons().begin(); it != menu->buttons().end(); it++) { ButtonDescription *button = (*it); - os << "\"" << button->text() << "\" " + os << "\"" << button->text() << "\" " << button->alignment() << " " - << "\"" << button->command() << "\" " + << button->command_type() << " " + << "\"" << button->command() << "\" " << "\"" << button->modelname() << "\" "; } } @@ -97,6 +100,7 @@ MenuDescription * Descriptions::receive(std::istream &is) MenuDescription *menu = new MenuDescription(); int a; + int t; std::string n; size_t nb; char c; @@ -135,12 +139,22 @@ MenuDescription * Descriptions::receive(std::istream &is) else button->set_alignment(ButtonDescription::Center); + // button command type + is >> t; + // button command n.clear(); while ( (is.get(c)) && (c != '"')); while ( (is.get(c)) && (c != '"')) n += c; - if (n.size()) button->set_command(n); + + if (n.size()) { + if (t == ButtonDescription::CommandGame) { + button->set_command(n, ButtonDescription::CommandGame); + } else if (t == ButtonDescription::CommandMenu) { + button->set_command(n, ButtonDescription::CommandMenu); + } + } // button modelname n.clear(); @@ -213,7 +227,10 @@ bool Descriptions::load_entity_menus(core::Entity *entity, const std::string &me if (strval[i] == ',') strval[i] = ';'; } aux::strip_quotes(strval); - button->set_command(strval); + + // default command is a game command + button->set_command(strval, ButtonDescription::CommandGame); + } else if (inifile.got_key_string("model", strval)) { button->set_modelname(strval); } else if (inifile.got_key_string("align", strval)) { diff --git a/src/core/descriptions.h b/src/core/descriptions.h index 345d354..dec7896 100644 --- a/src/core/descriptions.h +++ b/src/core/descriptions.h @@ -28,6 +28,8 @@ class ButtonDescription public: enum Align {Center=0, Left=1, Right=2}; + enum CommandType {CommandNone=0, CommandGame=1, CommandMenu=2}; + ButtonDescription(); ~ButtonDescription(); @@ -36,6 +38,9 @@ public: /// button text inline const std::string & text() const { return button_text; } + /// button command type + inline const CommandType command_type() const {return button_commandtype; } + /// button command inline const std::string & command() const { return button_command; } @@ -54,7 +59,7 @@ public: void set_text(const std::string &text); /// set button command - void set_command(const std::string &command); + void set_command(const std::string &command, const CommandType command_type); /// set button name void set_modelname(const std::string &modelname); @@ -64,10 +69,10 @@ public: private: std::string button_text; + CommandType button_commandtype; std::string button_command; std::string button_modelname; Align button_align; - model::Model *button_model; }; diff --git a/src/core/gameconnection.cc b/src/core/gameconnection.cc index c2763ee..2dc0e32 100644 --- a/src/core/gameconnection.cc +++ b/src/core/gameconnection.cc @@ -74,6 +74,28 @@ GameConnection::~GameConnection() connection_instance = 0; } +Info *GameConnection::info(const std::string &label) +{ + // check if we already have the info record + Info *info = Info::find(label); + if (info) + return info; + + // create a new information record and set the label + info = new Info(label); + Info::add(info); + + info->text().push_back("Requesting information..."); + + // send an information request to the server + if (connection_network) { + connection_network->send_info_request(info); + } else { + info->text().push_back("^RNot connected."); + } + return info; +} + void GameConnection::abort() { connection_running = false; diff --git a/src/core/gameconnection.h b/src/core/gameconnection.h index e1a7008..5880f9b 100644 --- a/src/core/gameconnection.h +++ b/src/core/gameconnection.h @@ -51,6 +51,9 @@ public: /// localplayer sends a private message to another player void private_message(std::string const &args); + /// returns an info record + Info *info(const std::string &label); + /*----- static ---------------------------------------------------- */ /// return the current game connection diff --git a/src/core/gameinterface.cc b/src/core/gameinterface.cc index f658619..0ade34b 100644 --- a/src/core/gameinterface.cc +++ b/src/core/gameinterface.cc @@ -12,6 +12,7 @@ #include "core/application.h" #include "core/cvar.h" #include "core/func.h" +#include "core/info.h" #include "core/gameinterface.h" #include "core/player.h" #include "core/zone.h" @@ -120,6 +121,9 @@ void GameInterface::clear() // remove all models model::Model::clear(); + // remove infos + Info::clear(); + // clear player list for (Players::iterator it = game_players.begin(); it != game_players.end(); it++) { Player *player = (*it); diff --git a/src/core/gameinterface.h b/src/core/gameinterface.h index 22b85d5..8dc401b 100644 --- a/src/core/gameinterface.h +++ b/src/core/gameinterface.h @@ -8,6 +8,7 @@ #define __INCLUDED_CORE_GAMEINTERFACE_H__ #include "core/player.h" +#include "core/info.h" namespace core { @@ -38,6 +39,9 @@ public: /// show a list of connected players void list_players(); + /// return the current game time, in seconds + float time() const { return ((float)(timestamp()) / 1000.0f); } + /*----- virtual inspectors --------------------------------------- */ /// returns true if the game server can run a time frime @@ -49,8 +53,8 @@ public: /// return the current game time virtual unsigned long timestamp() const = 0; - /// return the current game time, in seconds - float time() const { return ((float)(timestamp()) / 1000.0f); } + /// returns an info record + virtual Info *info(const std::string &label) = 0; /*----- mutators ------------------------------------------------- */ diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc index fc7a814..b82946b 100644 --- a/src/core/gameserver.cc +++ b/src/core/gameserver.cc @@ -226,6 +226,11 @@ GameServer::~GameServer() server_instance = 0; } +Info *GameServer::info(const std::string &label) +{ + return Info::find(label); +} + void GameServer::abort() { server_running = false; diff --git a/src/core/gameserver.h b/src/core/gameserver.h index 31cfca6..ac5f19e 100644 --- a/src/core/gameserver.h +++ b/src/core/gameserver.h @@ -77,6 +77,9 @@ public: /// time the server was started inline const unsigned long startup() const { return server_startup; } + /// returns an info record + Info *info(const std::string &label); + /*----- static ---------------------------------------------------- */ /// return the current game server diff --git a/src/core/info.cc b/src/core/info.cc new file mode 100644 index 0000000..fc10fe5 --- /dev/null +++ b/src/core/info.cc @@ -0,0 +1,183 @@ +/* + core/info.xx + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#include "auxiliary/functions.h" +#include "core/info.h" +#include "sys/sys.h" + +namespace core +{ + +Info::Registry Info::registry; + +Info::Info(const std::string & label) +{ + info_label.assign(label); + aux::to_lowercase(info_label); + aux::strip_quotes(info_label); + info_timestamp = 0; +} + +void Info::set_name(const std::string & name) +{ + info_name.assign(name); +} + +void Info::set_name(const char *name) +{ + info_name.assign(name); +} + +void Info::set_modelname(const std::string & modelname) +{ + info_modelname.assign(modelname); +} + +void Info::set_modelname(const char *modelname) +{ + info_modelname.assign(modelname); +} + +void Info::set_timestamp(const unsigned long timestamp) +{ + info_timestamp = timestamp; +} + +void Info::clear_timestamp() +{ + info_timestamp = 0; +} + +void Info::add_text(const char *text) +{ + std::string str(text); + aux::strip_quotes(str); + info_text.push_back(str); +} + +void Info::add_text(const std::string & text) +{ + add_text(text.c_str()); +} + +void Info::clear_text() +{ + info_text.clear(); +} + +void Info::serialize_server_update(std::ostream & os) const +{ + os << '"' << name() << "\" \"" << modelname() << "\" " << info_text.size() << " "; + + for (Text::const_iterator it = info_text.begin(); it != info_text.end(); it++) { + if (it != info_text.begin()) + os << ' '; + + os << '"' << (*it) << '"'; + } +} + +void Info::receive_server_update(std::istream &is) +{ + std::string n; + char c; + + // read name + while ( (is.get(c)) && (c != '"')); + while ( (is.get(c)) && (c != '"')) + n += c; + info_name.assign(n); + + // read model name + n.clear(); + while ( (is.get(c)) && (c != '"')); + while ( (is.get(c)) && (c != '"')) + n += c; + + info_modelname.assign(n); + + // read info text + size_t s; + info_text.clear(); + is >> s; + for (size_t i = 0; (i < s) && is.good(); i++) { + n.clear(); + while ( (is.get(c)) && (c != '"')); + while ( (is.get(c)) && (c != '"')) + n += c; + + info_text.push_back(n); + } +} + +Info::~Info() +{ + info_text.clear(); + info_modelname.clear(); + info_text.clear(); +} + +void Info::print() const +{ + con_print << "label: ^B" << label() << " ^Nname: ^B" << name() << "^N" << std::endl; + + for (Text::const_iterator it = info_text.begin(); it != info_text.end(); it++) { + con_print << " " << (*it) << std::endl; + } +} + +/* ---- static info registry --------------------------------------- */ + +void Info::add(Info *info) +{ + if (find(info->label())) + return; + + registry[info->label()] = info; +} + +Info *Info::find(const char *label) +{ + for (Registry::iterator it = registry.begin(); it != registry.end(); it++) { + Info *info = (*it).second; + if (info->label().compare(label) == 0) { + return info; + } + } + return 0; +} + +Info *Info::find(const std::string & label) +{ + for (Registry::iterator it = registry.begin(); it != registry.end(); it++) { + Info *info = (*it).second; + if (info->label().compare(label) == 0) { + return info; + } + } + return 0; +} + +void Info::clear() +{ + for (Registry::iterator it = registry.begin(); it != registry.end(); it++) { + Info *info = (*it).second;; + delete info; + } + registry.clear(); +} + +void Info::list() +{ + for (Registry::iterator it = registry.begin(); it != registry.end(); it++) { + Info *info = (*it).second;; + con_print << info->label() << std::endl; + } + con_print << registry.size() << " registered infos" << std::endl; +} + +} + diff --git a/src/core/info.h b/src/core/info.h new file mode 100644 index 0000000..cc480bf --- /dev/null +++ b/src/core/info.h @@ -0,0 +1,108 @@ +/* + core/info.h + This file is part of the Osirion project and is distributed under + the terms of the GNU General Public License version 2 +*/ + +#ifndef __INCLUDED_CORE_INFO_H__ +#define __INCLUDED_CORE_INFO_H__ + +#include +#include +#include +#include + +#include "model/model.h" + +namespace core +{ + +/** + * an information record + */ +class Info +{ +public: + /// create a new labeled information record + Info(const std::string & label); + /// delete the information record + ~Info(); + + typedef std::deque Text; + + inline const std::string & label() const { return info_label; } + + inline const std::string & name() const { return info_name; } + + inline const std::string & modelname() const { return info_modelname; } + + inline const unsigned long ×tamp() const { return info_timestamp; } + + inline Text & text() { return info_text; } + + void set_name(const std::string & name); + + void set_name(const char *name); + + void set_modelname(const std::string & modelname); + + void set_modelname(const char *modelname); + + /// set the timestamp + void set_timestamp(const unsigned long timestamp); + + /// clear the timestamp + void clear_timestamp(); + + /// add a line of info text + void add_text(const char *text); + + /// add a line of info text + void add_text(const std::string & text); + + /// clear the info text + void clear_text(); + + /// print info to sys::con_out + void print() const; + + /// serialize a server-to-client update on a stream + void serialize_server_update(std::ostream & os) const; + + /// receive a server-to-client update from a stream + void receive_server_update(std::istream &is); + +/* ---- static info registry --------------------------------------- */ + + typedef std::map Registry; + + /// add an item to the info regsitry + static void add(Info *info); + + /// search the info registry for a labeled item + static Info *find(const char * label); + + /// search the info registry for a labeled item + static Info *find(const std::string & label); + + /// clear the info registry + static void clear(); + + /// list the info registry + static void list(); + +private: + std::string info_label; + std::string info_name; + std::string info_modelname; + Text info_text; + + long info_credits; + static Registry registry; + + unsigned long info_timestamp; +}; + +} +#endif // __INCLUDED_CORE_INFO_H__ + diff --git a/src/core/net.h b/src/core/net.h index 887bf1b..01c15be 100644 --- a/src/core/net.h +++ b/src/core/net.h @@ -11,7 +11,7 @@ namespace core { /// network protocol version -const unsigned int PROTOCOLVERSION = 15; +const unsigned int PROTOCOLVERSION = 16; /// maximum lenght of a (compressed) network message block const unsigned int FRAMESIZE = 1152; diff --git a/src/core/netconnection.cc b/src/core/netconnection.cc index fc2b6bf..dfb86f7 100644 --- a/src/core/netconnection.cc +++ b/src/core/netconnection.cc @@ -410,6 +410,16 @@ void NetConnection::send_ping_reply(unsigned long timestamp) this->send_raw(msg.str()); } +// send an info record request +void NetConnection::send_info_request(Info *info) +{ + std::ostringstream msg; + msg << "inf " << '"' << info->label() << '"' << '\n'; + this->send_raw(msg.str()); + + info->set_timestamp(application()->timestamp()); +} + // parse incoming client messages /** * The following incoming messages are parsed; @@ -674,7 +684,28 @@ void NetConnection::parse_incoming_message(const std::string & message) return; } } - + } else if (command == "inf") { + + // incoming info record + std::string label; + char c; + + while ( (msgstream.get(c)) && (c != '"')); + while ( (msgstream.get(c)) && (c != '"')) + label += c; + + if (label.size()) { + Info *info = Info::find(label); + if (!info) { + info = new Info(label); + Info::add(info); + } + + info->receive_server_update(msgstream); + info->clear_timestamp(); + } else { + con_warn << "Received empty information record!" << std::endl; + } } else if (command == "sup") { if (connection_state == Connected) { diff --git a/src/core/netconnection.h b/src/core/netconnection.h index a17b35d..7c0b23d 100644 --- a/src/core/netconnection.h +++ b/src/core/netconnection.h @@ -30,6 +30,7 @@ #include "core/entity.h" #include "core/net.h" +#include "core/info.h" namespace core { @@ -71,6 +72,9 @@ public: /// send a console command to the remote server void send_rcon(std::string const &cmdline); + /// send an info request + void send_info_request(Info *info); + /// transmit messages in the send queue to the remote server void transmit(); diff --git a/src/core/netserver.cc b/src/core/netserver.cc index 62d9b74..5b3a991 100644 --- a/src/core/netserver.cc +++ b/src/core/netserver.cc @@ -525,7 +525,7 @@ void NetServer::send_player_update(NetClient *client) void NetServer::send_player_update(NetClient *client, Player *player) { std::ostringstream msg; - msg << "pif " << player->id() << " "; + msg << "pif " << player->id() << ' '; client->player()->serialize_server_update(msg); msg << '\n'; client->send_raw(msg.str()); @@ -539,6 +539,16 @@ void NetServer::send_player_disconnect_info(NetClient *client, Player *player) client->send_raw(msg.str()); } +// send a "inf" info record +void NetServer::send_info_update(NetClient *client, Info *info) +{ + std::ostringstream msg; + msg << "inf " << '"' << info->label() << '"' << ' '; + info->serialize_server_update(msg); + msg << '\n'; + client->send_raw(msg.str()); +} + // parse incoming client messages /** @@ -547,6 +557,7 @@ void NetServer::send_player_disconnect_info(NetClient *client, Player *player) * disconnect * cmd * cup + * inf * pif * ping * say @@ -641,6 +652,23 @@ void NetServer::parse_incoming_message(NetClient *client, const std::string & me return; } + if (command == "inf") { + std::string n; + char c; + + while ( (msgstream.get(c)) && (c != '"')); + while ( (msgstream.get(c)) && (c != '"')) + n += c; + + if (n.size()) { + Info *info = Info::find(n); + if (info) { + send_info_update(client, info); + client->transmit(); + } + } + } + if (command == "rcon") { if ((message.size() > command.size()+1) && Cvar::sv_password->str().size()) { if ((Cvar::sv_password->str().compare(client->player()->rconpassword()) == 0)) { diff --git a/src/core/netserver.h b/src/core/netserver.h index 9ef0f0d..e54ea2e 100644 --- a/src/core/netserver.h +++ b/src/core/netserver.h @@ -19,6 +19,7 @@ #include "core/net.h" #include "core/netclient.h" #include "core/player.h" +#include "core/info.h" namespace core { @@ -92,6 +93,9 @@ protected: /// send player disconnect information message void send_player_disconnect_info(NetClient *client, Player *player); + /// send player an info record + void send_info_update(NetClient *client, Info *info); + /// set the error state void abort(); -- cgit v1.2.3