From a185c11f2397c0296a4b62cc266b4fa00a63c1e2 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Wed, 14 May 2008 21:07:10 +0000 Subject: console, camera & interpolation --- src/client/camera.cc | 129 ++++++++--- src/client/chat.cc | 51 ++++- src/client/client.cc | 16 +- src/client/console.cc | 536 +++++++++++++++++++++----------------------- src/client/console.h | 84 ++++--- src/client/input.cc | 20 +- src/client/view.cc | 10 +- src/core/application.cc | 26 ++- src/core/application.h | 4 + src/core/cvar.cc | 1 + src/core/cvar.h | 2 + src/core/gameconnection.cc | 4 +- src/core/gameinterface.cc | 207 +++++++++-------- src/core/gameinterface.h | 4 +- src/core/gameserver.cc | 10 +- src/core/gameserver.h | 1 + src/core/netconnection.cc | 14 +- src/game/game.cc | 2 +- src/math/functions.cc | 10 +- src/render/draw.cc | 4 +- src/server/console.cc | 75 +------ src/server/console.h | 13 +- src/server/server.cc | 5 +- src/sys/consoleinterface.cc | 129 +++++++++++ src/sys/consoleinterface.h | 39 ++-- src/sys/sys.cc | 16 +- src/sys/sys.h | 4 +- 27 files changed, 808 insertions(+), 608 deletions(-) (limited to 'src') diff --git a/src/client/camera.cc b/src/client/camera.cc index 29310fc..21bf930 100644 --- a/src/client/camera.cc +++ b/src/client/camera.cc @@ -28,6 +28,7 @@ math::Vector3f target; math::Vector3f eye; math::Axis axis; +const float MIN_DELTA = 10e-10; // current camera mode Mode mode; @@ -86,10 +87,18 @@ void set_mode(Mode newmode) { target_pitch = 0.0f; distance = 0.4f; + axis.clear(); + switch(newmode) { case Track: // switch camera to Track mode mode = Track; + if (core::localcontrol()) { + if (core::localcontrol()->state()) + axis.assign(core::localcontrol()->state()->axis()); + else + axis.assign(core::localcontrol()->axis()); + } break; case Free: @@ -148,7 +157,7 @@ void next_mode() void draw(float seconds) { math::Matrix4f matrix; - + math::Axis target_axis; float d = 0; if (!core::localcontrol()) { @@ -165,37 +174,102 @@ void draw(float seconds) distance = 20.0f; } else { - if (mode == Overview) set_mode(Track); if (core::localcontrol()->state()) { target.assign(core::localcontrol()->state()->location()); - axis.assign(core::localcontrol()->state()->axis()); + target_axis.assign(core::localcontrol()->state()->axis()); } else { target.assign(core::localcontrol()->location()); - axis.assign(core::localcontrol()->axis()); + target_axis.assign(core::localcontrol()->axis()); } - + if (mode == Track) { - if (core::localcontrol()->state() && core::localcontrol()->model()) { - target -= (core::localcontrol()->model()->maxbbox().x + 0.15f) * core::localcontrol()->state()->axis().forward(); - - target += (core::localcontrol()->model()->maxbbox().z + 0.3f ) * - core::localcontrol()->state()->axis().up(); + float cosangle; + float angle; + float side; + float u; + const float cam_speed = seconds * 4 ; + + math::Vector3f n; + math::Vector3f p; + + // camera axis: pitch + + // project target_axis.up() into the plane with axis->left() normal + n = axis.left(); + p = target_axis.up(); + u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); + p = target_axis.up() + u * n; + + side = axis.forward().x * p.x + + axis.forward().y * p.y + + axis.forward().z * p.z; + + if ((fabs(side) - MIN_DELTA > 0)) { + + cosangle = math::dotproduct(p, axis.up()); + if (fabs(cosangle) + MIN_DELTA < 1 ) { + angle = acos(cosangle) * 180.0f / M_PI; + angle = math::sgnf(side) * angle * cam_speed; + axis.change_pitch(-angle); + } } - // make the camera swing while turning - target_direction = core::localcontrol()->target_direction; - target_pitch = core::localcontrol()->target_pitch; + // camera axis: direction + + // project target_axis.forward() into the plane with axis.up() normal + n = axis.up(); + p = target_axis.forward(); + u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); + p = target_axis.forward() + u * n; + + side = axis.left().x * p.x + + axis.left().y * p.y + + axis.left().z * p.z; + + if ((fabs(side) - MIN_DELTA > 0)) { + + cosangle = math::dotproduct(p, axis.forward()); + if (fabs(cosangle) + MIN_DELTA < 1 ) { + angle = acos(cosangle) * 180.0f / M_PI; + angle = math::sgnf(side) * angle * cam_speed; + axis.change_direction(angle); + } + } - yaw_target = - 30 * target_direction; - pitch_target = - 30 * target_pitch; - //pitch_target = pitch_track - 30 * target_pitch; + // camera axis: roll + + // project target_axis.up() into the plane with axis.forward() normal + n = axis.forward(); + p = target_axis.up(); + u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); + p = target_axis.up() + u * n; + + side = axis.left().x * p.x + + axis.left().y * p.y + + axis.left().z * p.z; + + if ((fabs(side) - MIN_DELTA > 0)) { + + cosangle = math::dotproduct(p, axis.up()); + if (fabs(cosangle) + MIN_DELTA < 1 ) { + angle = acos(cosangle) * 180.0f / M_PI; + angle = math::sgnf(side) * angle * cam_speed; + axis.change_roll(angle); + } + } distance = 0.0f; + if (core::localcontrol()->model()) { + target -= (core::localcontrol()->model()->maxbbox().x + 0.1f) * axis.forward(); + target += (core::localcontrol()->model()->maxbbox().z + 0.1f ) * axis.up(); + } + } else if (mode == Free) { + axis.assign(target_axis); yaw_target = yaw_current - 90 * target_direction; pitch_target = pitch_current - 90 * target_pitch; @@ -205,26 +279,25 @@ void draw(float seconds) } else { distance = 1.0f; } - - } else if (mode == Cockpit) { - if (core::localcontrol()->state() && core::localcontrol()->model()) - target += (core::localcontrol()->model()->maxbbox().x+0.05) * - core::localcontrol()->state()->axis().forward(); - - distance = 0.0f; - } - - if (mode != Cockpit) { // adjust direction d = degrees180f(yaw_current - yaw_target); yaw_current = degrees360f( yaw_current - d * seconds); axis.change_direction(yaw_current); - // adjust pitch target + // adjust pitch d = degrees180f(pitch_current - pitch_target); - pitch_current = degrees360f(pitch_current - d *seconds); + pitch_current = degrees360f(pitch_current - d * seconds); axis.change_pitch(pitch_current); + + } else if (mode == Cockpit) { + axis.assign(target_axis); + + if (core::localcontrol()->state() && core::localcontrol()->model()) + target += (core::localcontrol()->model()->maxbbox().x+0.05) * + core::localcontrol()->state()->axis().forward(); + + distance = 0.0f; } } diff --git a/src/client/chat.cc b/src/client/chat.cc index 1953390..9171387 100644 --- a/src/client/chat.cc +++ b/src/client/chat.cc @@ -4,6 +4,7 @@ the terms and conditions of the GNU General Public License version 2 */ +#include "auxiliary/functions.h" #include "core/core.h" #include "client/chat.h" #include "client/console.h" @@ -71,24 +72,54 @@ void draw() { using namespace render; - if (console::visible() || !visible()) + if (console()->visible() || !visible()) return; - size_t width = (size_t) (video::width / Text::fontwidth()) - 7; - size_t draw_pos = 0; - while (input_pos - draw_pos > width) - draw_pos += 2; + size_t width = (size_t) (video::width / Text::fontwidth()) - 8; + float y = video::height*8/10; + Text::draw(4, y, "^BSay^F:^B "); - // draw the chat input - float y = video::height * 8.0 / 10.0; + std::string firstpart((*history_pos).substr(0, input_pos)); + size_t draw_width = 0; + const char *c = firstpart.c_str(); - Text::draw(4 , y, "^Bsay^F:^B"); - Text::draw(4+Text::fontwidth()*5 , y, (*history_pos).substr(draw_pos, width)); + while (*c) { + if (aux::is_color_code(c)) { + c++; + } else { + draw_width++; + } + c++; + } + + c = firstpart.c_str(); + while (*c && draw_width > width - 2) { + if (aux::is_color_code(c)) { + c++; + Text::setcolor(*c); + } else { + draw_width--; + } + c++; + } + + if (*c) { + Text::draw(4+5*Text::fontwidth(), y, c); + } + + if (input_pos < (*history_pos).size()) { + // FIXME limit to width + if (input_pos > 1 && aux::is_color_code((*history_pos).c_str() + input_pos -1)) { + Text::setcolor((*history_pos)[input_pos]); + } + c = (*history_pos).c_str() + input_pos; + Text::draw(4+Text::fontwidth()*(draw_width+5), y, c); + } // draw cursor if ((core::application()->time() - ::floorf(core::application()->time())) < 0.5f) { std::string cursor("^B_"); - Text::draw(4+Text::fontwidth()*(input_pos - draw_pos+5), y, cursor); + Text::draw(4+Text::fontwidth()*(draw_width+5), y , cursor); } } diff --git a/src/client/client.cc b/src/client/client.cc index 97c0128..85dec27 100644 --- a/src/client/client.cc +++ b/src/client/client.cc @@ -25,6 +25,7 @@ namespace client core::Cvar *cl_framerate = 0; //--- private definition ------------------------------------------ + /// client application implementation class Client : public core::Application { @@ -49,10 +50,8 @@ Client app; void func_r_restart(std::stringstream &args) { video::shutdown(); - console::flush(); if (!video::init()) { - console::flush(); app.quit(1); } } @@ -87,6 +86,7 @@ void Client::init(int count, char **arguments) // initialize core core::Cvar::sv_dedicated = core::Cvar::set("sv_private", "0"); core::Application::init(count, arguments); + Console::init(); // client variables core::Cvar *cvar = 0; @@ -104,12 +104,10 @@ void Client::init(int count, char **arguments) // Initialize the video subsystem if (!video::init()) { - console::flush(); quit(1); } // initialize console - console::init(); chat::init(); // initialize input @@ -128,6 +126,9 @@ void Client::run() Uint32 client_framerate = (Uint32)(1000/120); Uint32 elapsed = 0; + console()->flush(); + console()->clear_notify(); + while (true) { Uint32 chrono = SDL_GetTicks(); @@ -155,24 +156,19 @@ void Client::run() void Client::shutdown() { con_print << "^BShutting down client..." << std::endl; - console::flush(); // remove engine functions core::Func::remove("r_restart"); chat::shutdown(); - console::shutdown(); - console::flush(); + Console::shutdown(); input::shutdown(); - console::flush(); video::shutdown(); - console::flush(); core::Application::shutdown(); - console::flush(); quit(0); } diff --git a/src/client/console.cc b/src/client/console.cc index 4c65581..f692db4 100644 --- a/src/client/console.cc +++ b/src/client/console.cc @@ -4,12 +4,12 @@ the terms and conditions of the GNU General Public License version 2 */ +#include "client/console.h" #include "auxiliary/functions.h" #include "core/core.h" #include "filesystem/filesystem.h" #include "render/render.h" #include "render/textures.h" -#include "client/console.h" #include "client/video.h" #include "client/keyboard.h" @@ -19,116 +19,225 @@ namespace client { -namespace console { +Console client_console; -//--- private definition ------------------------------------------ +Console *console() { + return &client_console; +} +//--- engine functions -------------------------------------------- -/// private client console implementation -class Console : public sys::ConsoleInterface { -public: - /// stream to send normal messages too - virtual std::ostream & messagestream(); +void func_con_toggle(std::string const &args) +{ + + console()->toggle(); +} - /// stream to send warning messages too - virtual std::ostream & warningstream(); +//--- public ------------------------------------------------------ - /// stream to send error messages too - virtual std::ostream & errorstream(); - - /// stream to send debug messages too - virtual std::ostream & debugstream(); +void Console::init() +{ + con_print << "^BInitializing console..." << std::endl; - /// flush buffered messages - virtual void flush(); + core::Func *func = core::Func::add("con_toggle", (core::FuncPtr) func_con_toggle); + func->set_info("toggle console on or off"); + console()->load_history(); +} + +void Console::shutdown() +{ + con_print << "^BShutting down console..." << std::endl; - /// console text buffer - std::stringstream buffer; -}; + console()->save_history(); -// private client console object -Console console; + // remove engine functions + core::Func::remove("con_toggle"); +} + +//--- Console ----------------------------------------------------- + +Console::Console() +{ + clear(); +} -// console text data -std::deque text; +Console::~Console() +{ + history.clear(); +} -// input history -std::deque history; -std::deque::reverse_iterator history_pos; -size_t input_pos = 0; +void Console::clear() +{ + console_visible = false; + console_scroll = 0; + history.clear(); + history.push_back(""); + history_pos = history.rbegin(); + input_pos = 0; -// console visibility -bool console_visible = false; -size_t console_scroll = 0; + clear_notify(); -// notifications -size_t notify_pos = 0; -std::string notify_text[MAXNOTIFYLINES]; -float notify_time[MAXNOTIFYLINES]; +} -//--- engine functions -------------------------------------------- +void Console::draw() { + if (visible()) + draw_console(); + else + draw_notify(); +} -void func_con_toggle(std::string const &args) +void Console::toggle() { + console_visible = !console_visible; - std::istringstream argstream(args); - int i; + if (console_visible) { + console_scroll = 0; + input_pos = 0; + + history_pos = history.rbegin(); + (*history_pos).clear(); - if (argstream >> i) { - if (i) console_visible = false; else console_visible = true; + SDL_WM_GrabInput(SDL_GRAB_OFF); + SDL_ShowCursor(SDL_ENABLE); + } else { + SDL_WM_GrabInput(SDL_GRAB_ON); + SDL_ShowCursor(SDL_DISABLE); + clear_notify(); } - toggle(); + + setkeyboardmode(visible()); } -//--- public ------------------------------------------------------ - -void clear_notify() +void Console::keypressed(int key) { - for (size_t i=0; i < MAXNOTIFYLINES; i++) { - notify_text[i].clear(); - notify_time[i] = 0; + std::deque::reverse_iterator upit; + + switch( key ) { + case SDLK_TAB: + core::CommandBuffer::complete( (*history_pos), input_pos); + break; + case SDLK_RETURN: + if ((*history_pos).size()) { + // store input into history + while (history.size() >= MAXHISTOLINES) { + history.pop_front(); + } + + core::cmd() << (*history_pos) << std::endl; + con_print << "^B>" << (*history_pos) << std::endl; + (*history.rbegin()) = (*history_pos); + + history.push_back(""); + history_pos = history.rbegin(); + input_pos = 0; + } + break; + case SDLK_UP: + upit = history_pos; + ++upit; + if (upit != history.rend()) { + history_pos = upit; + input_pos = (*history_pos).size(); + } + break; + case SDLK_DOWN: + if (history_pos != history.rbegin()) { + --history_pos; + input_pos = (*history_pos).size(); + } + break; + case SDLK_HOME: + input_pos = 0; + break; + case SDLK_END: + input_pos = (*history_pos).size(); + break; + case SDLK_LEFT: + if (input_pos > 0) + input_pos--; + break; + case SDLK_RIGHT: + if (input_pos < (*history_pos).size()) + input_pos++; + break; + case SDLK_BACKSPACE: + if ((*history_pos).size() && input_pos) { + (*history_pos).erase(input_pos-1, 1); + input_pos--; + } + break; + case SDLK_PAGEUP: + console_scroll +=5; + if (console_scroll > consoleinterface_text.size()) console_scroll = consoleinterface_text.size(); + break; + case SDLK_PAGEDOWN: + if (console_scroll > 5) console_scroll -=5; + else console_scroll = 0; + break; + default: + if ((key >= 32 ) && (key <175)) { + if (input_pos == (*history_pos).size()) + (*history_pos) += (char)key; + else + (*history_pos).insert(input_pos, 1, (char)key); + input_pos++; + } + break; } + + } -void init() +void Console::save_history() { - con_print << "^BInitializing console..." << std::endl; - - console_visible = false; - - // add engine functions - core::Func *func = core::Func::add("con_toggle", (core::FuncPtr) func_con_toggle); - func->set_info("toggle console on or off"); - clear_notify(); - text.clear(); - console_scroll = 0; + if (history.size() <= 1) + return; - history.clear(); - history.push_back(""); - history_pos = history.rbegin(); - input_pos = 0; + std::string filename(filesystem::writedir); + filename.append("history.txt"); + std::ofstream ofs(filename.c_str()); - load_history(); + if (!ofs.is_open()) { + con_warn << "Could not write " << filename << std::endl; + return; + } + std::deque::iterator it; + size_t l = 1; + for (it = history.begin(); it != history.end(); it++) { + if (l < history.size()) + ofs << (*it) << std::endl; + l++; + } + + ofs.close(); } -void shutdown() +void Console::load_history() { - con_print << "^BShutting down console..." << std::endl; - - save_history(); + std::string filename(filesystem::writedir); + filename.append("history.txt"); + std::ifstream ifs(filename.c_str(), std::ifstream::in); - // remove engine functions - //core::Func::remove("con_toggle"); - - text.clear(); - console_scroll = 0; + if (!ifs.is_open()) { + con_warn << "Could not read " << filename << std::endl; + return; + } history.clear(); + char line[MAXCMDSIZE]; + while (ifs.getline(line, MAXCMDSIZE-1)) { + history.push_back(line); + } + + ifs.close(); + + history.push_back(""); + history_pos = history.rbegin(); input_pos = 0; } -void draw_notify() +void Console::draw_notify() { using namespace render; @@ -150,6 +259,7 @@ void draw_notify() const char *c = linedata.c_str(); char pen = 'N'; + char wordpen = 'N'; while (*c) { @@ -170,7 +280,7 @@ void draw_notify() h += Text::fontheight(); line.clear(); line += '^'; - line += pen; + line += wordpen; line_length = 0; } } @@ -180,6 +290,7 @@ void draw_notify() word.clear(); word_length = 0; + wordpen = pen; // new line if (*c == '\n' ) { @@ -205,7 +316,7 @@ void draw_notify() h += Text::fontheight(); line.clear(); line += '^'; - line += pen; + line += wordpen; line_length = 0; } @@ -214,6 +325,7 @@ void draw_notify() word.clear(); word_length = 0; + wordpen = pen; } } @@ -225,7 +337,7 @@ void draw_notify() } } -void draw_console() +void Console::draw_console() { using namespace render; @@ -251,17 +363,17 @@ void draw_console() gl::color(0.0f, 1.0f, 0.0f, 0.5f); Text::draw(video::width-Text::fontwidth()*(version.size()+1), video::height*con_height-Text::fontheight()-4, version); - // draw the console text - if (console_scroll > text.size()) - console_scroll = text.size(); + // draw the console consoleinterface_text + if (console_scroll > consoleinterface_text.size()) + console_scroll = consoleinterface_text.size(); size_t height = (size_t) (video::height * con_height / Text::fontheight()) -1; size_t width = (size_t) ((video::width-8) / Text::fontwidth()); - size_t bottom = text.size() - console_scroll; + size_t bottom = consoleinterface_text.size() - console_scroll; size_t current_line = 0; std::deque lines; - for (std::deque::iterator it = text.begin(); it != text.end() && current_line < bottom; it++) { + for (std::deque::iterator it = consoleinterface_text.begin(); it != consoleinterface_text.end() && current_line < bottom; it++) { if (current_line >= bottom - height) { std::string linedata(*it); linedata += '\n'; @@ -274,6 +386,7 @@ void draw_console() const char *c = linedata.c_str(); char pen = 'N'; + char wordpen = 'N'; while (*c) { @@ -293,7 +406,7 @@ void draw_console() lines.push_back(line); line.clear(); line += '^'; - line += pen; + line += wordpen; line_length = 0; } } @@ -303,6 +416,7 @@ void draw_console() word.clear(); word_length = 0; + wordpen = pen; // new line if (*c == '\n' ) { @@ -326,7 +440,7 @@ void draw_console() lines.push_back(line); line.clear(); line += '^'; - line += pen; + line += wordpen; line_length = 0; } @@ -335,6 +449,7 @@ void draw_console() word.clear(); word_length = 0; + wordpen = pen; } } @@ -354,233 +469,86 @@ void draw_console() // draw the console input - size_t draw_pos = 0; y = video::height*con_height - Text::fontheight() - 4; - - while (input_pos - draw_pos > width) - draw_pos += 2; - Text::draw(4, y, "^B>"); - Text::draw(4+Text::fontwidth(), y , (*history_pos).substr(draw_pos, width-1)); - // draw cursor - if ((core::application()->time() - ::floorf(core::application()->time())) < 0.5f) { - std::string cursor("^B_"); - Text::draw(4+Text::fontwidth()*(input_pos-draw_pos+1), y , cursor); - } - -} - -void draw(){ - if (visible()) - draw_console(); - else - draw_notify(); -} + std::string firstpart((*history_pos).substr(0, input_pos)); + size_t draw_width = 0; + const char *c = firstpart.c_str(); -void flush() -{ - char line[MAXCMDSIZE]; - while(console.buffer.getline(line, MAXCMDSIZE-1)) { - while (text.size() >= MAXCONLINES) { - text.pop_front(); + while (*c) { + if (aux::is_color_code(c)) { + c++; + } else { + draw_width++; } - text.push_back(std::string(line)); - - // save notification - notify_text[notify_pos] = line; - notify_time[notify_pos] = core::application()->time(); - notify_pos = (notify_pos+1) % MAXNOTIFYLINES; - - // print to stdout - std::cout << line << std::endl; + c++; } - - console.buffer.clear(); -} - -void toggle() -{ - console_visible = !console_visible; - - if (console_visible) { - console_scroll = 0; - input_pos = 0; - history_pos = history.rbegin(); - (*history_pos).clear(); - - SDL_WM_GrabInput(SDL_GRAB_OFF); - SDL_ShowCursor(SDL_ENABLE); - } else { - SDL_WM_GrabInput(SDL_GRAB_ON); - SDL_ShowCursor(SDL_DISABLE); - clear_notify(); + c = firstpart.c_str(); + while (*c && draw_width > width - 2) { + if (aux::is_color_code(c)) { + c++; + Text::setcolor(*c); + } else { + draw_width--; + } + c++; } - - setkeyboardmode(console::visible()); -} - -void keypressed(int key) -{ - std::deque::reverse_iterator upit; - - switch( key ) { - case SDLK_TAB: - core::CommandBuffer::complete( (*history_pos), input_pos); - break; - case SDLK_RETURN: - if ((*history_pos).size()) { - // store input into history - while (history.size() >= MAXHISTOLINES) { - history.pop_front(); - } - core::cmd() << (*history_pos) << std::endl; - con_print << "^B>" << (*history_pos) << std::endl; - (*history.rbegin()) = (*history_pos); + if (*c) { + Text::draw(4+Text::fontwidth(), y, c); + } - history.push_back(""); - history_pos = history.rbegin(); - input_pos = 0; - } - break; - case SDLK_UP: - upit = history_pos; - ++upit; - if (upit != history.rend()) { - history_pos = upit; - input_pos = (*history_pos).size(); - } - break; - case SDLK_DOWN: - if (history_pos != history.rbegin()) { - --history_pos; - input_pos = (*history_pos).size(); + if (input_pos < (*history_pos).size()) { + // FIXME limit to width + if (input_pos > 1 && aux::is_color_code((*history_pos).c_str() + input_pos -1)) { + Text::setcolor((*history_pos)[input_pos]); } - break; - case SDLK_HOME: - input_pos = 0; - break; - case SDLK_END: - input_pos = (*history_pos).size(); - break; - case SDLK_LEFT: - if (input_pos > 0) - input_pos--; - break; - case SDLK_RIGHT: - if (input_pos < (*history_pos).size()) - input_pos++; - break; - case SDLK_BACKSPACE: - if ((*history_pos).size() && input_pos) { - (*history_pos).erase(input_pos-1, 1); - input_pos--; - } - break; - case SDLK_PAGEUP: - console_scroll +=5; - if (console_scroll > text.size()) console_scroll = text.size(); - break; - case SDLK_PAGEDOWN: - if (console_scroll > 5) console_scroll -=5; - else console_scroll = 0; - break; - default: - if ((key >= 32 ) && (key <175)) { - if (input_pos == (*history_pos).size()) - (*history_pos) += (char)key; - else - (*history_pos).insert(input_pos, 1, (char)key); - input_pos++; - } - break; + c = (*history_pos).c_str() + input_pos; + Text::draw(4+Text::fontwidth()*(draw_width+1), y, c); } - -} - -bool visible() -{ - return console_visible; -} - -void save_history() -{ - - if (history.size() <= 1) - return; - - std::string filename(filesystem::writedir); - filename.append("history.txt"); - std::ofstream ofs(filename.c_str()); - - if (!ofs.is_open()) { - con_warn << "Could not write " << filename << std::endl; - return; - } - std::deque::iterator it; - size_t l = 1; - for (it = history.begin(); it != history.end(); it++) { - if (l < history.size()) - ofs << (*it) << std::endl; - l++; + // draw cursor + if ((core::application()->time() - ::floorf(core::application()->time())) < 0.5f) { + std::string cursor("^B_"); + Text::draw(4+Text::fontwidth()*(draw_width+1), y , cursor); } - ofs.close(); } -void load_history() -{ - std::string filename(filesystem::writedir); - filename.append("history.txt"); - std::ifstream ifs(filename.c_str(), std::ifstream::in); - if (!ifs.is_open()) { - con_warn << "Could not read " << filename << std::endl; - return; - } - - history.clear(); - char line[MAXCMDSIZE]; - while (ifs.getline(line, MAXCMDSIZE-1)) { - history.push_back(line); +void Console::clear_notify() +{ + for (size_t i=0; i < MAXNOTIFYLINES; i++) { + notify_text[i].clear(); + notify_time[i] = 0; } - - ifs.close(); - - history.push_back(""); - history_pos = history.rbegin(); - input_pos = 0; + notify_pos = 0; } -//--- private ----------------------------------------------------- void Console::flush() { - console::flush(); -} + char line[MAXCMDSIZE]; -std::ostream & Console::messagestream() -{ - return (buffer << "^N"); -} + while(consoleinterface_buffer.getline(line, MAXCMDSIZE-1)) { -std::ostream & Console::warningstream() -{ - return (buffer << "^W"); -} + while (consoleinterface_text.size() >= sys::MAXCONLINES) { + consoleinterface_text.pop_front(); + } + consoleinterface_text.push_back(std::string(line)); -std::ostream & Console::errorstream() -{ - return (buffer << "^R"); -} + // save notification + notify_text[notify_pos] = line; + notify_time[notify_pos] = core::application()->time(); + notify_pos = (notify_pos+1) % MAXNOTIFYLINES; -std::ostream & Console::debugstream() -{ - return (buffer << "^D"); + // print to stdout + print_ansi(line); + std::cout << std::endl; + } + + consoleinterface_buffer.clear(); } -} // namespace console - } // namespace client diff --git a/src/client/console.h b/src/client/console.h index dc831b7..2f8d6a0 100644 --- a/src/client/console.h +++ b/src/client/console.h @@ -9,54 +9,70 @@ #include "sys/consoleinterface.h" -#include -#include +namespace client { -const size_t MAXCONLINES = 2048; -const size_t MAXHISTOLINES = 512; const size_t MAXNOTIFYLINES = 3; +const size_t MAXHISTOLINES = 512; -namespace client { +/// client console implementation +class Console : public sys::ConsoleInterface { +public: + Console(); + virtual ~Console(); -/// the client console -namespace console { + virtual void flush(); -/// initialize client console -/** Adds the engine functions for the client console - */ -void init(); + void draw_console(); -/// shutdown the client console -/** Removes the engine functions for the client console - */ -void shutdown(); + void draw_notify(); -/// flush buffer messages and print to stdout -void flush(); - -/// draw the console -void draw(); + /// clear notifications + void clear_notify(); -/// toggle the console on or off -void toggle(); + /// draw client notifications or console text + void draw(); -/// handle keyboard input -void keypressed(int key); + /// toggle the console on or off + void toggle(); -/// true of the console is visible -bool visible(); + /// handle keyboard input + void keypressed(int key); -/// load input history -void load_history(); + /// true of the console is visible + inline bool visible() { return console_visible; } -/// save input history -void save_history(); + /// load input history + void load_history(); -extern size_t notify_pos; -extern std::string notify_text[MAXNOTIFYLINES]; -extern float notify_time[MAXNOTIFYLINES]; + /// save input history + void save_history(); -} + /// clear console + void clear(); + + /// initialize client console + static void init(); + + /// shutdown the client console + static void shutdown(); + +private: + // notifications + size_t notify_pos; + std::string notify_text[MAXNOTIFYLINES]; + float notify_time[MAXNOTIFYLINES]; + + // input history + std::deque history; + std::deque::reverse_iterator history_pos; + size_t input_pos; + + bool console_visible; + size_t console_scroll; + +}; + +Console *console(); } diff --git a/src/client/input.cc b/src/client/input.cc index f40591c..22db6bc 100644 --- a/src/client/input.cc +++ b/src/client/input.cc @@ -221,31 +221,31 @@ void frame(float seconds) mouse_y = event.motion.y; break; case SDL_MOUSEBUTTONDOWN: - if (!console::visible() && core::application()->connected() && core::localcontrol()) + if (!console()->visible() && core::application()->connected() && core::localcontrol()) mousebuttonpressed(event.button); break; case SDL_KEYUP: if (event.key.keysym.sym == SDLK_PRINT) { video::screenshot(); - } else if (!chat::visible() && !console::visible() && + } else if (!chat::visible() && !console()->visible() && core::application()->connected() && core::localcontrol()) // send key events to the game world keyreleased(event.key.keysym); break; case SDL_KEYDOWN: - if (chat::visible() && !console::visible() && (event.key.keysym.sym == SDLK_ESCAPE)) { + if (chat::visible() && !console()->visible() && (event.key.keysym.sym == SDLK_ESCAPE)) { chat::toggle(); } else if (event.key.keysym.sym == '`' || event.key.keysym.sym == '~' || (event.key.keysym.sym == SDLK_ESCAPE)) { //last_control = 0; - console::toggle(); + console()->toggle(); - if (console::visible() && chat::visible()) + if (console()->visible() && chat::visible()) chat::toggle(); - } else if (console::visible()) { + } else if (console()->visible()) { // send key events to the console - console::keypressed(translate_keysym(event.key.keysym)); + console()->keypressed(translate_keysym(event.key.keysym)); } else if (chat::visible()) { if(event.key.keysym.sym == SDLK_ESCAPE) { @@ -270,7 +270,7 @@ void frame(float seconds) } - if (!console::visible() && core::application()->connected() && core::localcontrol()) { + if (!console()->visible() && core::application()->connected() && core::localcontrol()) { if (cl_mousecontrol->value()) { // the mouse will not react if it is in the deadzone @@ -302,8 +302,8 @@ void frame(float seconds) } if ((camera::mode == camera::Track) || (camera::mode == camera::Cockpit)) { - local_direction = mouse_direction; - local_pitch = mouse_pitch; + local_direction = mouse_direction * math::absf(mouse_direction); + local_pitch = mouse_pitch * math::absf(mouse_pitch); } else if (camera::mode == camera::Free) { // squared values to smoothen camera movement camera::set_direction( -mouse_direction * math::absf(mouse_direction)); diff --git a/src/client/view.cc b/src/client/view.cc index 63c373e..e2c8687 100644 --- a/src/client/view.cc +++ b/src/client/view.cc @@ -128,7 +128,7 @@ void draw_status() { using namespace render; - if (console::visible()) + if (console()->visible()) return; // print the status in the upper left corner @@ -171,7 +171,7 @@ void draw_status() void draw_cursor() { - if (!core::localcontrol() || console::visible()) + if (!core::localcontrol() || console()->visible()) return; float crosshair_size = 48.0f; @@ -222,7 +222,7 @@ void frame(float seconds) fps = 9999; // flush console messages - console::flush(); + console()->flush(); // Clear the color and depth buffers. gl::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -234,7 +234,7 @@ void frame(float seconds) gl::loadidentity(); // FIXME width must always be one - const float frustumsize = 0.5f; + const float frustumsize = 0.25f; gl::frustum(-frustumsize*video::aspect, frustumsize*video::aspect, -frustumsize, frustumsize, 1.0f, 1024.0f); gl::matrixmode(GL_MODELVIEW); // map world to screen coordinates @@ -263,7 +263,7 @@ void frame(float seconds) // draw text elements Text::setfont("bitmaps/fonts/console", 12, 18); - console::draw(); + console()->draw(); chat::draw(); Text::setfont("bitmaps/fonts/gui", 16, 24); diff --git a/src/core/application.cc b/src/core/application.cc index 79f4a28..67bb952 100644 --- a/src/core/application.cc +++ b/src/core/application.cc @@ -100,10 +100,10 @@ Application::Application() application_game = 0; #ifndef _WIN32 - //sys::signal(SIGHUP, signal_handler); - //sys::signal(SIGINT, signal_handler); - //sys::signal(SIGQUIT, signal_handler); - //sys::signal(SIGTERM, signal_handler); + sys::signal(SIGHUP, signal_handler); + sys::signal(SIGINT, signal_handler); + sys::signal(SIGQUIT, signal_handler); + sys::signal(SIGTERM, signal_handler); #endif } @@ -117,7 +117,7 @@ void Application::init(int count, char **arguments) { con_debug << "Debug messages enabled\n"; con_print << "^BInitializing core...\n"; - + filesystem::init(); CommandBuffer::init(); @@ -156,6 +156,14 @@ void Application::init(int count, char **arguments) Cvar::net_framerate = Cvar::get("net_framerate", "25", Cvar::Archive); Cvar::net_framerate->set_info("[int] network framerate in frames/sec"); +#ifdef _WIN32 + Cvar::con_ansi = Cvar::get("con_ansi", "0", Cvar::Archive); +#else + Cvar::con_ansi = Cvar::get("con_ansi", "1", Cvar::Archive); +#endif + Cvar::con_ansi->set_info("[bool] console ANSI colors"); + sys::ConsoleInterface::instance()->set_ansi(Cvar::con_ansi->value()); + #ifdef _WIN32 // Initialize win32 socket library WSADATA wsa_data; @@ -217,6 +225,8 @@ void Application::shutdown() void Application::quit(int status) { + console()->flush(); + sys::quit(status); } @@ -264,6 +274,8 @@ void Application::disconnect() void Application::frame(float seconds) { + console()->flush(); + // execute commands in the buffer CommandBuffer::exec(); @@ -278,9 +290,11 @@ void Application::frame(float seconds) // run a game interface frame application_game->frame(seconds); - + if (!application_game->running()) disconnect(); + + console()->flush(); } void Application::save_config() diff --git a/src/core/application.h b/src/core/application.h index 01f34cf..bec53d9 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -7,6 +7,7 @@ #ifndef __INCLUDED_CORE_APPLICATION_H__ #define __INCLUDED_CORE_APPLICATION_H__ +#include "sys/sys.h" #include "core/commandbuffer.h" #include "core/netserver.h" #include "core/netconnection.h" @@ -86,6 +87,9 @@ inline Application *application() { return Application::instance(); } /// pointer to the current GameInterface inline GameInterface *game() { return Application::instance()->game(); } +/// pointer to the console +inline sys::ConsoleInterface *console() { return sys::ConsoleInterface::instance(); }; + } // namespace core #endif // __INCLUDED_CORE_APPLICATION_H__ diff --git a/src/core/cvar.cc b/src/core/cvar.cc index 7593ac3..f8ea746 100644 --- a/src/core/cvar.cc +++ b/src/core/cvar.cc @@ -17,6 +17,7 @@ namespace core { +Cvar *Cvar::con_ansi = 0; Cvar *Cvar::sv_dedicated = 0; Cvar *Cvar::sv_private = 0; Cvar *Cvar::sv_framerate = 0; diff --git a/src/core/cvar.h b/src/core/cvar.h index 4125d3c..69fcae1 100644 --- a/src/core/cvar.h +++ b/src/core/cvar.h @@ -113,6 +113,8 @@ public: static Cvar *sv_private; // client with private server static Cvar *sv_framerate; // server framerate + static Cvar *con_ansi; // console ANSI colors + static Cvar *net_host; // network server ip (default binds to all interfaces) static Cvar *net_port; // network port static Cvar *net_maxclients;// maximum number of connected clients diff --git a/src/core/gameconnection.cc b/src/core/gameconnection.cc index 1d022c5..6090a52 100644 --- a/src/core/gameconnection.cc +++ b/src/core/gameconnection.cc @@ -88,9 +88,7 @@ void GameConnection::frame(float seconds) return; } - if (!Cvar::sv_dedicated->value()) { - update_clientstate(seconds); - } + update_clientstate(seconds); connection_network->frame(seconds); diff --git a/src/core/gameinterface.cc b/src/core/gameinterface.cc index 1f4a5cd..f50c1cc 100644 --- a/src/core/gameinterface.cc +++ b/src/core/gameinterface.cc @@ -18,6 +18,8 @@ namespace core { +const float MIN_DELTA = 10e-10; + void func_list_model(std::string const &args) { model::Model::list(); @@ -97,12 +99,10 @@ void GameInterface::clear() game_clientframetime = 0; } -void GameInterface::reset_clientstate(float servertime) +void GameInterface::reset_clientstate(float timestamp, float prevtimestamp) { - game_previousframetime = game_serverframetime; - game_clientframetime = game_serverframetime; - - game_serverframetime = servertime; + game_previousframetime = prevtimestamp; + game_serverframetime = timestamp; std::map::iterator it; for (it=core::Entity::registry.begin(); it != core::Entity::registry.end(); it++) { @@ -112,121 +112,130 @@ void GameInterface::reset_clientstate(float servertime) if (entity->state() && !(entity->flags() & core::Entity::Static)) entity->state()->assign(entity); } -} - -void GameInterface::update_clientstate(float seconds) -{ - game_clientframetime += seconds; - if (game_clientframetime > game_serverframetime) + if ( game_clientframetime < game_previousframetime) + game_clientframetime = game_previousframetime; + else if ( game_clientframetime > game_serverframetime) game_clientframetime = game_serverframetime; - std::map::iterator it; - for (it=Entity::registry.begin(); it != Entity::registry.end(); it++) { +} + - Entity *entity = (*it).second; +void GameInterface::update_entity_clientstate(Entity *entity) +{ + if (!entity->state()) { + entity->entity_clientstate = new core::ClientState(entity); + entity->entity_clientstate->assign(entity); + } - // update client state - if (!entity->state()) { - entity->entity_clientstate = new core::ClientState(entity); - } + if (!(entity->flags() & core::Entity::Static)) + return; + + if (game_clientframetime < game_serverframetime) { if (!(entity->flags() & core::Entity::Static)) { - + // clientstate location entity->state()->state_location = entity->state()->previouslocation() + - (entity->location() - entity->state()->previouslocation()) * core::game()->timeoffset(); - - if (core::game()->clientframetime() < core::game()->serverframetime()) { - - // http://local.wasp.uwa.edu.au/~pbourke/geometry/planeline/ - float cosangle; - float angle; - float side; - float u; - - math::Vector3f n; - math::Vector3f p; - - // clientstate axis: pitch - - // project entity->axis().up() into the plane with entity->state()->axis()->left() normal - n = entity->state()->axis().left(); - p = entity->axis().up(); - u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); - p = entity->axis().up() + u * n; - - side = entity->state()->axis().forward().x * p.x + - entity->state()->axis().forward().y * p.y + - entity->state()->axis().forward().z * p.z; - - if (fabs(side) > 0.00005f) { - cosangle = math::dotproduct(p, entity->state()->axis().up()); - - if (fabs(cosangle) < 0.99995f) { - angle = acos(cosangle) * 180.0f / M_PI; - angle = math::sgnf(side) * angle * seconds / - (core::game()->serverframetime() - core::game()->clientframetime()); - - entity->state()->state_axis.change_pitch(-angle); - } + (entity->location() - entity->state()->previouslocation()) * timeoffset(); + + // http://local.wasp.uwa.edu.au/~pbourke/geometry/planeline/ + float cosangle; + float angle; + float side; + float u; + float l; + + math::Vector3f n; + math::Vector3f p; + + entity->state()->state_axis.assign(entity->state()->previousaxis()); + // clientstate axis: pitch + + // project entity->axis().up() into the plane with entity->state()->axis()->left() normal + n = entity->state()->axis().left(); + p = entity->axis().up(); + u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); + p = entity->axis().up() + u * n; + + side = entity->state()->axis().forward().x * p.x + + entity->state()->axis().forward().y * p.y + + entity->state()->axis().forward().z * p.z; + + l = p.length(); + if ((fabs(side) - MIN_DELTA > 0)) { + cosangle = math::dotproduct(p, entity->state()->axis().up()); + if (fabs(cosangle) + MIN_DELTA < 1 ) { + angle = acos(cosangle) * 180.0f / M_PI; + angle = math::sgnf(side) * angle * timeoffset(); + entity->state()->state_axis.change_pitch(-angle); } - - // clientstate axis: direction - - // project entity->axis().forward() into the plane with entity->state()->axis().up() normal - n = entity->state()->axis().up(); - p = entity->axis().forward(); - u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); - p = entity->axis().forward() + u * n; - - side = entity->state()->axis().left().x * p.x + - entity->state()->axis().left().y * p.y + - entity->state()->axis().left().z * p.z; - - if (fabs(side) > 0.00005f) { - cosangle = math::dotproduct(p, entity->state()->axis().forward()); - if (fabs(cosangle) < 0.99995f) { - angle = acos(cosangle) * 180.0f / M_PI; - angle = math::sgnf(side) * angle * seconds / - (core::game()->serverframetime() - core::game()->clientframetime()); - - entity->state()->state_axis.change_direction(angle); - } + } + + // clientstate axis: direction + + // project entity->axis().forward() into the plane with entity->state()->axis().up() normal + n = entity->state()->axis().up(); + p = entity->axis().forward(); + u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); + p = entity->axis().forward() + u * n; + + side = entity->state()->axis().left().x * p.x + + entity->state()->axis().left().y * p.y + + entity->state()->axis().left().z * p.z; + + l = p.length(); + if ((fabs(side) - MIN_DELTA > 0)) { + cosangle = math::dotproduct(p, entity->state()->axis().forward()); + if (fabs(cosangle) + MIN_DELTA < 1 ) { + angle = acos(cosangle) * 180.0f / M_PI; + angle = math::sgnf(side) * angle * timeoffset(); + entity->state()->state_axis.change_direction(angle); } - - // clientstate axis: roll - - // project entity->axis().up() into the plane with entity->state()->axis().forward() normal - n = entity->state()->axis().forward(); - p = entity->axis().up(); - u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); - p = entity->axis().up() + u * n; - - side = entity->state()->axis().left().x * p.x + - entity->state()->axis().left().y * p.y + - entity->state()->axis().left().z * p.z; - - if (fabs(side) > 0.00005f) { - cosangle = math::dotproduct(p, entity->state()->axis().up()); + } + + // clientstate axis: roll + + // project entity->axis().up() into the plane with entity->state()->axis().forward() normal + n = entity->state()->axis().forward(); + p = entity->axis().up(); + u = p[0]*n[0] + p[1]*n[1] + p[2]*n[2] / (-n[0]*n[0] - n[1]*n[1] - n[2] * n[2]); + p = entity->axis().up() + u * n; + + side = entity->state()->axis().left().x * p.x + + entity->state()->axis().left().y * p.y + + entity->state()->axis().left().z * p.z; + + l = p.length(); + if ((fabs(side) - MIN_DELTA > 0)) { + cosangle = math::dotproduct(p, entity->state()->axis().up()); + if (fabs(cosangle) + MIN_DELTA < 1 ) { angle = acos(cosangle) * 180.0f / M_PI; - if (fabs(cosangle) < 0.99995f) { - angle = math::sgnf(side) * angle * seconds / - (core::game()->serverframetime() - core::game()->clientframetime()); - - entity->state()->state_axis.change_roll(angle); - } + angle = math::sgnf(side) * angle * timeoffset(); + entity->state()->state_axis.change_roll(angle); } - } - } + } + + } else { + entity->state()->assign(entity); + } +} +void GameInterface::update_clientstate(float seconds) +{ + std::map::iterator it; + for (it=core::Entity::registry.begin(); it != core::Entity::registry.end(); it++) { + update_entity_clientstate((*it).second); } } float GameInterface::timeoffset() { + if (game_clientframetime > game_serverframetime) + return 1; + float d = game_serverframetime - game_previousframetime; if (d <= 0) return 0; diff --git a/src/core/gameinterface.h b/src/core/gameinterface.h index 0edcb1b..19c6886 100644 --- a/src/core/gameinterface.h +++ b/src/core/gameinterface.h @@ -52,11 +52,13 @@ public: void clear(); /// reset the client state - void reset_clientstate(float servertime); + void reset_clientstate(float timestamp, float prevtimestamp); /// update the client state timers void update_clientstate(float seconds); + void update_entity_clientstate(Entity *entity); + /*----- virtual mutators ------------------------------------------ */ /// run one game time frame diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc index 11a8b13..fb828e2 100644 --- a/src/core/gameserver.cc +++ b/src/core/gameserver.cc @@ -34,6 +34,7 @@ GameServer::GameServer() : GameInterface() server_instance = this; server_network = 0; server_time = 0; + server_previoustime = 0; server_frametime = 0.0f; server_maxplayerid = 1; @@ -278,7 +279,7 @@ void GameServer::frame(float seconds) // copy the previous entity state to the client state if (!Cvar::sv_dedicated->value()) { - reset_clientstate(server_time); + reset_clientstate(server_time, server_previoustime); } // run a time frame on each entity @@ -308,7 +309,7 @@ void GameServer::frame(float seconds) // start server frame std::ostringstream framehdr; framehdr.str(""); - framehdr << "frame " << server_time << "\n"; + framehdr << "frame " << server_time << " " << server_previoustime << "\n"; server_network->broadcast(framehdr.str()); std::map::iterator it; @@ -377,7 +378,12 @@ void GameServer::frame(float seconds) } } + if (!Cvar::sv_dedicated->value()) { + update_clientstate(0); + } + server_frametime = 0; + server_previoustime = server_time; } diff --git a/src/core/gameserver.h b/src/core/gameserver.h index 4fb9c47..bcd9cc3 100644 --- a/src/core/gameserver.h +++ b/src/core/gameserver.h @@ -76,6 +76,7 @@ private: unsigned int server_maxplayerid; float server_frametime; float server_time; + float server_previoustime; }; inline GameServer *server() { return GameServer::instance(); } diff --git a/src/core/netconnection.cc b/src/core/netconnection.cc index 2bcd6dc..22614d2 100644 --- a/src/core/netconnection.cc +++ b/src/core/netconnection.cc @@ -307,9 +307,9 @@ void NetConnection::parse_incoming_message(const std::string & message) } else if (command == "ping") { } else if (command == "frame") { - float timestamp; - if (msgstream >> timestamp) { - game()->reset_clientstate(timestamp); + float timestamp, prevtimestamp; + if ((msgstream >> timestamp) && (msgstream >> prevtimestamp)) { + game()->reset_clientstate(timestamp, prevtimestamp); } } else if (command == "die") { @@ -329,16 +329,16 @@ void NetConnection::parse_incoming_message(const std::string & message) switch (type) { case Entity::Default: - new Entity(msgstream); + game()->update_entity_clientstate(new Entity(msgstream)); break; case Entity::Dynamic: - new EntityDynamic(msgstream); + game()->update_entity_clientstate(new EntityDynamic(msgstream)); break; case Entity::Controlable: - new EntityControlable(msgstream); + game()->update_entity_clientstate(new EntityControlable(msgstream)); break; case Entity::Globe: - new EntityGlobe(msgstream); + game()->update_entity_clientstate(new EntityGlobe(msgstream)); break; default: con_warn << "Create for unknown entity type " << type << std::endl; diff --git a/src/game/game.cc b/src/game/game.cc index d2e5242..aa78e41 100644 --- a/src/game/game.cc +++ b/src/game/game.cc @@ -96,7 +96,7 @@ void func_buy(core::Player *player, std::string const &args) player->player_control = new Ship(player, shipmodel); player->control()->entity_color = player->color(); - core::server()->broadcast("^N" + player->name() + " ^Bpurchased " + aux::article(shipmodel->name())); + core::server()->broadcast("^B" + player->name() + " ^Bpurchased " + aux::article(shipmodel->name())); player->player_dirty = true; } else { core::server()->send(player, "Usage: buy <" + helpstr + "^N>"); diff --git a/src/math/functions.cc b/src/math/functions.cc index e048659..40f0f4e 100644 --- a/src/math/functions.cc +++ b/src/math/functions.cc @@ -9,6 +9,8 @@ namespace math { +const float DELTA = 10e-10; + float min(float a, float b) { return (a < b ? a : b); @@ -42,9 +44,9 @@ unsigned randomi(const unsigned int max) float degrees180f(float angle) { float r = angle; - while (r < -180.0f) + while (r - DELTA < -180.0f) r += 360.0f; - while (r > 180.0f) + while (r + DELTA > 180.0f) r -= 360.0f; return r; } @@ -52,9 +54,9 @@ float degrees180f(float angle) float degrees360f(float angle) { float r = angle; - while (r < 0.0f) + while (r - DELTA < 0) r += 360.0f; - while (r > 360.0f) + while (r + DELTA > 360.0f) r -= 360.0f; return r; } diff --git a/src/render/draw.cc b/src/render/draw.cc index 7c35bf3..9292460 100644 --- a/src/render/draw.cc +++ b/src/render/draw.cc @@ -431,7 +431,7 @@ void draw_pass_model_fx() t = (core::application()->time() + entity->state()->fuzz() - (*lit)->offset()) * (*lit)->frequency(); if (!(*lit)->strobe() || (( t - floorf(t)) <= (*lit)->time())) { - math::Vector3f location = entity->state()->location() + (entity->axis() * (*lit)->location()); + math::Vector3f location = entity->state()->location() + (entity->state()->axis() * (*lit)->location()); float light_size = 0.0625 * (*lit)->radius(); if ((*lit)->render_texture != flare_texture) { @@ -482,7 +482,7 @@ void draw_pass_model_fx() t = 0.75f + t/2; for(std::list::iterator eit = entity->model()->model_engine.begin(); eit != entity->model()->model_engine.end(); eit++) { - math::Vector3f location = entity->state()->location() + (entity->axis() * (*eit)->location()); + math::Vector3f location = entity->state()->location() + (entity->state()->axis() * (*eit)->location()); float engine_size = 0.0625 * (*eit)->radius() * t; math::Color color(1.0f, 0.0f, 0.0f, 0.9f * u); diff --git a/src/server/console.cc b/src/server/console.cc index b5d0aaf..4b7992e 100644 --- a/src/server/console.cc +++ b/src/server/console.cc @@ -11,86 +11,21 @@ namespace server { -namespace console { +Console server_console; -//--- private definition ------------------------------------------ - -/// server console implementation -class Console : public sys::ConsoleInterface { -public: - /// stream to send normal messages too - virtual std::ostream & messagestream(); - - /// stream to send warning messages too - virtual std::ostream & warningstream(); - - /// stream to send warning messages too - virtual std::ostream & errorstream(); - - /// stream to send debug messages too - virtual std::ostream & debugstream(); - - /// flush does nothing in this implementation - virtual void flush(); - - unsigned long ping; - -}; - -// private console object -Console console; - -//--- engine functions -------------------------------------------- - -extern "C" void func_con_ping(std::stringstream &args) +Console *console() { - con_print << "Ping!" << std::endl; - console.ping++; + return (&server_console); } - -//--- public ------------------------------------------------------ - -void init() +void Console::init() { con_print << "Initializing console..." << std::endl; - - // register our engine functions - core::Func::add("con_ping", (core::FuncPtr) func_con_ping); } -void shutdown() +void Console::shutdown() { con_print << "Shutting down console..." << std::endl; - - // unregister our engine functions - core::Func::remove("con_ping"); -} - -//--- private ----------------------------------------------------- - -void Console::flush() -{ } -std::ostream & Console::messagestream() -{ - return std::cout; -} - -std::ostream & Console::warningstream() -{ - return std::cerr; } -std::ostream & Console::errorstream() -{ - return std::cerr; -} - -std::ostream & Console::debugstream() -{ - return std::cout; -} - -} // namespace console -} // namespace server diff --git a/src/server/console.h b/src/server/console.h index 1d94ba6..d894bf1 100644 --- a/src/server/console.h +++ b/src/server/console.h @@ -11,15 +11,16 @@ namespace server { -namespace console { +class Console : public sys::ConsoleInterface { +public: + static void init(); -void init(); + static void shutdown(); +}; -void shutdown(); +Console *console(); -} // namespace console - -} // namespace server +} #endif // __INCLUDED_SERVER_CONSOLE_H__ diff --git a/src/server/server.cc b/src/server/server.cc index 1c95ee8..ee54352 100644 --- a/src/server/server.cc +++ b/src/server/server.cc @@ -33,6 +33,7 @@ public: virtual void quit(int status); }; + Server app; //--- public ------------------------------------------------------ @@ -60,7 +61,7 @@ void Server::init(int count, char **arguments) core::Cvar::sv_private = core::Cvar::set("sv_dedicated", "1", core::Cvar::ReadOnly); core::Application::init(count, arguments); - console::init(); + Console::init(); // the command line is in the buffer, execute it core::CommandBuffer::exec(); @@ -103,7 +104,7 @@ void Server::shutdown() con_debug << " bytes sent " << std::setw(6) << core::Stats::network_bytes_sent / 1024 << " Kb" << std::endl; con_debug << " bytes received " << std::setw(6) << core::Stats::network_bytes_received / 1024 << " Kb" << std::endl; - console::shutdown(); + Console::shutdown(); core::Application::shutdown(); diff --git a/src/sys/consoleinterface.cc b/src/sys/consoleinterface.cc index f80939d..a300ea1 100644 --- a/src/sys/consoleinterface.cc +++ b/src/sys/consoleinterface.cc @@ -17,11 +17,15 @@ ConsoleInterface *ConsoleInterface::consoleinterface_instance = 0; ConsoleInterface::ConsoleInterface() { + consoleinterface_ansi = true; if (consoleinterface_instance) { std::cerr << "multiple sys::ConsoleInterface instances!" << std::endl; sys::quit(2); } + consoleinterface_instance = this; + consoleinterface_text.clear(); + consoleinterface_buffer.clear(); } ConsoleInterface::~ConsoleInterface() @@ -34,4 +38,129 @@ ConsoleInterface *ConsoleInterface::instance() return consoleinterface_instance; } +std::ostream & ConsoleInterface::messagestream() +{ + flush(); + return (consoleinterface_buffer << "^N"); +} + +std::ostream & ConsoleInterface::warningstream() +{ + flush(); + return (consoleinterface_buffer << "^W"); +} + +std::ostream & ConsoleInterface::errorstream() +{ + flush(); + return (consoleinterface_buffer << "^R"); +} + +std::ostream & ConsoleInterface::debugstream() +{ + flush(); + return (consoleinterface_buffer << "^D"); +} + +void ConsoleInterface::flush() +{ + char line[MAXCMDSIZE]; + + while(consoleinterface_buffer.getline(line, MAXCMDSIZE-1)) { + + while (consoleinterface_text.size() >= MAXCONLINES) { + consoleinterface_text.pop_front(); + } + consoleinterface_text.push_back(std::string(line)); + + // print to stdout + print_ansi(line); + std::cout << std::endl; + } + + consoleinterface_buffer.clear(); +} + +void ConsoleInterface::print_ansi(const char *line) +{ + if (consoleinterface_ansi) + std::cout << "\033[0;39m"; + + const char *c = line; + while (*c) { + + if ((*c == '^')) { + bool is_code = true; + int bold = 0; + int color = 39; + + switch (*(c+1)) { + case '0': // black + color = 0; + bold = 1; + break; + case '1': // red + color = 31; + break; + case '2': // green + color = 32; + break; + case '3': // yellow + bold = 1; + color = 33; + break; + case '4': // blue + color = 34; + break; + case '5': // cyan + color = 36; + break; + case '6': // magenta + color = 35; + break; + case '7': // white is mapped to foreground color + bold = 1; + color = 39; + break; + + case 'N': // normal + bold = 0; + color = 39; + break; + case 'B': // bold + bold = 1; + color = 39; + break; + case 'D': // debug + bold = 0; + color = 39; + break; + case 'R': // error + bold = 0; + color = 31; + break; + case 'W': // warning + bold = 1; + color = 33; + break; + case 'F': // fancy + bold = 0; + color = 32; + break; + default: + is_code = false; + } + if (is_code) { + c++; + if (consoleinterface_ansi) + std::cout << "\033[" << bold << ";" << color << "m"; + } else + std::cout << *c; + } else { + std::cout << *c; + } + c++; + } +} + } // namespace sys diff --git a/src/sys/consoleinterface.h b/src/sys/consoleinterface.h index 33dc5b5..f874182 100644 --- a/src/sys/consoleinterface.h +++ b/src/sys/consoleinterface.h @@ -7,11 +7,11 @@ #ifndef __INCLUDED_SYS_CONSOLEINTERFACE_H__ #define __INCLUDED_SYS_CONSOLEINTERFACE_H__ -// project headers -#include "sys/sys.h" - -// C++ headers #include +#include +#include + +#include "sys/sys.h" /// global define to send a message to the system console #define con_print sys::ConsoleInterface::instance()->messagestream() @@ -30,6 +30,8 @@ namespace sys { +const size_t MAXCONLINES = 2048; + /// interface for the client and server Console classes class ConsoleInterface { @@ -40,27 +42,38 @@ public: /// default destructor virtual ~ConsoleInterface(); - /// stream to send normal messages too - virtual std::ostream & messagestream() = 0; + /// stream to send normal messages to + std::ostream & messagestream(); - /// stream to send warning messages too - virtual std::ostream & warningstream() = 0; + /// stream to send warning messages to + std::ostream & warningstream(); - /// stream to send error messages too - virtual std::ostream & errorstream() = 0; + /// stream to send error messages to + std::ostream & errorstream(); - /// stream to send debug messages too - virtual std::ostream & debugstream() = 0; + /// stream to send debug messages to + std::ostream & debugstream(); /// flush buffered messages - virtual void flush() = 0; + virtual void flush(); + + /// turn ANSI color codes on or off + inline void set_ansi(bool ansi) { consoleinterface_ansi = ansi; } /// a pointer to the current console instance static ConsoleInterface *instance(); +protected: + std::deque consoleinterface_text; + std::stringstream consoleinterface_buffer; + + /// print a string to stdout with ansi color codes + void print_ansi(const char *line); + private: /// console singleton static ConsoleInterface *consoleinterface_instance; + bool consoleinterface_ansi; }; } // namespace sys diff --git a/src/sys/sys.cc b/src/sys/sys.cc index 4c3f38f..4cb820d 100644 --- a/src/sys/sys.cc +++ b/src/sys/sys.cc @@ -20,25 +20,25 @@ #endif #include +#include #include "sys/sys.h" namespace sys { -void mkdir(const char *path) +void mkdir(std::string const &path) { #ifdef _WIN32 - mkdir(path); + string p(path); + for (size_t i = 0; i < p.lenght(); i++) + if (p[i] == '/') p[i] = '\\'; + ::mkdir(p.cstr()); #else - ::mkdir(path, 0777); + + ::mkdir(path.c_str(), 0777); #endif } -void mkdir(const std::string &path) -{ - mkdir(path.c_str()); -} - void signal(int signum, signalfunc handler) { #ifndef _WIN32 diff --git a/src/sys/sys.h b/src/sys/sys.h index 178fe60..e455b82 100644 --- a/src/sys/sys.h +++ b/src/sys/sys.h @@ -22,9 +22,7 @@ namespace sys typedef void (* signalfunc)(int signum); /// create a directory -void mkdir(const char *path); - -void mkdir(const std::string &path); +void mkdir(std::string const &path); /// intercept OS signals void signal(int signum, signalfunc handler); -- cgit v1.2.3