diff options
38 files changed, 751 insertions, 374 deletions
@@ -123,6 +123,9 @@ game: docking jumpgates (required docking) +data: + rename skies (lindblade1, lindblade2, ...) + win32 port: network (ok) texture loading (ok) diff --git a/osirion.kdevelop b/osirion.kdevelop index c94d33e..d40c050 100644 --- a/osirion.kdevelop +++ b/osirion.kdevelop @@ -21,7 +21,7 @@ </general> <kdevautoproject> <general> - <activetarget>src/server/libserver.la</activetarget> + <activetarget>src/core/libcore.la</activetarget> <useconfiguration>debug</useconfiguration> </general> <run> diff --git a/src/auxiliary/functions.cc b/src/auxiliary/functions.cc index 860524a..8cefbc5 100644 --- a/src/auxiliary/functions.cc +++ b/src/auxiliary/functions.cc @@ -165,4 +165,13 @@ void to_label(std::string &text) } } +void strip_quotes(std::string &text) +{ + for (size_t pos = 0; pos < text.size(); pos++) { + if (text[pos] == '"') { + text[pos] = '\''; + } + } +} + } diff --git a/src/auxiliary/functions.h b/src/auxiliary/functions.h index fccb4dc..d5b590d 100644 --- a/src/auxiliary/functions.h +++ b/src/auxiliary/functions.h @@ -55,6 +55,9 @@ const std::string text_strip_lowercase(const std::string &text); /// trim leading ad trailing spaces from a string void trim(std::string &text); +/// replaces double quotes by single quotes +void strip_quotes(std::string &text); + /// convert a string to a valid label string /** trim leading and trealing spaces, convert remaining spaces to underscores, and make lowercase * remove any non-alphanumeric character diff --git a/src/client/client.cc b/src/client/client.cc index 7ba61d6..a8d4ca8 100644 --- a/src/client/client.cc +++ b/src/client/client.cc @@ -19,6 +19,8 @@ #include "client/input.h" #include "client/view.h" #include "core/core.h" +#include "core/zone.h" +#include "render/render.h" namespace client { @@ -181,6 +183,8 @@ void Client::shutdown() { con_print << "^BShutting down client..." << std::endl; + if (connected()) disconnect(); + core::Func::remove("r_restart"); core::Func::remove("snd_restart"); @@ -210,34 +214,49 @@ void Client::notify_remove_sound(size_t source) audio::Sources::remove(source); } -void Client::notify_message(std::string const & message) +void Client::notify_message(core::Message::Channel const channel, std::string const message) { - con_print << message << std::endl; + + switch(channel) { + + case core::Message::Info: // Info message + break; + + case core::Message::Local: // Chat message in the local zone + break; + + case core::Message::RCon: // RCon message + break; + + case core::Message::Public: // Public chat message + audio::play("com/chat"); + break; + + case core::Message::Private: // Private chat message + audio::play("com/priv"); + break; + + default: + break; + } + + con_print << message << std::endl; console()->notify(message); } void Client::notify_zoneclear(core::Zone *zone) { - // FIXME unload zone textures - /* if (!zone) return; - for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content.end(); i++) { - core:: Entity *entity = (*it); - - if (entity->type() == core::Entity::Globe) { - core::EntityGlobe *globe = static_cast<core::EntityGlobe *>(entity); - if (globe->render_texture) - render::Textures::unload(render_texture); - - } + view::clear_zone(zone); +} - if (zone->sky_texture()) { - render::Textures::unload(zone->sky_texture()); - zone->set_sky_texture(0); - } - */ +void Client::notify_disconnect() +{ + // FIXME unload sounds + + render::unload(); } } // namespace client diff --git a/src/client/client.h b/src/client/client.h index 664bbb4..6da5c5f 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -32,13 +32,16 @@ public: virtual void notify_sound(const char * name); /// text notifications from the core - virtual void notify_message(std::string const & message); + virtual void notify_message(core::Message::Channel const channel, std::string const message); /// remove sound source notification virtual void notify_remove_sound(size_t source); /// clear zone notification virtual void notify_zoneclear(core::Zone *zone); + + /// disconnect notification + virtual void notify_disconnect(); }; diff --git a/src/client/targets.cc b/src/client/targets.cc index a18392f..4764245 100644 --- a/src/client/targets.cc +++ b/src/client/targets.cc @@ -42,7 +42,9 @@ bool is_legal_target(core::Entity *entity) { if (entity->serverside()) { return false; - } else if (entity->id() == core::localcontrol()->id()) { + } else if (entity == core::localplayer()->mission_target()) { + return true; + } else if (entity == core::localcontrol()) { return false; } else if (entity->state()->distance() < 0.001f) { return false; diff --git a/src/client/view.cc b/src/client/view.cc index 8cf1af9..bbf9088 100644 --- a/src/client/view.cc +++ b/src/client/view.cc @@ -18,13 +18,8 @@ #include "client/input.h" #include "client/targets.h" #include "client/video.h" -#include "render/draw.h" #include "render/render.h" -#include "render/textures.h" -#include "render/camera.h" #include "core/core.h" -#include "core/stats.h" -#include "core/zone.h" #include "math/mathlib.h" #include "sys/sys.h" @@ -38,6 +33,7 @@ core::Cvar *draw_keypress = 0; core::Cvar *ui_pointercolor = 0; core::Cvar *ui_pointerhovercolor =0; + namespace view { @@ -50,6 +46,8 @@ float net_counter_time[net_counter_size]; size_t net_counter_traffic[net_counter_size]; size_t net_counter_index; +core::Zone *current_zone = 0; + void init() { draw_stats = core::Cvar::get("draw_stats", "0", core::Cvar::Archive); @@ -84,6 +82,26 @@ void shutdown() targets::shutdown(); } +void clear_zone(core::Zone *zone) +{ + for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { + core:: Entity *entity = (*it); + + if (entity->type() == core::Entity::Globe) { + core::EntityGlobe *globe = static_cast<core::EntityGlobe *>(entity); + if (globe->render_texture) { + render::Textures::unload(globe->render_texture); + globe->render_texture = 0; + } + } + } + + if (zone->sky_texture()) { + render::Textures::unload(zone->sky_texture()); + zone->set_sky_texture(0); + } +} + void draw_loader() { using namespace render; @@ -219,10 +237,12 @@ void draw_entity_offscreen_target(core::Entity *entity, bool is_active_target) glVertex3f(cx, cy-r+2, 0); render::gl::end(); - if (entity->type() == core::Entity::Controlable) { - render::gl::color(0, 1, 0, 1); + if (entity == core::localplayer()->mission_target()) { + render::gl::color(1, 0.5f, 1, 1); // FIXME mission color + } else if (entity->type() == core::Entity::Controlable) { + render::gl::color(0, 1, 0, 1); // FIXME allegiance color } else { - render::gl::color(1, 1, 1, 1); + render::gl::color(1, 1, 1, 1); // FIXME neutral color } render::gl::begin(render::gl::LineLoop); @@ -279,11 +299,14 @@ void draw_entity_target(core::Entity *entity, bool is_active_target) glVertex3f(cx, cy-r+2, 0); render::gl::end(); - if (entity->type() == core::Entity::Controlable) { - render::gl::color(0, 1, 0, 1); + if (entity == core::localplayer()->mission_target()) { + render::gl::color(1, 0.5f, 1, 1); // FIXME mission color + } else if (entity->type() == core::Entity::Controlable) { + render::gl::color(0, 1, 0, 1); // FIXME allegiance color } else { - render::gl::color(1, 1, 1, 1); + render::gl::color(1, 1, 1, 1); // FIXME neutral color } + // outer square0 render::gl::begin(render::gl::LineLoop); glVertex3f(cx+r, cy, 0); @@ -391,7 +414,9 @@ void draw_status() core::Entity *entity = (*it); if (targets::is_legal_target(entity)) { - if (entity == targets::current()) { + if (entity == core::localplayer()->mission_target()) { + draw_entity_target(entity, true); + } else if (entity == targets::current()) { draw_entity_target(entity, true); } else if (entity->type() == core::Entity::Controlable) { draw_entity_target(entity, false); @@ -716,11 +741,20 @@ void frame(float seconds) render::Stats::clear(); if (core::application()->connected() && core::game()->serverframetime()) { + + if (core::localplayer()->zone() != current_zone) { + if (current_zone) + clear_zone(current_zone); + current_zone = core::localplayer()->zone(); + } + render::draw(seconds); // draw the world targets::draw(); // validate current target, render sound if (targets::current()) // draw target docks etc draw_entity_world_target(targets::current()); + } else { + current_zone = 0; } // switch to orthographic projection to draw the GUI diff --git a/src/client/view.h b/src/client/view.h index d9e44ab..1f81597 100644 --- a/src/client/view.h +++ b/src/client/view.h @@ -6,6 +6,8 @@ #ifndef __INCLUDED_CLIENT_VIEW_H__ #define __INCLUDED_CLIENT_VIEW_H__ +#include "core/zone.h" + namespace client { @@ -24,6 +26,9 @@ namespace view /// reset OpenGL state void reset(); + /// clear client-side assets of a zone + void clear_zone(core::Zone *zone); + } // namespace view } // namespace client diff --git a/src/core/Makefile.am b/src/core/Makefile.am index 802234e..8c44d13 100644 --- a/src/core/Makefile.am +++ b/src/core/Makefile.am @@ -12,6 +12,5 @@ libcore_la_LIBADD = $(top_builddir)/src/model/libmodel.la \ noinst_LTLIBRARIES = libcore.la noinst_HEADERS = application.h clientstate.h commandbuffer.h core.h cvar.h \ - entity.h func.h gameconnection.h gameinterface.h gameserver.h module.h net.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 - diff --git a/src/core/application.cc b/src/core/application.cc index 21d5e50..6207a0d 100644 --- a/src/core/application.cc +++ b/src/core/application.cc @@ -70,6 +70,16 @@ void func_say(std::string const &args) } } +void func_msg(std::string const &args) +{ + if (connection()) { + connection()->private_message(args); + } else if (server()) { + server()->private_message(localplayer(), args); + } else { + con_print << "Not connected." << std::endl; + } +} // --------------- signal_handler ----------------------------------- #ifndef _WIN32 @@ -222,6 +232,9 @@ void Application::init(int count, char **arguments) func = Func::add("say",func_say); func->set_info("say [text] say something on the public chat"); + + func = Func::add("msg",func_msg); + func->set_info("msg [player] [text] send a private message to another player"); } void Application::shutdown() @@ -299,6 +312,7 @@ void Application::connect(std::string const &host) void Application::disconnect() { if(application_game) { + notify_disconnect(); delete application_game; application_game = 0; con_print << "^BDisconnected.\n"; @@ -446,6 +460,11 @@ void Application::load_commandline(int count, char **arguments) cmd() << '\n'; } +void Application::notify_message(Message::Channel const channel, std::string const message) +{ + con_print << message << std::endl; +} + void Application::notify_sound(const char *name) { // the default implementation does nothing. @@ -458,15 +477,17 @@ void Application::notify_remove_sound(size_t source) // Dedicated servers don't need sounds } -void Application::notify_message(std::string const & message) +void Application::notify_zoneclear(Zone *zone) { - con_print << message << std::endl; + // the default implementation does nothing. + // The client uses this to clear old zones } -void Application::notify_zoneclear(Zone *zone) +void Application::notify_disconnect() { // the default implementation does nothing. - // The client uses this to clear old zones + // The client uses this to clear game data + } } diff --git a/src/core/application.h b/src/core/application.h index ef89e70..0dfa652 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -9,6 +9,7 @@ #include "sys/sys.h" #include "core/commandbuffer.h" +#include "core/message.h" #include "core/netserver.h" #include "core/netconnection.h" #include "core/gameinterface.h" @@ -62,7 +63,7 @@ public: virtual void notify_sound(const char * name); /// text notifications from the core to the application - virtual void notify_message(std::string const & message); + virtual void notify_message(Message::Channel const channel, std::string const message); /// remove sound source notification virtual void notify_remove_sound(size_t source); @@ -70,6 +71,9 @@ public: /// zone clear notification virtual void notify_zoneclear(Zone *zone); + /// disconnect notification + virtual void notify_disconnect(); + /*----- static --------------------------------------------------- */ /// a pointer to the current application instance diff --git a/src/core/commandbuffer.cc b/src/core/commandbuffer.cc index c111e17..5ed3787 100644 --- a/src/core/commandbuffer.cc +++ b/src/core/commandbuffer.cc @@ -64,6 +64,11 @@ void func_list_zone(std::string const &args) } } +void func_list_model(std::string const &args) +{ + model::Model::list(); +} + void func_set(std::string const &args) { std::istringstream argstream(args); @@ -160,6 +165,9 @@ void CommandBuffer::init() 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 = Func::add("set", (FuncPtr)func_set); func->set_info("[variable] [str] set variable value"); @@ -185,6 +193,7 @@ void CommandBuffer::shutdown() Func::remove("list_var"); Func::remove("list_func"); Func::remove("list_ent"); + Func::remove("list_model"); Func::remove("list_zone"); Func::remove("print"); Func::remove("print_file"); @@ -205,6 +214,10 @@ void CommandBuffer::exec(std::string const &cmdline) 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) { @@ -248,10 +261,15 @@ void CommandBuffer::exec(std::string const &cmdline) } // this gets forwarded to the server - if (connection()) - connection()->forward(cmdline); - else + 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() diff --git a/src/core/core.h b/src/core/core.h index feca5fd..80f6d54 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -18,6 +18,7 @@ #include "core/module.h" #include "core/player.h" #include "core/range.h" +#include "core/stats.h" #include "core/zone.h" /// core contains the basic functionality of the engine diff --git a/src/core/gameconnection.cc b/src/core/gameconnection.cc index ef998e6..114931c 100644 --- a/src/core/gameconnection.cc +++ b/src/core/gameconnection.cc @@ -57,6 +57,8 @@ GameConnection::GameConnection(std::string const &connectionstr) return; } + game_players.push_back(localplayer()); + connection_running = true; } @@ -91,6 +93,14 @@ void GameConnection::say(std::string const &args) connection_network->send_say(args); } +void GameConnection::private_message(std::string const &args) +{ + if (!connection_network->connected()) + return; + + connection_network->send_private_message(args); +} + void GameConnection::frame(float seconds) { if (!running()) diff --git a/src/core/gameconnection.h b/src/core/gameconnection.h index d0da18e..ecf50f2 100644 --- a/src/core/gameconnection.h +++ b/src/core/gameconnection.h @@ -39,6 +39,9 @@ public: /// localplayer sends a chat message to the public channel void say(std::string const &args); + /// localplayer sends a private message to another player + void private_message(std::string const &args); + /*----- static ---------------------------------------------------- */ /// return the current game connection diff --git a/src/core/gameinterface.cc b/src/core/gameinterface.cc index 70224b0..17623f2 100644 --- a/src/core/gameinterface.cc +++ b/src/core/gameinterface.cc @@ -4,9 +4,11 @@ the terms of the GNU General Public License version 2 */ -#include <stdlib.h> +#include <cstdlib> #include <iostream> +#include <iomanip> +#include "auxiliary/functions.h" #include "core/application.h" #include "core/cvar.h" #include "core/func.h" @@ -19,13 +21,13 @@ namespace core { -const float MIN_DELTA = 10e-10; - -void func_list_model(std::string const &args) +void func_list_players(std::string const &args) { - model::Model::list(); + game()->list_players(); } +const float MIN_DELTA = 10e-10; + Player GameInterface::game_localplayer; EntityControlable *localcontrol() @@ -52,13 +54,14 @@ GameInterface::GameInterface() game_localplayer.player_name.assign("Player"); game_localplayer.update_info(); } - - Func::add("list_model", (FuncPtr) func_list_model); + + Func *func = Func::add("list_players", func_list_players); + func->set_info("get the local list of connected players"); } GameInterface::~GameInterface() { - Func::remove("list_model"); + Func::remove("list_players"); game_localplayer.clear(); @@ -105,6 +108,16 @@ void GameInterface::clear() // remove all models model::Model::clear(); + // clear player list + for (Players::iterator it = game_players.begin(); it != game_players.end(); it++) { + Player *player = (*it); + if (player != localplayer()) { + delete player; + } + } + + game_players.clear(); + game_previousframetime = 0; game_serverframetime = 0; game_clientframetime = 0; @@ -220,4 +233,19 @@ float GameInterface::timeoffset() { return t/d; } +void GameInterface::list_players() +{ + using namespace std; + stringstream msgstr; + int count = 0; + + for (Players::iterator it = game_players.begin(); it != game_players.end(); it++) { + msgstr.str(""); + con_print << setw(3) << (*it)->id() << aux::pad_left((*it)->name(), 24) << std::endl; + count++; + } + + con_print << count << " connected " << aux::plural("player", count) << std::endl; +} + } diff --git a/src/core/gameinterface.h b/src/core/gameinterface.h index ef51545..69cd588 100644 --- a/src/core/gameinterface.h +++ b/src/core/gameinterface.h @@ -22,6 +22,9 @@ public: /// destroy the game virtual ~GameInterface(); + /// type definition for the Players collection + typedef std::list<Player *> Players; + /*----- inspectors ---------------------------------------------- */ /// return the local player @@ -41,6 +44,11 @@ public: inline float timestep() const { return game_timestep; } + inline Players & players() { return game_players; } + + /// show a list of connected players + void list_players(); + /*----- virtual inspectors --------------------------------------- */ /// returns true if the game server can run a time frime @@ -68,6 +76,9 @@ public: protected: /// the local player static Player game_localplayer; + + /// all the players + Players game_players; float game_serverframetime; float game_previousframetime; diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc index 14f97bb..f251b75 100644 --- a/src/core/gameserver.cc +++ b/src/core/gameserver.cc @@ -4,17 +4,17 @@ the terms of the GNU General Public License version 2 */ -#include <iomanip> #include <fstream> +#include <iomanip> #include "auxiliary/functions.h" -#include "sys/sys.h" #include "core/application.h" #include "core/cvar.h" #include "core/func.h" #include "core/gameserver.h" #include "core/netserver.h" #include "filesystem/filesystem.h" +#include "sys/sys.h" namespace core { @@ -174,8 +174,6 @@ GameServer::GameServer() : GameInterface() func = Func::add("who", func_who, Func::Shared); func->set_info("get a list of connected players"); - server_players.clear(); - if (!Cvar::sv_dedicated->value()) { player_connect(localplayer()); } @@ -218,8 +216,6 @@ GameServer::~GameServer() Func::remove("who"); server_instance = 0; - - server_players.clear(); } void GameServer::abort() @@ -227,21 +223,6 @@ void GameServer::abort() server_running = false; } -void GameServer::list_players() -{ - using namespace std; - stringstream msgstr; - int count = 0; - - for (Players::iterator it = server_players.begin(); it != server_players.end(); it++) { - msgstr.str(""); - con_print << setw(3) << (*it)->id() << aux::pad_left((*it)->name(), 24) << std::endl; - count++; - } - - con_print << count << " connected " << aux::plural("player", count) << std::endl; -} - void GameServer::showtime() { using namespace std; @@ -265,7 +246,7 @@ Player *GameServer::find_player(std::string const search) std::istringstream searchstr(search); int id = 0; if (searchstr >> id) { - for (std::list<Player *>:: iterator it = server_players.begin(); it != server_players.end(); it++) { + for (std::list<Player *>:: iterator it = game_players.begin(); it != game_players.end(); it++) { if ((*it)->id() == id) { return (*it); } @@ -275,7 +256,7 @@ Player *GameServer::find_player(std::string const search) if (search.size() <3) return 0; - for (std::list<Player *>:: iterator it = server_players.begin(); it != server_players.end(); it++) { + for (std::list<Player *>:: iterator it = game_players.begin(); it != game_players.end(); it++) { if (aux::text_strip_lowercase((*it)->name()).find(lowercase(search)) != std::string::npos) return (*it); } @@ -298,14 +279,35 @@ void GameServer::say(Player *player, std::string const &message) notification.append("^F:^B "); notification.append(message); - // send to application - application()->notify_message(notification); - application()->notify_sound("com/chat"); - - // broadcast to remote clients - if (server_network) { - server_network->broadcast_message("public", notification); + broadcast_message(Message::Public, notification); +} + +void GameServer::private_message(Player *player, std::string const &args) +{ + if (!args.size()) + return; + + if (player->mute()) { + send(player, "^BYou have been muted."); + return; + } + + std::string target; + std::stringstream argstr(args); + if (!(argstr >> target)) { + return; } + + core::Player *targetplayer = core::server()->find_player(target); + if (!targetplayer) { + send(player, "^BPlayer " + target + "^B not found."); + return; + } + + + std::string message(args.substr(target.size())); + send_message(Message::Private, player, "^FTo ^B" + targetplayer->name() + "^F:" + message); + send_message(Message::Private, targetplayer, "^FFrom ^B" + player->name() + "^F:" + message); } // FIXME kicked by @@ -327,44 +329,114 @@ void GameServer::kick(Player *player, std::string const &reason) } // broadcast an "info" message to all players -void GameServer::broadcast(std::string const & message, Player *ignore_player) +void GameServer::broadcast(std::string const message, Player *ignore_player) { if (!message.size()) return; - // send to application - if (ignore_player != game()->localplayer()) - application()->notify_message(message); - - // broadcast to remote clients - if (server_network) { - server_network->broadcast_message("info", message, ignore_player); - } + broadcast_message(Message::Info, message, ignore_player); } // send and "info" message to a single player -void GameServer::send(Player *player, std::string message) +void GameServer::send(Player *player, std::string const message) +{ + send_message(Message::Info, player, message); +} + +// send an rcon message to a single player +void GameServer::send_rcon(Player *player, std::string const message) +{ + send_message(Message::RCon, player, message); +} + +void GameServer::send_message(Message::Channel const channel, Player *player, std::string const message) { if (!message.size()) return; - // send to application if (player == localplayer()) { - application()->notify_message(message); + application()->notify_message(channel, message); return; + } else { + if (server_network) { + std::string msg_channel; + switch(channel) { + case core::Message::Info: // Info message + msg_channel.assign("info"); + break; + + case core::Message::Local: // Chat message in the local zone + msg_channel.assign("local"); + break; + + case core::Message::Public: // Public chat message + msg_channel.assign("public"); + break; + + case core::Message::Private: // Private chat message + msg_channel.assign("private"); + break; + + case core::Message::RCon: // RCon message + msg_channel.assign("rcon"); + break; + + default: + con_warn << "message on unknown channel " << channel << "!" << std::endl; + return; + break; + } + + NetClient *client = server_network->find_client(player); + if (client) { + server_network->send_message(client, msg_channel.c_str(), message); + } + } } +} + +// broadcast a message on a specified channel to all players +void GameServer::broadcast_message(Message::Channel const channel, std::string const message, Player *ignore_player) +{ + if (!message.size()) + return; - // send to remote clients + // send to application + if (ignore_player != game()->localplayer()) + application()->notify_message(channel, message); + + // broadcast to remote clients if (server_network) { - NetClient *client = server_network->find_client(player); - if (client) { - server_network->send_message(client, "info", message); + std::string msg_channel; + switch(channel) { + case core::Message::Info: // Info message + msg_channel.assign("info"); + break; + + case core::Message::Local: // Chat message in the local zone + msg_channel.assign("local"); + break; + + case core::Message::RCon: // RCon message + msg_channel.assign("rcon"); + break; + + case core::Message::Public: // Public chat message + msg_channel.assign("public"); + break; + + default: + con_warn << "message on unknown channel " << channel << "!" << std::endl; + return; + break; } + + server_network->broadcast_message(msg_channel.c_str(), message); } } // broadcast a sound event to all players -void GameServer::broadcast_sound(std::string const & sound, Player *ignore_player) +void GameServer::broadcast_sound(std::string const sound, Player *ignore_player) { if (!sound.size()) return; @@ -381,7 +453,7 @@ void GameServer::broadcast_sound(std::string const & sound, Player *ignore_playe } // send a sound event to a single player -void GameServer::send_sound(Player *player, std::string sound) +void GameServer::send_sound(Player *player, std::string const sound) { if (!sound.size()) return; @@ -401,24 +473,6 @@ void GameServer::send_sound(Player *player, std::string sound) } } -// send an rcon message to a single player -void GameServer::send_rcon(Player *player, std::string message) -{ - // send to application - if (player == localplayer()) { - con_print << message << std::endl; - return; - } - - // send to remote clients - if (server_network) { - NetClient *client = server_network->find_client(player); - if (client) { - server_network->send_message(client, "rcon", message); - } - } -} - // execute a command for a remote player void GameServer::exec(Player *player, std::string const & cmdline) { @@ -478,7 +532,7 @@ void GameServer::player_connect(Player *player) server_module->player_connect(player); // manage player list - server_players.push_back(player); + game_players.push_back(player); } void GameServer::player_disconnect(Player *player) @@ -495,12 +549,12 @@ void GameServer::player_disconnect(Player *player) server_module->player_disconnect(player); // manage player list - std::list<Player *>:: iterator it = server_players.begin(); - while (((*it)->id() != player->id()) && (it != server_players.end())) { + std::list<Player *>:: iterator it = game_players.begin(); + while (((*it)->id() != player->id()) && (it != game_players.end())) { it++; } - if (it != server_players.end()) { - server_players.erase(it); + if (it != game_players.end()) { + game_players.erase(it); } } diff --git a/src/core/gameserver.h b/src/core/gameserver.h index 1f6d8cc..b25f1a0 100644 --- a/src/core/gameserver.h +++ b/src/core/gameserver.h @@ -8,6 +8,7 @@ #define __INCLUDED_CORE_GAMESERVER_H__ #include "core/gameinterface.h" +#include "core/message.h" #include "core/module.h" #include "core/netserver.h" @@ -21,8 +22,6 @@ namespace core class GameServer : public GameInterface { public: - typedef std::list<Player *> Players; - GameServer(); ~GameServer(); @@ -34,9 +33,6 @@ public: /// returns true if the game server can not run a time frime inline bool error() { return !server_running; } - /// show a list of connected players - void list_players(); - /// show the current time void showtime(); @@ -57,23 +53,32 @@ public: /// a player sends a chat message to the public channel void say(Player *player, std::string const &args); + /// a player sends a private message to another player + void private_message(Player *player, std::string const &args); + /// kick a player from the server void kick(Player *player, std::string const &reason); - /// broadcast a message to all players - void broadcast(std::string const & message, Player *ignore_player = 0); + /// broadcast an Info message to all players + void broadcast(std::string const message, Player *ignore_player = 0); + + /// broadcast a message to all players on a specified channel + void broadcast_message(Message::Channel const channel, std::string const message, Player *ignore_player = 0); + + /// send an Info message to a single player + void send(Player *player, std::string const message); - /// send a message to a single player - void send(Player *player, std::string message); + /// send a RCon message to a single player + void send_rcon(Player *player, std::string const message); + + /// send a message on the specific channel to the specified Player + void send_message(Message::Channel const channel, Player *player, std::string const message); /// broadcast a sound to all players - void broadcast_sound(std::string const & sound, Player *ignore_player = 0); + void broadcast_sound(std::string const sound, Player *ignore_player = 0); /// send a sound to a single player - void send_sound(Player *player, std::string sound); - - /// send a rcon message to a single player - void send_rcon(Player *player, std::string message); + void send_sound(Player *player, std::string const sound); /// a player sends a command to the game server void exec(Player *player, std::string const &cmdline); @@ -81,8 +86,6 @@ public: /// find the first player who's id or name matches the search string Player *find_player(std::string const search); - inline Players & players() { return server_players; } - /*----- static ---------------------------------------------------- */ /// return the current game server @@ -104,8 +107,6 @@ private: float server_frametime; float server_time; float server_previoustime; - - Players server_players; }; inline GameServer *server() { return GameServer::instance(); } diff --git a/src/core/message.h b/src/core/message.h new file mode 100644 index 0000000..53d24be --- /dev/null +++ b/src/core/message.h @@ -0,0 +1,23 @@ +/* + core/message.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_MESSAGE_H__ +#define __INCLUDED_CORE_MESSAGE_H__ + +namespace core +{ + +class Message { + +public: + /// indicates the type of message + enum Channel {Info=0, Public=1, Local=2, Private=3, RCon=4 }; +}; + +} + +#endif // __INCLUDED_CORE_MESSAGE_H__ + diff --git a/src/core/net.h b/src/core/net.h index f3f976b..4909136 100644 --- a/src/core/net.h +++ b/src/core/net.h @@ -11,7 +11,7 @@ namespace core { /// network protocol version -const unsigned int PROTOCOLVERSION = 9; +const unsigned int PROTOCOLVERSION = 10; /// 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 ed1a91b..9268447 100644 --- a/src/core/netconnection.cc +++ b/src/core/netconnection.cc @@ -328,6 +328,7 @@ void NetConnection::send_raw(std::string const &msg) * cup <id> <entity data> * cmd <text> * say <text> + * priv <text> */ // send a "connect" message to the server @@ -380,6 +381,15 @@ void NetConnection::send_say(std::string const &text) this->send_raw(msg); } +// send a "priv" private message to the server +void NetConnection::send_private_message(std::string const &text) +{ + std::string msg("priv "); + msg.append(text); + msg += '\n'; + this->send_raw(msg); +} + // parse incoming client messages /** * The following incoming messages are parsed; @@ -388,13 +398,14 @@ void NetConnection::send_say(std::string const &text) * disconnect * msg info <text> * msg public <name> <text> + * msg private <name> <text> * msg rcon <text> * msg snd <soundname> - * die - * ent + * die <id> + * ent <id> * frame - * sup - * pif + * sup <id> + * pif <id> * zone */ void NetConnection::parse_incoming_message(const std::string & message) @@ -409,19 +420,22 @@ void NetConnection::parse_incoming_message(const std::string & message) if (msgstream >> level) { if (level =="info") { if (message.size() > 9) { - application()->notify_message(message.substr(9)); + application()->notify_message(Message::Info, message.substr(9)); } } else if (level =="rcon") { if (message.size() > 9) { - con_print << message.substr(9) << std::endl; + application()->notify_message(Message::RCon, message.substr(9)); } } else if (level == "public") { // FIXME - separate sender nickname if (message.size() > 11) { - application()->notify_message(message.substr(11)); - application()->notify_sound("com/chat"); + application()->notify_message(Message::Public, message.substr(11)); } - + } else if (level == "private") { + // FIXME - separate sender nickname + if (message.size() > 12) { + application()->notify_message(Message::Private, message.substr(12)); + } } else if (level == "snd") { if (message.size() > 8) { application()->notify_sound(message.substr(8).c_str()); @@ -527,29 +541,50 @@ void NetConnection::parse_incoming_message(const std::string & message) } else if (command == "pif") { //con_debug << "Received update player info" << std::endl; - - Zone *oldzone = connection()->localplayer()->zone(); - connection()->localplayer()->receive_server_update(msgstream); - - //con_debug << "zone " << ( connection()->localplayer()->zone() ? connection()->localplayer()->zone()->id() : 0) << std::endl; - if (connection()->localplayer()->zonechange() && oldzone && (oldzone != connection()->localplayer()->zone())) { - - // notify the applciation to clear none-core zone assets (textures etc) - application()->notify_zoneclear(oldzone); - - // delete all entities in the old zone - for (Entity::Registry::iterator it=Entity::registry().begin(); it != Entity::registry().end(); ) { - Entity *entity = (*it).second; + int player_id; + if (!(msgstream >> player_id)) { + con_warn << "Received illegal update player info for player!" << std::endl; + return; + } - if ((entity->zone() == oldzone)) { - delete entity; - Entity::registry().erase(it++); - } else { - ++it; + if (!player_id) { + Zone *oldzone = connection()->localplayer()->zone(); + connection()->localplayer()->receive_server_update(msgstream); + + //con_debug << "zone " << ( connection()->localplayer()->zone() ? connection()->localplayer()->zone()->id() : 0) << std::endl; + + if (connection()->localplayer()->zonechange() && oldzone && (oldzone != connection()->localplayer()->zone())) { + + // notify the applciation to clear none-core zone assets (textures etc) + application()->notify_zoneclear(oldzone); + + // delete all entities in the old zone + for (Entity::Registry::iterator it=Entity::registry().begin(); it != Entity::registry().end(); ) { + Entity *entity = (*it).second; + + if ((entity->zone() == oldzone)) { + delete entity; + Entity::registry().erase(it++); + } else { + ++it; + } + } + oldzone->content().clear(); + } + } else { + // FIXME find player + Player *player = 0; + for (GameInterface::Players::iterator it = game()->players().begin(); it != game()->players().end() && !player; it++) { + if( (*it)->id() == player_id) { + player = (*it); } } - oldzone->content().clear(); + if (!player) { + player = new Player(); + game()->players().push_back(player); + } + player->receive_server_update(msgstream); } } else if (command == "sup") { diff --git a/src/core/netconnection.h b/src/core/netconnection.h index da683f5..cb04ce2 100644 --- a/src/core/netconnection.h +++ b/src/core/netconnection.h @@ -62,6 +62,9 @@ public: /// send a chat message void send_say(std::string const &text); + /// send a private message + void send_private_message(std::string const &text); + /// send a command line to the remote server void send_command(std::string const &cmdline); diff --git a/src/core/netserver.cc b/src/core/netserver.cc index 93d4682..e1bd41a 100644 --- a/src/core/netserver.cc +++ b/src/core/netserver.cc @@ -514,7 +514,7 @@ void NetServer::send_zone_update(NetClient *client, Zone *zone) void NetServer::send_player_update(NetClient *client) { std::ostringstream msg; - msg << "pif "; + msg << "pif 0 "; client->player()->serialize_server_update(msg); msg << '\n'; client->send_raw(msg.str()); @@ -531,6 +531,7 @@ void NetServer::send_player_update(NetClient *client) * pif * ping * say <text> + * priv <player> <text> * */ void NetServer::parse_incoming_message(NetClient *client, const std::string & message) @@ -653,6 +654,14 @@ void NetServer::parse_incoming_message(NetClient *client, const std::string & me } return; } + + // priv + if (command == "priv") { + if (message.size() > command.size()+1) { + server()->private_message(client->player(), message.substr(command.size()+1)); + } + return; + } } diff --git a/src/core/player.cc b/src/core/player.cc index 1a610ca..26ea070 100644 --- a/src/core/player.cc +++ b/src/core/player.cc @@ -6,6 +6,7 @@ #include <sstream> +#include "auxiliary/functions.h" #include "sys/sys.h" #include "core/player.h" #include "core/cvar.h" @@ -33,6 +34,7 @@ void Player::clear() player_zonechange = false; player_rcon = false; player_mute = false; + player_mission_target = 0; clear_assets(); player_control = 0; @@ -56,12 +58,23 @@ void Player::set_zone(Zone *zone) } } +void Player::set_mission_target(Entity *new_mission_target) +{ + if (new_mission_target != player_mission_target) { + player_mission_target = new_mission_target; + player_dirty = true; + } +} + void Player::update_info() { Cvar *cl_name = Cvar::find("cl_name"); if (cl_name) { - if (cl_name->str().size()) + if (cl_name->str().size()) { player_name = cl_name->str(); + aux::strip_quotes(player_name); + (*cl_name) = player_name; + } } Cvar *cl_color = Cvar::find("cl_color"); @@ -105,8 +118,9 @@ void Player::serialize_server_update(std::ostream & os) const { unsigned int zo = (zone() ? zone()->id() : 0); unsigned int co = (player_control ? player_control->id() : 0); + unsigned int mission = (player_mission_target ? player_mission_target->id() : 0); - os << player_id << " " << zo << " " << co << " " << player_color << " \"" << player_name << "\""; + os << player_id << " " << zo << " " << co << " " << mission << " " << player_color << " \"" << player_name << "\""; } void Player::receive_server_update(std::istream &is) @@ -131,6 +145,16 @@ void Player::receive_server_update(std::istream &is) player_control = 0; } + unsigned int mission = 0; + is >> mission; + if (mission) { + player_mission_target = Entity::find(mission); + if (!player_mission_target) { + con_warn << "mission target set to unknown entity " << co << "\n"; + } + } else { + player_mission_target = 0; + } is >> player_color; std::string n; diff --git a/src/core/player.h b/src/core/player.h index 7bf533c..aa31a35 100644 --- a/src/core/player.h +++ b/src/core/player.h @@ -67,6 +67,9 @@ public: /// player has been muted by admin or console inline bool mute() const { return player_mute; } + /// mission target + inline Entity *mission_target() { return player_mission_target; } + /*----- mutators -------------------------------------------------- */ /// serialize player info to a stream @@ -99,6 +102,8 @@ public: /// update player info from client variables void update_info(); + void set_mission_target(Entity *new_mission_target); + /* -- should actually not be public --*/ /// dirty state @@ -131,10 +136,12 @@ private: // the entity the Player is currently controling EntityControlable *player_control; + Entity *player_mission_target; + // the zone the player is currently in Zone *player_zone; - + float player_credits; }; } diff --git a/src/game/game.cc b/src/game/game.cc index 0502ece..4d66cbe 100644 --- a/src/game/game.cc +++ b/src/game/game.cc @@ -224,6 +224,9 @@ void Game::init() g_strafespeed = core::Cvar::get("g_strafespeed", "0.003", core::Cvar::Game | core::Cvar::Archive); g_strafespeed->set_info("[float] strafe speed"); + g_jumppointrange = core::Cvar::get("g_jumppointrange", "512", core::Cvar::Game | core::Cvar::Archive); + g_jumppointrange->set_info("[float] jumppoint range"); + g_devel = core::Cvar::get("g_devel", "0", core::Cvar::Archive); g_devel->set_info("[bool] enable or disable developer mode"); @@ -305,6 +308,65 @@ bool Game::load_world() return true; } +bool Game::got_entity_key(filesystem::IniFile &inifile, core::Entity *entity) +{ + std::string shapename; + std::string strval; + float direction; + float pitch; + float roll; + + if (inifile.got_key_string("shape", shapename)) { + + if (shapename.compare("axis") == 0) { + entity->entity_shape = core::Entity::Axis; + return true; + } else if (shapename.compare("cube") == 0) { + entity->entity_shape = core::Entity::Cube; + return true; + } else if (shapename.compare("diamond") == 0) { + entity->entity_shape = core::Entity::Diamond; + return true; + } else if (shapename.compare("sphere") == 0) { + entity->entity_shape = core::Entity::Sphere; + return true; + } else { + con_warn << inifile.name() << " unknown shape '" << shapename << "' at line " << inifile.line() << std::endl; + return false; + } + + } else if (inifile.got_key_string("label", strval)) { + aux::to_label(strval); + entity->entity_label.assign(strval); + return true; + } else if (inifile.got_key_string("name", strval)) { + aux::strip_quotes(strval); + entity->entity_name.assign(strval); + return true; + } else if (inifile.got_key_string("model", entity->entity_modelname)) { + return true; + } else if (inifile.got_key_angle("direction", direction)) { + entity->axis().change_direction(direction); + return true; + } else if (inifile.got_key_angle("pitch", pitch)) { + entity->axis().change_pitch(pitch); + return true; + } else if (inifile.got_key_angle("roll", roll)) { + entity->axis().change_roll(roll); + return true; + } else if (inifile.got_key_angle("radius", entity->entity_radius)) { + return true; + } else if (inifile.got_key_vector3f("location", entity->entity_location)) { + return true; + } else if (inifile.got_key_color("color", entity->entity_color)) { + return true; + } else if (inifile.got_key_color("colorsecond", entity->entity_color_second)) { + return true; + } + + return false; +} + bool Game::load_zone(core::Zone *zone) { using math::Vector3f; @@ -331,10 +393,6 @@ bool Game::load_zone(core::Zone *zone) CheckPoint *checkpoint = 0; core::Entity *entity = 0; - float direction; - float pitch; - float roll; - bool b; std::string strval; @@ -346,6 +404,7 @@ bool Game::load_zone(core::Zone *zone) if (zoneini.got_key()) { if (zoneini.section().compare("zone") == 0) { if (zoneini.got_key_string("name", strval)) { + aux::strip_quotes(strval); zone->set_name(strval); continue; } else if (zoneini.got_key_string("sky", strval)) { @@ -358,77 +417,32 @@ bool Game::load_zone(core::Zone *zone) con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl; } } else if (zoneini.section().compare("star") == 0) { - - if (zoneini.got_key_string("label", strval)) { - aux::to_label(strval); - star->entity_label.assign(strval); - continue; - } else if (zoneini.got_key_string("name", star->entity_name)) { - continue; - } else if (zoneini.got_key_vector3f("location", star->entity_location )) { - continue; - } else if (zoneini.got_key_color("color", star->entity_color)) { - continue; - } else if (zoneini.got_key_angle("radius", star->entity_radius)) { - continue; - } else if (zoneini.got_key_angle("direction", direction)) { - star->axis().change_direction(direction); + if (got_entity_key(zoneini, star)) { continue; } else if (zoneini.got_key_string("texture", star->entity_texture)) { continue; - } else if (zoneini.got_key_angle("pitch", pitch)) { - star->axis().change_pitch(pitch); - continue; } else { con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl; } } else if (zoneini.section().compare("navpoint") == 0) { - if (zoneini.got_key_string("label", strval)) { - aux::to_label(strval); - navpoint->entity_label.assign(strval); - continue; - } else if (zoneini.got_key_string("name", navpoint->entity_name)) { - continue; - } else if (zoneini.got_key_vector3f("location", navpoint->entity_location )) { + if (got_entity_key(zoneini, navpoint)) { continue; } else { con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl; } } else if (zoneini.section().compare("jumppoint") == 0) { - if (zoneini.got_key_string("label", strval)) { - aux::to_label(strval); - jumppoint->entity_label.assign(strval); - continue; - } else if (zoneini.got_key_string("name", jumppoint->entity_name)) { + if (got_entity_key(zoneini, jumppoint)) { continue; } else if (zoneini.got_key_string("target", jumppoint->jumppoint_targetlabel)) { continue; - } else if (zoneini.got_key_vector3f("location", jumppoint->entity_location )) { - continue; } else { con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl; } } else if (zoneini.section().compare("planet") == 0) { - if (zoneini.got_key_string("label", strval)) { - aux::to_label(strval); - planet->entity_label.assign(strval); - continue; - } else if (zoneini.got_key_string("name", planet->entity_name)) { + if (got_entity_key(zoneini, planet)) { continue; } else if (zoneini.got_key_string("texture", planet->entity_texture)) { continue; - } else if (zoneini.got_key_vector3f("location", planet->entity_location )) { - continue; - } else if (zoneini.got_key_color("color", planet->entity_color)) { - continue; - } else if (zoneini.got_key_angle("radius", planet->entity_radius)) { - continue; - } else if (zoneini.got_key_angle("direction", direction)) { - planet->axis().change_direction(direction); - continue; - } else if (zoneini.got_key_angle("pitch", pitch)) { - planet->axis().change_pitch(pitch); - continue; } else if (zoneini.got_key_float("rotationspeed", planet->entity_rotationspeed)) { continue; } else { @@ -436,88 +450,21 @@ bool Game::load_zone(core::Zone *zone) } } else if (zoneini.section().compare("racetrack") == 0) { - if (zoneini.got_key_string("label", strval)) { - aux::to_label(strval); - racetrack->entity_label.assign(strval); - continue; - } else if (zoneini.got_key_string("name", racetrack->entity_name)) { - continue; - } else if (zoneini.got_key_vector3f("location", racetrack->entity_location )) { - continue; - } else if (zoneini.got_key_color("color", racetrack->entity_color)) { - continue; - } else if (zoneini.got_key_angle("direction", direction)) { - racetrack->axis().change_direction(direction); - continue; - } else if (zoneini.got_key_angle("pitch", pitch)) { - racetrack->axis().change_pitch(pitch); - continue; - } else if (zoneini.got_key_string("model", racetrack->entity_modelname)) { + if (got_entity_key(zoneini, racetrack)) { continue; } else { con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl; } } else if (zoneini.section().compare("checkpoint") == 0) { - if (zoneini.got_key_string("label", strval)) { - aux::to_label(strval); - checkpoint->entity_label.assign(strval); - continue; - } else if (zoneini.got_key_string("name", checkpoint->entity_name)) { - continue; - } else if (zoneini.got_key_vector3f("location", checkpoint->entity_location )) { - continue; - } else if (zoneini.got_key_angle("direction", direction)) { - checkpoint->axis().change_direction(direction); - continue; - } else if (zoneini.got_key_angle("pitch", pitch)) { - checkpoint->axis().change_pitch(pitch); - continue; - } else if (zoneini.got_key_string("model", checkpoint->entity_modelname)) { + if (got_entity_key(zoneini, checkpoint)) { continue; } else { con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl; } } else if (zoneini.section().compare("entity") == 0) { - std::string shapename; - if (zoneini.got_key_string("shape", shapename)) { - if (shapename.compare("axis") == 0) { - entity->entity_shape = core::Entity::Axis; - } else if (shapename.compare("cube") == 0) { - entity->entity_shape = core::Entity::Cube; - } else if (shapename.compare("diamond") == 0) { - entity->entity_shape = core::Entity::Diamond; - } else if (shapename.compare("sphere") == 0) { - entity->entity_shape = core::Entity::Sphere; - } else { - con_warn << zoneini.name() << " unknown shape '" << shapename << "' at line " << zoneini.line() << std::endl; - } - continue; - } else if (zoneini.got_key_string("label", strval)) { - aux::to_label(strval); - entity->entity_label.assign(strval); - continue; - } else if (zoneini.got_key_string("name", entity->entity_name)) { - continue; - } else if (zoneini.got_key_string("model", entity->entity_modelname)) { - continue; - } else if (zoneini.got_key_angle("direction", direction)) { - entity->axis().change_direction(direction); - continue; - } else if (zoneini.got_key_angle("pitch", pitch)) { - entity->axis().change_pitch(pitch); - continue; - } else if (zoneini.got_key_angle("roll", roll)) { - entity->axis().change_roll(roll); - continue; - } else if (zoneini.got_key_angle("radius", entity->entity_radius)) { - continue; - } else if (zoneini.got_key_vector3f("location", entity->entity_location)) { - continue; - } else if (zoneini.got_key_color("color", entity->entity_color)) { - continue; - } else if (zoneini.got_key_color("colorsecond", entity->entity_color_second)) { + if (got_entity_key(zoneini, entity)) { continue; } else { con_warn << zoneini.name() << " unknown key '" << zoneini.key() << "' at line " << zoneini.line() << std::endl; @@ -576,6 +523,8 @@ bool Game::load_zone(core::Zone *zone) bool Game::validate_zone(core::Zone *zone) { + con_debug << " validating " << zone->name() << std::endl; + for (core::Zone::Content::iterator it = zone->content().begin(); it != zone->content().end(); it++) { core::Entity *entity = (*it); @@ -614,7 +563,7 @@ bool Game::validate_zone(core::Zone *zone) jumppoint->jumppoint_target = static_cast<JumpPoint *>(targetentity); - con_debug << " Jump point " << zone->label() << ":" << jumppoint->label() << " with target " << jumppoint->targetlabel() << std::endl; + //con_debug << " Jumppoint " << zone->label() << ":" << jumppoint->label() << " with target " << jumppoint->targetlabel() << std::endl; } } diff --git a/src/game/game.h b/src/game/game.h index c7ec040..3b65da1 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -7,16 +7,15 @@ #ifndef __INCLUDED_GAME_H__ #define __INCLUDED_GAME_H__ -// project headers +#include <vector> +#include <string> + +#include "filesystem/inifile.h" #include "game/ship.h" #include "game/star.h" #include "core/core.h" #include "sys/sys.h" -// C++ headers -#include <vector> -#include <string> - /// the game-specific engine /** The main game functions. */ @@ -55,10 +54,13 @@ public: core::Cvar *g_impulsespeed; core::Cvar *g_impulseacceleration; core::Cvar *g_strafespeed; + core::Cvar *g_jumppointrange; core::Cvar *g_devel; private: + bool got_entity_key(filesystem::IniFile &inifile, core::Entity *entity); + bool load_world(); bool load_zone(core::Zone *zone); diff --git a/src/game/jumppoint.cc b/src/game/jumppoint.cc index a5f9b1a..d2c6bc1 100644 --- a/src/game/jumppoint.cc +++ b/src/game/jumppoint.cc @@ -13,13 +13,13 @@ namespace game JumpPoint::JumpPoint() : core::Entity(core::Entity::Static) { entity_shape = core::Entity::Diamond; - entity_color.assign(0.8f, 0.0f, 0.0f, 1.0f); + entity_color.assign(0.0f, 0.8f, 0.8f, 1.0f); entity_color_second.assign(0.6f, 1.0f); entity_radius = 0.25f; entity_moduletypeid = jumppoint_enttype; jumppoint_target = 0; - entity_serverside = true; + entity_serverside = false; } JumpPoint::~JumpPoint() diff --git a/src/game/racetrack.cc b/src/game/racetrack.cc index 897a839..cfacb82 100644 --- a/src/game/racetrack.cc +++ b/src/game/racetrack.cc @@ -56,6 +56,9 @@ void RaceTrack::add_checkpoint(CheckPoint *checkpoint) void RaceTrack::reset() { + if (track_player) { + track_player->set_mission_target(0); + } track_player = 0; track_racestart = 0; track_checkpointtime = 0; @@ -64,8 +67,7 @@ void RaceTrack::reset() (*cpit)->set_eventstate(core::Entity::NoPower); } - entity_eventstate |= core::Entity::NoPower; - entity_dirty = true; + set_eventstate(core::Entity::NoPower); } void RaceTrack::frame(float seconds) @@ -93,6 +95,7 @@ void RaceTrack::frame(float seconds) message.append(track_player->name()); message.append(" ^Bactivated the race! Race starts in 5..."); core::server()->broadcast(message); + track_player->set_mission_target(this); return; } } @@ -149,6 +152,7 @@ void RaceTrack::frame(float seconds) track_checkpointtime = core::server()->time() + 15.0f; track_checkpoint = track_checkpoints.begin(); (*track_checkpoint)->set_eventstate(core::Entity::Normal); + track_player->set_mission_target((*track_checkpoint)); } } @@ -175,16 +179,13 @@ void RaceTrack::frame(float seconds) (*track_checkpoint)->set_eventstate(core::Entity::NoPower); track_checkpoint++; (*track_checkpoint)->set_eventstate(core::Entity::Normal); + track_player->set_mission_target((*track_checkpoint)); } else { std::stringstream msgstr; msgstr << "^BRace completed in " << core::server()->time() - track_racestart << " seconds!"; core::server()->broadcast(msgstr.str()); - track_player = 0; - track_racestart = 0; - track_checkpointtime = 0; - reset(); } } diff --git a/src/game/ship.cc b/src/game/ship.cc index 0dde90e..1828172 100644 --- a/src/game/ship.cc +++ b/src/game/ship.cc @@ -118,7 +118,7 @@ void Ship::jump(std::string const &args) return; } - core::server()->send(owner(), "Jumping to '" + jumptargetzone->name() + '\''); + core::server()->send(owner(), "Jumping to the " + jumptargetzone->name()); set_zone(jumptargetzone); if (owner()->control() == (EntityControlable*) this) owner()->set_zone(jumptargetzone); @@ -145,6 +145,10 @@ void Ship::jump(std::string const &args) return; } + if (!find_closest_jumppoint()) { + return; + } + entity_eventstate = core::Entity::JumpInitiate; if (Game::instance()->g_devel->value()) { entity_timer = 0; @@ -157,6 +161,39 @@ void Ship::jump(std::string const &args) } } +JumpPoint * Ship::find_closest_jumppoint() +{ + // find closest jumppoint + float d = -1; + JumpPoint *jumppoint = 0; + for (core::Zone::Content::iterator it = zone()->content().begin(); it != zone()->content().end(); it++) { + core::Entity *entity = (*it); + if (entity->moduletype() == jumppoint_enttype) { + JumpPoint *te = static_cast<JumpPoint *>(entity); + float d1 = math::distance(location(), te->location()); + if ((d < 0) || (d1 < d)) { + d = d1; + jumppoint = te; + } + } + } + + if (jumppoint && jumppoint->target()) { + if (Game::instance()->g_jumppointrange->value() < d) { + core::server()->send(owner(), "Jumppoint out of range!"); + return 0; + } else { + core::server()->send(owner(), "Jumping to the " + jumppoint->target()->zone()->name()); + return jumppoint; + } + } else { + core::server()->send(owner(), "No jumppoints found!"); + return 0; + } + + return 0; +} + void Ship::frame(float seconds) { const float direction_change_speed = 2; @@ -184,29 +221,15 @@ void Ship::frame(float seconds) entity_timer -= 1.0f; if (entity_timer <= 0) { - // find closest jumppoint - float d = -1; - JumpPoint *jumppoint = 0; - for (core::Zone::Content::iterator it = zone()->content().begin(); it != zone()->content().end(); it++) { - core::Entity *entity = (*it); - if (entity->moduletype() == jumppoint_enttype) { - JumpPoint *te = static_cast<JumpPoint *>(entity); - float d1 = math::distance(location(), te->location()); - if ((d < 0) || (d1 < d1)) { - d = d1; - jumppoint = te; - } - } - } - if (jumppoint && jumppoint->target()) { - core::server()->send(owner(), "Jumping to '" + jumppoint->target()->zone()->name() + '\''); + JumpPoint *jumppoint = find_closest_jumppoint(); + + if (jumppoint) { set_zone(jumppoint->target()->zone()); if (owner()->control() == (EntityControlable*) this) owner()->set_zone(jumppoint->target()->zone()); entity_eventstate = core::Entity::Jump; entity_location.assign(jumppoint->target()->location() + location() - jumppoint->location()); } else { - core::server()->send(owner(), "Jump failed!"); entity_eventstate = core::Entity::Normal; } ship_jumpdrive_timer = 0; diff --git a/src/game/ship.h b/src/game/ship.h index 568997c..3a62a9d 100644 --- a/src/game/ship.h +++ b/src/game/ship.h @@ -49,7 +49,9 @@ private: bool ship_jumpdrive; float ship_jumpdrive_timer; - float ship_impulsedrive_timer; + float ship_impulsedrive_timer; + + JumpPoint * find_closest_jumppoint(); }; } diff --git a/src/render/camera.cc b/src/render/camera.cc index e708b71..53d27f7 100644 --- a/src/render/camera.cc +++ b/src/render/camera.cc @@ -138,19 +138,22 @@ void Camera::view_next() case Free: // switch camera to Track mode set_mode(Track); - core::application()->notify_message(std::string("view: track")); + con_print << "view: track" << std::endl; + //core::application()->notify_message(core::Message::Info, std::string("view: track")); break; case Track: // switch camera to Cockpit mode set_mode(Cockpit); - core::application()->notify_message(std::string("view: cockpit")); + con_print << "view: cockpit" << std::endl; + //core::application()->notify_message(core::Message::Info, std::string("view: cockpit")); break; case Cockpit: // switch camera to Free mode set_mode(Free); - core::application()->notify_message(std::string("view: free")); + con_print << "view: free" << std::endl; + //core::application()->notify_message(core::Message::Info, std::string("view: free")); break; default: @@ -170,19 +173,22 @@ void Camera::view_previous() case Cockpit: // switch camera to Track mode set_mode(Track); - core::application()->notify_message(std::string("view: track")); + con_print << "view: track" << std::endl; + //core::application()->notify_message(std::string("view: track")); break; case Free: // switch camera to Cockpit mode set_mode(Cockpit); - core::application()->notify_message(std::string("view: cockpit")); + con_print << "view: cockpit" << std::endl; + //core::application()->notify_message(std::string("view: cockpit")); break; case Track: // switch camera to Free mode set_mode(Free); - core::application()->notify_message(std::string("view: free")); + con_print << "view: free" << std::endl; + //core::application()->notify_message(std::string("view: free")); break; default: diff --git a/src/render/render.cc b/src/render/render.cc index e91be23..8fce251 100644 --- a/src/render/render.cc +++ b/src/render/render.cc @@ -22,8 +22,6 @@ namespace render { -GLuint textures[32]; - core::Cvar *r_arraysize = 0; core::Cvar *r_bbox = 0; core::Cvar *r_grid = 0; @@ -32,31 +30,11 @@ core::Cvar *r_sky = 0; core::Cvar *r_wireframe = 0; using model::VertexArray; - VertexArray *vertexarray = 0; -bool texture(const char *filename, size_t id) +void func_list_textures(std::string const &args) { - Image *image = TGA::load(filename); - if (!image) - return false; - - glGenTextures(1, &textures[id]); - glBindTexture(GL_TEXTURE_2D, textures[id]); - - int texture_type; - if (image->channels() == 4) - texture_type = GL_RGBA; - else - texture_type = GL_RGB; - - gluBuild2DMipmaps(GL_TEXTURE_2D, image->channels(), - image->width(), image->height(), texture_type, GL_UNSIGNED_BYTE, image->data()); - - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR); - - return true; + Textures::list(); } void init() @@ -101,12 +79,13 @@ void init() Text::init(); Dust::init(); + + core::Func *func = core::Func::add("list_textures", func_list_textures); + func->set_info("list loaded textures"); } -void shutdown() +void clear() { - con_print << "^BShutting down renderer..." << std::endl; - // clear zone sky textures for (core::Zone::Registry::iterator it = core::Zone::registry().begin(); it != core::Zone::registry().end(); it++) { core::Zone *zone = (*it).second; @@ -132,6 +111,30 @@ void shutdown() // clear vertex array delete vertexarray; vertexarray = 0; +} + +void unload() +{ + clear(); + + Textures::shutdown(); + Textures::init(); + size_t mb = (size_t) r_arraysize->value(); + if (mb < 4 * sizeof(float)) + mb = 4 * sizeof(float); + if (mb > 256) + mb = 256; + (*r_arraysize) = (float) mb; + vertexarray = new VertexArray(mb); + +} +void shutdown() +{ + con_print << "^BShutting down renderer..." << std::endl; + + core::Func::remove("list_textures"); + + clear(); Text::shutdown(); diff --git a/src/render/render.h b/src/render/render.h index 2a8952e..5d8d12f 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -12,8 +12,13 @@ #include "render/camera.h" #include "render/draw.h" +#include "render/dust.h" #include "render/gl.h" +#include "render/jpgfile.h" +#include "render/pngfile.h" +#include "render/image.h" #include "render/text.h" +#include "render/textures.h" #include "render/tga.h" namespace render { @@ -24,6 +29,9 @@ namespace render { /// shutdown the render subsystem void shutdown(); + /// unload render data + void unload(); + extern core::Cvar *r_arraysize; extern core::Cvar *r_bbox; extern core::Cvar *r_grid; diff --git a/src/render/textures.cc b/src/render/textures.cc index a041c32..b6b7f05 100644 --- a/src/render/textures.cc +++ b/src/render/textures.cc @@ -19,14 +19,18 @@ namespace render { std::map<std::string, size_t> Textures::registry; -size_t Textures::index = 0; GLuint Textures::textures[MAXTEXTURES]; void Textures::init() { - clear(); con_print << "^BLoading textures..." << std::endl; + if (registry.size()) { + clear(); + } else { + memset(textures,0, sizeof(textures)); + } + // "no texture" bitmap load("textures/common/notex"); @@ -51,14 +55,54 @@ void Textures::shutdown() clear(); } +void Textures::list() +{ + for (iterator it = registry.begin(); it != registry.end(); it++) { + con_print << " " << (*it).first << " " << (*it).second << std::endl; + } + con_print << registry.size() << " loaded textures" << std::endl; +} + void Textures::clear() { - if (index) - glDeleteTextures(index, textures); + for (size_t i=0; i < MAXTEXTURES; i++) { + if (textures[i]) { + glDeleteTextures(1, &textures[i]); + } + } registry.clear(); memset(textures,0, sizeof(textures)); - index = 0; +} + +void Textures::unload(std::string name) +{ + iterator it = registry.find(name); + if (it != registry.end()) { + con_debug << " unloading " << (*it).first << std::endl; + size_t id = (*it).second; + if (textures[id]) { + glDeleteTextures(1, &textures[id]); + } + registry.erase(it); + + } +} + +void Textures::unload(size_t id) +{ + // find in map + for (iterator it = registry.begin(); it != registry.end(); it++) { + if ((*it).second == id) { + con_debug << " unloading " << (*it).first << std::endl; + size_t id = (*it).second; + if (textures[id]) { + glDeleteTextures(1, &textures[id]); + } + registry.erase(it); + break; + } + } } size_t Textures::load(std::string name, bool filter) @@ -68,7 +112,12 @@ size_t Textures::load(std::string name, bool filter) if (it != registry.end()) return (*it).second; - if (index == MAXTEXTURES) { + // find first available texture + size_t id = 0; + while ((id < MAXTEXTURES) && (textures[id])) { + id++; + } + if (id == MAXTEXTURES) { con_error << "Texture limit " << MAXTEXTURES << " exceeded!" << std::endl; registry[name] = 0; return 0; @@ -105,8 +154,6 @@ size_t Textures::load(std::string name, bool filter) return 0; } - size_t id = index; - glGenTextures(1, &textures[id]); glBindTexture(GL_TEXTURE_2D, textures[id]); @@ -123,7 +170,6 @@ size_t Textures::load(std::string name, bool filter) // add to the registry registry[name] = id; - index++; // delete image data delete image; @@ -157,7 +203,7 @@ size_t Textures::bind(std::string name, bool filter) size_t Textures::bind(size_t texture, bool filter) { size_t id = texture; - if (texture >= index) + if (!textures[id]) id = 0; glBindTexture(GL_TEXTURE_2D, textures[id]); @@ -175,4 +221,5 @@ void Textures::set_filter(bool filter) glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); } } + } diff --git a/src/render/textures.h b/src/render/textures.h index 43e312d..aa47bfa 100644 --- a/src/render/textures.h +++ b/src/render/textures.h @@ -43,15 +43,22 @@ public: /// find the texture index for a given name static size_t find(std::string name); + /// unload a texture + static void unload(size_t id); + + /// unload a texture + static void unload(std::string name); + + /// list loaded textures + static void list(); + private: static void clear(); - static void set_filter(bool filter); typedef std::map<std::string, size_t>::iterator iterator; static std::map<std::string, size_t> registry; - static size_t index; static GLuint textures[MAXTEXTURES]; }; |