Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2014-12-07 23:27:31 +0000
committerStijn Buys <ingar@osirion.org>2014-12-07 23:27:31 +0000
commit493e4317e19725e2de2d51753e5c1906bf9c64ba (patch)
treec46831d6d661a79b5da6580d4472d39a615fedea /src
parent941c64546ca22b87a9153d36e9e3fe59c18abafe (diff)
Implemented messageboxes and the ability for the game module to send them to remote clients,
send a messagebox if the player's ship is destroyed, this fixes having to press the respawn button twice. added messageboxes on network connection failures.
Diffstat (limited to 'src')
-rw-r--r--src/client/Makefile.am2
-rw-r--r--src/client/client.cc13
-rw-r--r--src/client/client.h5
-rw-r--r--src/client/mainwindow.cc2
-rw-r--r--src/client/messagebox.cc150
-rw-r--r--src/client/messagebox.h50
-rw-r--r--src/core/application.cc22
-rw-r--r--src/core/application.h6
-rw-r--r--src/core/gameserver.cc19
-rw-r--r--src/core/gameserver.h3
-rw-r--r--src/core/netconnection.cc54
-rw-r--r--src/core/netserver.cc42
-rw-r--r--src/core/netserver.h7
-rw-r--r--src/core/player.cc13
-rw-r--r--src/core/player.h5
-rw-r--r--src/game/base/ship.cc1
16 files changed, 380 insertions, 14 deletions
diff --git a/src/client/Makefile.am b/src/client/Makefile.am
index f6d447d..5577879 100644
--- a/src/client/Makefile.am
+++ b/src/client/Makefile.am
@@ -34,6 +34,7 @@ noinst_HEADERS = \
mainwindow.h \
mapwidget.h \
mapwindow.h \
+ messagebox.h \
notifications.h \
reputationwindow.h \
savegamemenu.h \
@@ -70,6 +71,7 @@ libclient_la_SOURCES = \
mainwindow.cc \
mapwidget.cc \
mapwindow.cc \
+ messagebox.cc \
notifications.cc \
reputationwindow.cc \
savegamemenu.cc \
diff --git a/src/client/client.cc b/src/client/client.cc
index 128ac7f..336baee 100644
--- a/src/client/client.cc
+++ b/src/client/client.cc
@@ -105,12 +105,18 @@ void Client::init(int count, char **arguments)
// initialize user interface
ui::init();
+ // main application window
client_mainwindow = new MainWindow(ui::root());
+ // messagebox window
+ client_messagebox = new Messagebox(ui::root());
+ client_messagebox->hide();
+
// FIXME needs to be a mainwindow child
client_testmodelwindow = new TestModelWindow(ui::root());
client_testmodelwindow->hide();
+
// Initialize the video subsystem
if (!video::init()) {
quit(1);
@@ -391,6 +397,13 @@ void Client::notify_message(const core::Message::Channel channel, const std::str
con_print << message << std::endl;
}
+void Client::notify_messagebox(const std::string & text, const std::string &label1, const std::string command1, const std::string &label2, const std::string command2)
+{
+ client_messagebox->set_text(text);
+ client_messagebox->set_buttons(label1, command1, label2, command2);
+ client_messagebox->show();
+}
+
void Client::notify_loader(const std::string &message)
{
video::set_loader_message(message.c_str());
diff --git a/src/client/client.h b/src/client/client.h
index f4bfcf3..2b0d187 100644
--- a/src/client/client.h
+++ b/src/client/client.h
@@ -14,6 +14,7 @@
#include "client/soundext.h"
#include "client/testmodelwindow.h"
#include "client/mainwindow.h"
+#include "client/messagebox.h"
#include "render/renderext.h"
/// client part of the engine
@@ -41,6 +42,9 @@ public:
/// text notifications from the core
virtual void notify_message(const core::Message::Channel channel, const std::string &message);
+
+ /// messagebox notifications
+ virtual void notify_messagebox(const std::string & text, const std::string &label1, const std::string command1, const std::string &label2, const std::string command2);
/// loading message notification
virtual void notify_loader(const std::string &message);
@@ -111,6 +115,7 @@ private:
MainWindow *client_mainwindow;
TestModelWindow *client_testmodelwindow;
+ Messagebox *client_messagebox;
unsigned long previous_timestamp;
};
diff --git a/src/client/mainwindow.cc b/src/client/mainwindow.cc
index 1d9f4ff..aa113a7 100644
--- a/src/client/mainwindow.cc
+++ b/src/client/mainwindow.cc
@@ -126,7 +126,7 @@ void MainWindow::draw()
} else if (core::localcontrol()->state() == core::Entity::Destroyed) {
mainwindow_gamewindow->hide();
- mainwindow_mainmenu->show_menu("respawn");
+ // game module sends a messagebox to take approriate action
} else if (mainwindow_gamewindow->hidden()) {
mainwindow_gamewindow->show();
diff --git a/src/client/messagebox.cc b/src/client/messagebox.cc
new file mode 100644
index 0000000..f0e449a
--- /dev/null
+++ b/src/client/messagebox.cc
@@ -0,0 +1,150 @@
+/*
+ client/messagebox.cc
+ This file is part of the Osirion project and is distributed under
+ the terms and conditions of the GNU General Public License version 2
+*/
+
+#include "audio/audio.h"
+#include "client/messagebox.h"
+#include "core/commandbuffer.h"
+#include "ui/ui.h"
+
+namespace client
+{
+
+Messagebox::Messagebox(ui::Widget * parent) :
+ ui::Window(parent)
+{
+ set_border(false);
+ set_background(false);
+ set_label("messagebox");
+
+ messagebox_frame = new ui::Window(this);
+ messagebox_frame->set_border(true);
+ messagebox_frame->set_background(true);
+
+ messagebox_label = new ui::Label(messagebox_frame);
+ messagebox_label->set_border(false);
+ messagebox_label->set_background(false);
+ messagebox_label->set_alignment(ui::AlignTop | ui::AlignHCenter);
+
+ messagebox_button1 = new ui::Button(messagebox_frame);
+ messagebox_button2 = new ui::Button(messagebox_frame);
+}
+
+Messagebox::~Messagebox()
+{
+}
+
+void Messagebox::set_text(const std::string &text)
+{
+ messagebox_label->set_text(text);
+}
+
+void Messagebox::set_buttons(const std::string &text1, const std::string &command1, const std::string &text2, const std::string &command2)
+{
+ if (text1.size()) {
+ messagebox_button1->set_text(text1);
+ } else {
+ messagebox_button1->set_text("Close");
+ }
+ if (command1.size()) {
+ messagebox_button1->set_command("remote " + command1);
+ } else {
+ messagebox_button1->set_command("");
+ }
+
+ messagebox_button2->set_text(text2);
+ if (command2.size()) {
+ messagebox_button2->set_command("remote " + command2);
+ } else {
+ messagebox_button2->set_command("");
+ }
+
+ if (text2.size()) {
+ messagebox_button2->show();
+ } else {
+ messagebox_button2->hide();
+ }
+}
+
+void Messagebox::resize()
+{
+ const float padding = ui::root()->font_large()->height();
+
+ set_size(parent()->size());
+
+ messagebox_frame->set_size(
+ ui::UI::elementsize.width() * 3.0f,
+ ui::UI::elementsize.width() * 1.5f
+ );
+ messagebox_frame->set_location(
+ (width() - messagebox_frame->width()) * 0.5f,
+ (height() - messagebox_frame->height()) * 0.5f
+ );
+
+ messagebox_label->set_size(messagebox_frame->width() - padding * 2.0f, messagebox_frame->height() - padding * 2.0f);
+ messagebox_label->set_location(padding, padding);
+
+ messagebox_button1->set_size(ui::UI::elementsize);
+ messagebox_button2->set_size(ui::UI::elementsize);
+
+ if (messagebox_button2->visible()) {
+ const float l = (messagebox_frame->width() - messagebox_button1->width() - messagebox_button2->width() - padding * 2.0f) * 0.5f;
+ messagebox_button1->set_location(l, messagebox_frame->height() - messagebox_button1->height() - padding);
+ messagebox_button2->set_location(messagebox_button1->right() + padding, messagebox_frame->height() - messagebox_button2->height() - padding);
+ } else {
+ messagebox_button1->set_location((messagebox_frame->width() - messagebox_button1->width()) * 0.5f, messagebox_frame->height() - messagebox_button1->height() - padding);
+ }
+}
+
+bool Messagebox::on_emit(Widget *sender, const Event event, void *data)
+{
+ if ((sender == messagebox_button1) || (sender == messagebox_button2)) {
+ if (event == Widget::EventButtonClicked) {
+ hide();
+ }
+ return true;
+ }
+
+ return false;
+}
+
+bool Messagebox::on_keypress(const int key, const unsigned int modifier)
+{
+ std::string command;
+
+ switch (key) {
+ case SDLK_RETURN:
+ case SDLK_KP_ENTER:
+ command.assign(messagebox_button1->command());
+ if (command.size()) {
+ core::cmd() << command << std::endl;
+ }
+ audio::play("ui/clicked");
+ hide();
+ return true;
+ break;
+
+ case SDLK_ESCAPE:
+ if (messagebox_button2->visible()) {
+ command.assign(messagebox_button2->command());
+ } else {
+ command.assign(messagebox_button1->command());
+ }
+ if (command.size()) {
+ core::cmd() << command << std::endl;
+ }
+ audio::play("ui/clicked");
+ hide();
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ return Window::on_keypress(key, modifier);
+}
+
+} // namespace client
diff --git a/src/client/messagebox.h b/src/client/messagebox.h
new file mode 100644
index 0000000..ac1d46b
--- /dev/null
+++ b/src/client/messagebox.h
@@ -0,0 +1,50 @@
+/*
+ client/messagebox.h
+ This file is part of the Osirion project and is distributed under
+ the terms and conditions of the GNU General Public License version 2
+*/
+
+#ifndef __INCLUDED_CLIENT_MESSAGEBOX_H__
+#define __INCLUDED_CLIENT_MESSAGEBOX_H__
+
+#include "ui/window.h"
+#include "ui/button.h"
+#include "ui/label.h"
+
+namespace client
+{
+
+/**
+ * @brief a generic messagebox window class
+ * */
+class Messagebox : public ui::Window
+{
+public:
+ Messagebox(ui::Widget *parent = 0);
+ virtual ~Messagebox();
+
+ void set_text(const std::string &text);
+
+ void set_buttons(const std::string &text1, const std::string &command1, const std::string &text2, const std::string &command2);
+
+protected:
+ virtual void resize();
+
+ virtual bool on_keypress(const int key, const unsigned int modifier);
+
+ virtual bool on_emit(Widget *sender, const Event event, void *data);
+
+private:
+ /// the actual dialog widget
+ ui::Window *messagebox_frame;
+
+ ui::Label *messagebox_label;
+ ui::Button *messagebox_button1;
+ ui::Button *messagebox_button2;
+};
+
+}
+
+#endif // __INCLUDED_CLIENT_MESSAGEBOX_H__
+
+
diff --git a/src/core/application.cc b/src/core/application.cc
index 14bb9f3..b181178 100644
--- a/src/core/application.cc
+++ b/src/core/application.cc
@@ -469,10 +469,30 @@ void Application::notify_message(const core::Message::Channel channel, const std
}
}
+void Application::messagebox(const char *text, const char *label1, const char *command1, const char *label2, const char *command2)
+{
+ std::string str_text(text ? text : "" );
+
+ std::string str_label1(label1 ? label1 : "" );
+ std::string str_command1(command1 ? command1 : "" );
+
+ std::string str_label2(label2 ? label2 : "" );
+ std::string str_command2(command2 ? command2 : "" );
+
+ notify_messagebox(str_text, str_label1, str_command1, str_label2, str_command2);
+}
+
+
+void Application::notify_messagebox(const std::string & text, const std::string &label1, const std::string command1, const std::string &label2, const std::string command2)
+{
+ // the default implementation does nothing
+ // used by the client to show messageboxes
+}
+
void Application::notify_loader(const std::string &message)
{
// the default implementation does nothing.
- // used by the client to udpate the loader screen
+ // used by the client to update the loader screen
}
void Application::notify_zonechange()
diff --git a/src/core/application.h b/src/core/application.h
index 3f99187..da722db 100644
--- a/src/core/application.h
+++ b/src/core/application.h
@@ -82,6 +82,12 @@ public:
/// loading message notification
virtual void notify_loader(const std::string &message);
+
+ /// messagebox notifications
+ virtual void notify_messagebox(const std::string & text, const std::string &label1, const std::string command1, const std::string &label2, const std::string command2);
+
+ /// messagebox notifications
+ void messagebox(const char *text, const char *label1 = 0, const char *command1 = 0, const char *label2 = 0, const char *command2 = 0);
/// connect notification
virtual void notify_connect();
diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc
index 544f660..37c486c 100644
--- a/src/core/gameserver.cc
+++ b/src/core/gameserver.cc
@@ -472,6 +472,25 @@ void GameServer::broadcast_sound(const std::string name, Player *ignore_player)
}
}
+// server sends a messagebox to a single player
+void GameServer::messagebox(Player *player, const std::string & text, const std::string &label1, const std::string command1, const std::string &label2, const std::string command2)
+{
+ if (!text.size()) {
+ return;
+ }
+
+ NetClient *client = player->client();
+
+ if (client) {
+ // this player is a network client, send message over network
+ server_network->send_messagebox(client, text, label1, command1, label2, command2);
+
+ } else if (player == localplayer()) {
+ // local player, send message to the local application
+ application()->notify_messagebox(text, label1, command1, label2, command2);
+ }
+}
+
// execute a command for a remote player
void GameServer::exec(Player *player, std::string const & cmdline)
{
diff --git a/src/core/gameserver.h b/src/core/gameserver.h
index 4f25a9b..3e9c50a 100644
--- a/src/core/gameserver.h
+++ b/src/core/gameserver.h
@@ -80,7 +80,8 @@ public:
/// broadcast a sound to all players
void broadcast_sound(std::string const sound, Player *ignore_player = 0);
-
+ /// send a messagebox to a single player
+ void messagebox(Player *player, const std::string & text, const std::string &label1, const std::string command1, const std::string &label2, const std::string command2);
/// a player sends a command to the game server
void exec(Player *player, std::string const &cmdline);
diff --git a/src/core/netconnection.cc b/src/core/netconnection.cc
index 4892792..ee3e754 100644
--- a/src/core/netconnection.cc
+++ b/src/core/netconnection.cc
@@ -56,8 +56,13 @@ void NetConnection::connect(std::string const &to_host, int to_port)
struct hostent *serverhostent;
serverhostent = gethostbyname(to_host.c_str());
if (!serverhostent) {
- con_warn << "Could not resolve '" << to_host.c_str() << "'" << std::endl;
+ std::ostringstream str;
+ str << "Could not resolve hostname'" << to_host.c_str() << "'";
+ con_error << str.str() << std::endl;
+
abort();
+
+ application()->messagebox(str.str().c_str());
return;
}
@@ -76,8 +81,13 @@ void NetConnection::connect(std::string const &to_host, int to_port)
server_addr.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)serverhostent->h_addr)));
memset(server_addr.sin_zero, '\0', sizeof server_addr.sin_zero);
if (server_addr.sin_addr.s_addr == INADDR_NONE) {
- con_error << "Network invalid address " << to_host << "!" << std::endl;
+ std::ostringstream str;
+ str << "Invalid address for '" << to_host << "'";
+ con_error << str.str() << std::endl;
+
abort();
+
+ application()->messagebox(str.str().c_str());
return;
}
@@ -156,12 +166,14 @@ void NetConnection::receive()
if (bytes_received == 0) {
con_print << "^BDisconnected." << std::endl;
- abort();
+ abort();
+ application()->messagebox("Disconnected from server.");
return;
} else if (bytes_received < 0) {
con_error << "Network receive() error!" << std::endl;
//perror("recv");
abort();
+ application()->messagebox("Disconnected from server.");
return;
}
@@ -249,8 +261,9 @@ void NetConnection::frame()
int nb = select(fd() + 1, &readset, NULL, NULL, &timeout);
if (nb == 0) {
if (connection_timeout + NETTIMEOUT < core::application()->time()) {
- con_error << "Connection timeout!\n";
+ con_error << "Connection timeout exceeded!\n";
abort();
+ application()->messagebox("Connection timeout exceeded!");
}
return;
}
@@ -649,6 +662,39 @@ void NetConnection::parse_incoming_message(const std::string & message)
}
}
+ } else if (command.compare("box") == 0) {
+
+ // box "text" "label1" "cmd1" "label2" "cmd2"
+ char c;
+
+ // read text
+ std::string text;
+ while ((msgstream.get(c)) && (c != '"'));
+ while ((msgstream.get(c)) && (c != '"'))
+ text += c;
+
+ std::string label1;
+ while ((msgstream.get(c)) && (c != '"'));
+ while ((msgstream.get(c)) && (c != '"'))
+ label1 += c;
+
+ std::string command1;
+ while ((msgstream.get(c)) && (c != '"'));
+ while ((msgstream.get(c)) && (c != '"'))
+ command1 += c;
+
+ std::string label2;
+ while ((msgstream.get(c)) && (c != '"'));
+ while ((msgstream.get(c)) && (c != '"'))
+ label2 += c;
+
+ std::string command2;
+ while ((msgstream.get(c)) && (c != '"'));
+ while ((msgstream.get(c)) && (c != '"'))
+ command2 += c;
+
+ application()->notify_messagebox(text, label1, command1, label2, command2);
+
} else if (command.compare("connect") == 0) {
if (connection_state == Pending) {
diff --git a/src/core/netserver.cc b/src/core/netserver.cc
index cbb2dc7..1b49aee 100644
--- a/src/core/netserver.cc
+++ b/src/core/netserver.cc
@@ -487,20 +487,23 @@ void NetServer::frame(unsigned long timestamp)
* The following messages can be send to a client
*
* frame <timestamp> <previous timestamp>
- * ent <id> <entity create data>
+ * ent <id> <entity data>
* die <id> <entity data>
* inf <id>
* inv <id>
* ping <timestamp>
- * sup <entity update data>
+ * rep <reputation data>
+ * sup <entity data>
*
* msg <channel> <text>
* supported message channels are "info" "public" "rcon" and "snd"
* "snd" is a special channel to transmit sound events
+ * box <text> <label1> <command1> <label2> <command2>
+ * send a messagebox
* zone <id> <zone create/update data>
*/
-// send a message on a specified channel to a single client
+// send a text message on a specified channel to a single client
void NetServer::send_message(NetClient *client, const Message::Channel channel, const std::string & message)
{
if (!message.size())
@@ -538,15 +541,44 @@ void NetServer::send_message(NetClient *client, const Message::Channel channel,
break;
}
+ std::string str_message(message);
+ aux::strip_quotes(str_message);
+
std::string msg("msg ");
msg.append(msg_channel);
msg += ' ';
- msg.append(message);
+ msg.append(str_message);
msg += '\n';
client->send_raw(msg);
}
+// send a messagebox to a single client
+void NetServer::send_messagebox(NetClient *client, const std::string & text, const std::string &label1, const std::string command1, const std::string &label2, const std::string command2)
+{
+ std::string str_text(text);
+ aux::strip_quotes(str_text);
+
+ std::string str_label1(label1);
+ aux::strip_quotes(str_label1);
+ std::string str_command1(command1);
+ aux::strip_quotes(str_command1);
+
+ std::string str_label2(label2);
+ aux::strip_quotes(str_label2);
+ std::string str_command2(command2);
+ aux::strip_quotes(str_command2);
+
+ std::ostringstream msg("");
+ msg << "box ";
+ msg << "\"" << str_text << '\"' << ' ';
+ msg << "\"" << str_label1 << '\"' << ' ';
+ msg << "\"" << str_command1 << '\"' << ' ';
+ msg << "\"" << str_label2 << '\"' << ' ';
+ msg << "\"" << str_command2 << '\"' << '\n';
+
+ client->send_raw(msg.str());
+}
// disconnect a client
void NetServer::send_disconnect(NetClient *client)
@@ -745,7 +777,6 @@ void NetServer::send_inventory_update(NetClient *client, Entity *entity, const u
* info <id>
* req <id>
* inv <id>
- *
*/
void NetServer::parse_incoming_message(NetClient *client, const std::string & message)
{
@@ -779,6 +810,7 @@ void NetServer::parse_incoming_message(NetClient *client, const std::string & me
con_print << client->host() << ":" << client->port() << " " << netmsgstream.str() << std::endl;
send_message(client, Message::Info, netmsgstream.str());
+ send_messagebox(client, netmsgstream.str(), "", "", "", "");
send_disconnect(client);
} else {
diff --git a/src/core/netserver.h b/src/core/netserver.h
index 7277866..95ada0d 100644
--- a/src/core/netserver.h
+++ b/src/core/netserver.h
@@ -18,7 +18,9 @@
namespace core
{
-/// network server
+/**
+ * Handles server-side network messages
+ * */
class NetServer
{
public:
@@ -72,6 +74,9 @@ public:
/// send a message on a specified channel
void send_message(NetClient *client, const Message::Channel channel, const std::string & message);
+
+ /// send a messagebox to a single client
+ void send_messagebox(NetClient *client, const std::string & text, const std::string &label1, const std::string command1, const std::string &label2, const std::string command2);
protected:
diff --git a/src/core/player.cc b/src/core/player.cc
index 14767bd..7511e06 100644
--- a/src/core/player.cc
+++ b/src/core/player.cc
@@ -95,6 +95,19 @@ void Player::print() const
<< std::setfill('0') << std::setw(2) << time_wasted_seconds << std::endl;
}
+void Player::messagebox(const char *text, const char *label1, const char *command1, const char *label2, const char *command2)
+{
+ std::string str_text(text ? text : "" );
+
+ std::string str_label1(label1 ? label1 : "" );
+ std::string str_command1(command1 ? command1 : "" );
+
+ std::string str_label2(label2 ? label2 : "" );
+ std::string str_command2(command2 ? command2 : "" );
+
+ server()->messagebox(this, str_text, str_label1, str_command1, str_label2, str_command2);
+}
+
void Player::message(Message::Channel channel, const std::string text)
{
server()->message(this, channel, text);
diff --git a/src/core/player.h b/src/core/player.h
index a9eb4b0..e68a219 100644
--- a/src/core/player.h
+++ b/src/core/player.h
@@ -200,7 +200,10 @@ public:
}
- /*----- server-side mesage functions ------------------------------ */
+ /*----- server-side message functions ----------------------------- */
+
+ /// send a messagebox to the player
+ void messagebox(const char *text, const char *label1 = 0, const char *command1 = 0, const char *label2 = 0, const char *command2 = 0);
/// send a message to the player on one of the message channels
void message(core::Message::Channel channel, const std::string text);
diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc
index 9a4218f..0dd5415 100644
--- a/src/game/base/ship.cc
+++ b/src/game/base/ship.cc
@@ -434,6 +434,7 @@ void Ship::explode()
// make the player watch his death
if (owner()->control() == this) {
owner()->set_view(this);
+ owner()->messagebox("Your ship has been destroyed.", "Respawn", "respawn");
}
// cargo loss % is set by the g_cargoloss CVar