/* core/commandbuffer.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include #include #include #include #include "auxiliary/functions.h" #include "sys/sys.h" #include "filesystem/filesystem.h" #include "core/application.h" #include "core/commandbuffer.h" #include "core/gameconnection.h" #include "core/func.h" #include "core/info.h" #include "core/item.h" #include "core/cvar.h" #include "core/loader.h" #include "core/zone.h" namespace core { std::stringstream CommandBuffer::cmdbuf(std::stringstream::in | std::stringstream::out); void func_print(std::string const &args) { con_print << args << "\n"; } void func_print_file(std::string const &args) { std::istringstream argstream(args); std::string filename; if (!(argstream >> filename)) return; 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(); } void func_list_var(std::string const &args) { Cvar::list(); } void func_list_ent(std::string const &args) { Entity::list(); } void func_list_zone(std::string const &args) { Zone *zone = Zone::search(args); if (zone) { zone->print(); } else { Zone::list(); } } void func_list_model(std::string const &args) { model::Model::list(); } void func_list_module(std::string const &args) { Loader::list(); } void func_list_item(std::string const &args) { Item::list(); } void func_set(std::string const &args) { std::istringstream argstream(args); std::string varname; if (!(argstream >> varname)) { con_print << "Variable name expected!" << std::endl; return; } aux::to_lowercase(varname); std::string value; if (!(argstream >> value)) { Cvar *cvar = Cvar::find(varname); if (cvar) { con_print << " " << varname << " " << cvar->str() << " ^N" << cvar->info() << "\n"; } return; } char c; while (argstream.get(c)) value += c; Cvar *cvar = Cvar::set(varname.c_str(), value.c_str(), Cvar::Archive); if (cvar->flags() && Cvar::Info) { localplayer()->set_dirty(); } con_debug << " " << cvar->name() << " " << cvar->str() << "\n"; } void func_toggle(std::string const &args) { std::istringstream argstream(args); std::string varname; if (!(argstream >> varname)) { con_print << "Variable name expected!" << std::endl; return; } aux::to_lowercase(varname); Cvar *cvar = Cvar::find(varname); if (!cvar) { con_print << "Unknown variable '" << varname << "'\n"; return; } float valueone = 1.0f; if (!(argstream >> valueone)) { valueone = 1.0f; } if (cvar->value()) { (*cvar) = 0.0f; } else { (*cvar) = valueone; } if (cvar->flags() && Cvar::Info) { localplayer()->set_dirty(); } con_debug << " " << cvar->name() << " " << cvar->str() << "\n"; } void func_exec(std::string const &args) { std::istringstream argstream(args); std::string filename; if (!(argstream >> filename)) return; CommandBuffer::exec_file(filename); } 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() { //con_debug << "Initializing command buffer...\n"; Func *func = 0; func = Func::add("list_ent", (FuncPtr)func_list_ent); func->set_info("list entities"); 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 info records"); func = Func::add("list_item", (FuncPtr)func_list_item); func->set_info("list item types"); func = Func::add("list_var", (FuncPtr)func_list_var); func->set_info("list variables"); func = Func::add("list_zone", (FuncPtr)func_list_zone); func->set_info("list zones"); Func::add("list_model", (FuncPtr) func_list_model); func->set_info("list models"); Func::add("list_module", (FuncPtr) func_list_module); func->set_info("list game modules"); func = Func::add("set", (FuncPtr)func_set); func->set_info("[variable] [str] set variable value"); func = Func::add("toggle", (FuncPtr)func_toggle); func->set_info("[variable] toggle a variable"); func = Func::add("print", func_print); func->set_info("[str] print a message on the console"); func = Func::add("print_file", func_print_file); func->set_info("[filename] print messages from file"); 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() { //con_debug << "Shutting down command buffer...\n"; Func::remove("set"); 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"); Func::remove("list_zone"); Func::remove("print"); Func::remove("print_file"); Func::remove("exec"); } void CommandBuffer::exec(std::string const &cmdline) { if (!cmdline.size()) return; std::istringstream cmdstream(cmdline); std::string command; if (!(cmdstream >> command)) return; aux::to_lowercase(command); //con_debug << "Executing '" << cmdline << "'\n"; if ((command[0] == '\\') || (command[0] == '/')) { command.erase(0, 1); } // is it a function Func *f = Func::find(command); if (f) { // console can not execute game functions, and neither should rcon if ((f->flags() & Func::Game) && (Cvar::sv_dedicated->value() == 0)) { if (application()->connected()) { if ((f->flags() & Func::Target)) { // target function unsigned int id = 0; if ((cmdstream >> id)) { //con_debug << "target function " << command << " " << id << std::endl; Entity *entity = Entity::find(id); if (entity) f->exec(game()->localplayer(), entity); } } else { // game function std::string args; char c; if (cmdstream >> args) { while (cmdstream.get(c)) args += c; } f->exec(game()->localplayer(), args); } } } else { // regular function std::string args; char c; if (cmdstream >> args) { while (cmdstream.get(c)) args += c; } f->exec(args); } return; } // is it a cvar Cvar *cvar = Cvar::find(command); if (cvar) { // cvar exists std::string value; if (((cvar->flags() & Cvar::ReadOnly) == 0) && (cmdstream >> value)) { // we're setting a new value char c; while (cmdstream.get(c)) value += c; (*cvar) = value; if (cvar->flags() && Cvar::Info) { localplayer()->set_dirty(); } } con_print << " " << command << " " << cvar->str() << " ^N" << cvar->info() << "\n"; return; } // this gets forwarded to the server if (connection()) { if ((cmdline[0] == '\\') || (cmdline[0] == '/')) { connection()->forward(cmdline.substr(1, cmdline.size() - 1)); } else { connection()->forward(cmdline); } } else { con_print << "Unknown command '" << command << "^N'\n"; } } void CommandBuffer::exec() { if (cmdbuf.eof()) return; std::string line; char c; bool quote = false; while (core::cmd().read(&c , 1) && c) { if (c == '\n') { exec(line); line.clear(); } else if (c == '"') { quote = !quote; } else if ((c == ';') && !quote) { exec(line); line.clear(); } else { line += c; } } if (line.size()) exec(line); cmdbuf.clear(); } void CommandBuffer::complete(std::string &input, size_t &pos) { std::list match; size_t start = 0; if (input.c_str()[0] == '/' || input.c_str()[0] == '\\') start = 1; std::string partial = input.substr(start, pos); if (!partial.size()) return; aux::to_lowercase(partial); // search function registry for matches for (Func::Registry::iterator f = Func::registry().begin(); f != Func::registry().end(); f++) { if (partial == (*f).first.substr(0, partial.size())) { match.push_back((*f).first); //con_print << " " << (*f).first << "\n"; } } // search cvar registry for matches for (Cvar::Registry::iterator c = Cvar::registry().begin(); c != Cvar::registry().end(); c++) { if (partial == (*c).first.substr(0, partial.size())) { match.push_back((*c).first); //con_print << " " << (*c).first << "\n"; } } if (!match.size()) return; std::string maxmatch(*match.begin()); if (match.size() > 1) { std::list::iterator l; for (l = match.begin(); l != match.end(); l++) { if (maxmatch.size()) { size_t i = 0; while ((i < maxmatch.size() && i < (*l).size()) && (maxmatch[i] == (*l)[i])) { i++; } if (i < maxmatch.size()) maxmatch.erase(i); } con_print << " " << (*l) << "\n"; } con_print << match.size() << " matches\n"; } if (maxmatch.size() > partial.size()) { if (match.size() == 1) maxmatch += ' '; input.replace(start, pos, maxmatch); pos = maxmatch.size(); } } void CommandBuffer::exec_file(std::string const & filename) { filesystem::File *f = filesystem::open(filename.c_str()); if (!f) { con_warn << "Could not open " << filename << std::endl; return; } std::string fn = f->path(); fn.append(f->name()); filesystem::close(f); std::ifstream ifs; ifs.open(fn.c_str()); if (!ifs.is_open()) { con_warn << "Could not stream " << fn << "!\n"; return; } con_print << "Executing " << fn.c_str() << std::endl; char line[MAXCMDSIZE]; while (ifs.getline(line, MAXCMDSIZE - 1)) { if (line[0] && line[0] != '#' && line[0] != ';') exec(std::string(line)); } ifs.close(); } void CommandBuffer::print_file(std::string const & filename) { filesystem::File *f = filesystem::open(filename.c_str()); if (!f) { con_warn << "Could not open " << filename << std::endl; return; } std::string fn = f->path(); fn.append(f->name()); filesystem::close(f); std::ifstream ifs; ifs.open(fn.c_str()); if (!ifs.is_open()) { con_warn << "Could not stream " << fn << "!\n"; return; } char line[MAXCMDSIZE]; while (ifs.getline(line, MAXCMDSIZE - 1)) { con_print << line << "\n"; } ifs.close(); } }