Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStijn Buys <ingar@osirion.org>2011-07-11 19:33:27 +0000
committerStijn Buys <ingar@osirion.org>2011-07-11 19:33:27 +0000
commit83c9d657773fa4f829b533791697ed07e0d9d962 (patch)
tree0c53d6a6d71c14894ac51124933ae31b66164217
parent99bd770a6030805ecd2cb22671e8f29d32fd59db (diff)
Initial support for saving player data in multiplayer games,
have ships remember their docks and spawns.
-rw-r--r--src/core/gameconnection.cc3
-rw-r--r--src/core/gameserver.cc23
-rw-r--r--src/core/gameserver.h10
-rw-r--r--src/core/module.cc8
-rw-r--r--src/core/module.h6
-rw-r--r--src/game/base/game.cc195
-rw-r--r--src/game/base/game.h11
-rw-r--r--src/game/base/ship.cc51
-rw-r--r--src/game/base/ship.h29
9 files changed, 288 insertions, 48 deletions
diff --git a/src/core/gameconnection.cc b/src/core/gameconnection.cc
index ddf4610..70d19ef 100644
--- a/src/core/gameconnection.cc
+++ b/src/core/gameconnection.cc
@@ -64,7 +64,8 @@ GameConnection::GameConnection(std::string const &connectionstr)
if (!ofs.is_open()) {
con_warn << "Could not write " << filename << std::endl;
} else {
- ofs << "; keys.ini - osirion client identification" << std::endl;
+ ofs << "; keys.ini" << std::endl;
+ ofs << "; Project::OSiRiON client identification" << std::endl;
ofs << "; DO NOT EDIT OR DELETE THIS FILE" << std::endl;
ofs << "; If you do, you will not be able to use existing characters in multiplayer games" << std::endl;
ofs << std::endl;
diff --git a/src/core/gameserver.cc b/src/core/gameserver.cc
index a1102bd..96dd51e 100644
--- a/src/core/gameserver.cc
+++ b/src/core/gameserver.cc
@@ -152,11 +152,17 @@ GameServer::GameServer() : GameInterface()
server_previoustime = 0;
server_maxplayerid = 1;
+ if (Cvar::sv_dedicated->value() || Cvar::sv_private->value()) {
+ server_mode = MultiPlayer;
+ } else {
+ server_mode = SinglePlayer;
+ }
+
// create the default infotype for entities
Entity::set_infotype(new InfoType("entity"));
Physics::init();
-
+
server_module = Loader::init();
if (!server_module) {
@@ -173,9 +179,12 @@ GameServer::GameServer() : GameInterface()
set_interactive(server_module->interactive());
+
if (interactive()) {
//FIXME interferes with command line because of cmd.exec
load_config();
+ } else {
+ server_mode = SinglePlayer;
}
// set the name of the game
@@ -184,7 +193,7 @@ GameServer::GameServer() : GameInterface()
con_print << " module '^B" << server_module->name() << "^N'\n";
- if (interactive() && (Cvar::sv_dedicated->value() || Cvar::sv_private->value())) {
+ if (mode() == MultiPlayer) {
server_network = new NetServer(Cvar::net_host->str(), (unsigned int) Cvar::net_port->value());
if (!server_network->valid()) {
delete server_network;
@@ -194,13 +203,14 @@ GameServer::GameServer() : GameInterface()
return;
}
} else {
- con_print << " network server disabled.\n";
server_network = 0;
}
Func *func = 0;
/* -- admin functions -- */
+ // FIXME these have to become shared functions and check the player's admin level
+
func = Func::add("mute", func_mute);
func->set_info("[player] mute a player");
@@ -527,6 +537,10 @@ void GameServer::player_connect(Player *player)
void GameServer::player_disconnect(Player *player)
{
+ // notify the game module
+ server_module->player_disconnect(player);
+
+ // print a message
std::string message("^B");
message.append(player->name());
message.append("^B disconnects.");
@@ -535,9 +549,6 @@ void GameServer::player_disconnect(Player *player)
// clear all player assets
player->clear_assets();
- // notify the game module
- server_module->player_disconnect(player);
-
// manage player list
std::list<Player *>:: iterator it = game_players.begin();
while ((it != game_players.end()) && ((*it)->id() != player->id())) {
diff --git a/src/core/gameserver.h b/src/core/gameserver.h
index 56d0361..4f25a9b 100644
--- a/src/core/gameserver.h
+++ b/src/core/gameserver.h
@@ -23,13 +23,15 @@ namespace core
class GameServer : public GameInterface
{
public:
+ enum Mode {SinglePlayer = 1, MultiPlayer = 2};
+
GameServer();
virtual ~GameServer();
/*----- inspectors ------------------------------------------------ */
/// current module
- inline const Module *module() const {
+ inline Module *module() {
return server_module;
}
@@ -88,6 +90,10 @@ public:
/// request inventory for entity with id
virtual Inventory *request_inventory(Entity *entity);
+
+ inline Mode mode() const {
+ return server_mode;
+ }
/*----- static ---------------------------------------------------- */
@@ -108,6 +114,8 @@ private:
unsigned long server_previoustime;
sys::Timer server_timer;
+
+ Mode server_mode;
};
inline GameServer *server()
diff --git a/src/core/module.cc b/src/core/module.cc
index 6271331..18c318e 100644
--- a/src/core/module.cc
+++ b/src/core/module.cc
@@ -44,4 +44,12 @@ void Module::abort()
module_running = false;
}
+void Module::player_load(Player *player)
+{
+}
+
+void Module::player_save(Player *player)
+{
+}
+
}
diff --git a/src/core/module.h b/src/core/module.h
index ac6b380..51b1824 100644
--- a/src/core/module.h
+++ b/src/core/module.h
@@ -56,6 +56,12 @@ public:
/// is called when a player disconnects
virtual void player_disconnect(Player *player) = 0;
+
+ /// is called when player data needs to be saved
+ virtual void player_save(Player *player);
+
+ /// is called when player data needs to be loaded
+ virtual void player_load(Player *player);
/// set the module label
void set_label(const std::string &label);
diff --git a/src/game/base/game.cc b/src/game/base/game.cc
index 4bc94f0..f954c53 100644
--- a/src/game/base/game.cc
+++ b/src/game/base/game.cc
@@ -6,6 +6,7 @@
#include <vector>
#include <string>
+#include <iomanip>
#include <assert.h>
#include "auxiliary/functions.h"
@@ -68,28 +69,30 @@ void Game::func_join(core::Player *player, std::string const &args)
if (player->control())
return;
- player->set_credits(Default::credits);
- Ship *ship = new Ship(player, Default::shipmodel);
- ship->set_zone(player->zone());
- player->set_control(ship);
-
- core::Entity *dock = ship->zone()->default_view();
- if (dock) {
- ship->get_location().assign(dock->location() + (dock->axis().forward() *((ship->radius() + dock->radius())*2.0f)));
- ship->get_axis().assign(dock->axis());
- ship->set_state(core::Entity::Docked);
- ship->reset();
- player->set_view(dock);
- }
-
std::string message("^B");
message.append(player->name());
message.append("^B joins the game.");
core::server()->broadcast(message);
- player->send("^BYou received " + aux::article(Default::shipmodel->name()));
- player->sound("game/buy-ship");
+ // load existing player data
+ core::server()->module()->player_load(player);
+
+ if (!player->control()) {
+ player->set_credits(Default::credits);
+ Ship *ship = new Ship(player, Default::shipmodel);
+ ship->set_zone(player->zone());
+ player->set_control(ship);
+ core::Entity *dock = ship->zone()->default_view();
+ if (dock) {
+ ship->set_dock(dock);
+ player->set_view(dock);
+ }
+
+ player->send("^BYou received " + aux::article(Default::shipmodel->name()));
+ player->sound("game/buy-ship");
+ }
+
player->set_dirty();
}
@@ -98,6 +101,8 @@ void Game::func_spectate(core::Player *player, std::string const &args)
{
if (!player->control())
return;
+
+ core::server()->module()->player_save(player);
std::string message("^B");
message.append(player->name());
@@ -194,10 +199,8 @@ void Game::func_target_dock(core::Player *player, core::Entity *entity)
RaceTrack *race = static_cast<RaceTrack *>(entity);
race->func_dock(ship);
} else {
- ship->get_location().assign(entity->location());
- ship->set_state(core::Entity::Docked);
- ship->reset();
-
+ ship->set_dock(entity);
+
if (player->control() == ship) {
player->set_view(entity);
if (owner) {
@@ -205,7 +208,7 @@ void Game::func_target_dock(core::Player *player, core::Entity *entity)
} else {
player->send("^BDocking at " + entity->name());
}
- }
+ }
}
}
@@ -760,12 +763,13 @@ void Game::func_launch(core::Player *player, std::string const &args)
return;
assert(player->view()->zone() == player->control()->zone());
+ assert(player->control()->moduletype() == ship_enttype);
+
+ Ship *ship = static_cast<Ship *>(player->control());
- core::Entity *dock = player->view();
-
- if (dock->moduletype() == ship_enttype) {
+ if (ship->dock()->moduletype() == ship_enttype) {
- switch(static_cast<Ship *>(dock)->state()) {
+ switch(static_cast<Ship *>(ship->dock())->state()) {
case core::Entity::Normal:
case core::Entity::Docked:
@@ -795,21 +799,13 @@ void Game::func_launch(core::Player *player, std::string const &args)
}
}
- assert(player->control()->moduletype() == ship_enttype);
-
- Ship *ship = static_cast<Ship *>(player->control());
+ player->send("^BLaunching from " + ship->dock()->name());
+
+ ship->launch();
- if (dock->type() == core::Entity::Globe)
- ship->get_location().assign(dock->location() + (dock->axis().forward() * (planet_safe_distance + ship->radius() + dock->radius())));
- else
- ship->get_location().assign(dock->location() + (dock->axis().forward() * (ship->radius() + dock->radius())));
-
- ship->get_axis().assign(dock->axis());
- ship->set_state(core::Entity::Normal);
- ship->reset();
player->set_view(0);
- player->send("^BLaunching from " + dock->name());
+
}
// respawn
@@ -1695,12 +1691,135 @@ void Game::player_connect(core::Player *player)
player->set_zone(Default::zone);
player->set_view(0); // not docked
+ // FIXME load player
func_spectate(player, args);
}
void Game::player_disconnect(core::Player *player)
{
- player->remove_asset(player->control());
+ if (player->control()) {
+ core::server()->module()->player_save(player);
+ }
}
+void Game::player_load(core::Player *player)
+{
+ if (!player->guid().is_valid()) {
+ return;
+ }
+
+ if (player->control())
+ return;
+
+ if (core::server()->mode() == core::GameServer::MultiPlayer) {
+ std::string guid(player->guid().str());
+ std::string directory(guid.substr(0,4));
+
+ std::string filename(filesystem::writedir());
+ // create players/ directory
+ filename.append("players");
+ filename += '/';
+ // second level directory
+ filename.append(directory);
+ filename += '/';
+ // guid.ini
+ filename.append(guid);
+ filename.append(".ini");
+ }
+
+}
+
+void Game::player_save(core::Player *player)
+{
+ if (!player->guid().is_valid()) {
+ return;}
+
+ if (core::server()->mode() == core::GameServer::MultiPlayer) {
+ std::string guid(player->guid().str());
+ std::string directory(guid.substr(0,4));
+
+ std::string filename(filesystem::writedir());
+ // create players/ directory
+ filename.append("players");
+ if (!sys::directory_exists(filename)) {
+ sys::mkdir(filename);
+ }
+ filename += '/';
+ // second level directory
+ filename.append(directory);
+ if (!sys::directory_exists(filename)) {
+ sys::mkdir(filename);
+ }
+ filename += '/';
+ // guid.ini
+ filename.append(guid);
+ filename.append(".ini");
+
+ std::ofstream ofs(filename.c_str());
+ if (ofs.is_open()) {
+ // *--- HEADER
+ ofs << "; " << guid << ".ini" << std::endl;
+ ofs << "; Project::OSiRiON player data" << std::endl;
+ ofs << std::endl;
+
+ // *--- PLAYER
+ ofs << "[player]" << std::endl;
+
+ // player name
+ ofs << "name=" << player->name() << std::endl;
+
+ // credit
+ ofs << "credits=" << player->credits() << std::endl;
+
+ // current zone
+ ofs << "zone=";
+ if (player->zone()) {
+ ofs << player->zone()->label();
+ }
+ ofs << std::endl;
+
+ // *--- SHIP
+ // FIXME special case: docked at another player's vessel
+ ofs << std::endl;
+ if ((player->control()) && (player->control()->moduletype() == ship_enttype)) {
+ Ship * ship = static_cast<Ship *>(player->control());
+ ofs << "[ship]" << std::endl;
+ ofs << "model=" << ship->shipmodel()->label() << std::endl;
+ // ship zone
+ ofs << "zone=" << ship->zone()->label()<< std::endl;
+ // ship location
+ ofs << "location=" << ship->location() << std::endl;
+ // ship orientation
+ ofs << "foward=" << std::setprecision(8) << ship->axis().forward() << std::endl;
+ ofs << "left=" << std::setprecision(8) << ship->axis().left() << std::endl;
+ // ship dock
+ ofs << "dock=";
+ if (ship->dock() && (ship->dock() == ship->spawn())) {
+ ofs << ship->dock()->zone()->label() << ":" << ship->dock()->label();
+
+ } else if (ship->state() == core::Entity::Destroyed) {
+ if (ship->spawn()) {
+ ofs << ship->spawn()->zone()->label() << ":" << ship->spawn()->label();
+ }
+ }
+ ofs << std::endl;
+ // ship spawn
+ ofs << "spawn=";
+ if (ship->spawn()) {
+ ofs << ship->spawn()->zone()->label() << ":" << ship->spawn()->label();
+ }
+ ofs << std::endl;
+
+ // TODO inventory
+ }
+
+ ofs.close();
+
+ con_debug << "Saving data for player id " << player->id() << std::endl;
+ } else {
+ con_warn << "Could not write " << filename << std::endl;
+ }
+ }
+}
+
} // namespace game
diff --git a/src/game/base/game.h b/src/game/base/game.h
index 27ba31b..945671c 100644
--- a/src/game/base/game.h
+++ b/src/game/base/game.h
@@ -68,10 +68,17 @@ public:
void frame(float seconds);
/// is called when a player connects
- void player_connect(core::Player *player);
+ virtual void player_connect(core::Player *player);
/// is called when a player disconnects
- void player_disconnect(core::Player *player);
+ virtual void player_disconnect(core::Player *player);
+
+ /// load a player data
+ virtual void player_load(core::Player *player);
+
+ /// save player data
+ virtual void player_save(core::Player *player);
+
/* --- game variables -------------------------------------- */
diff --git a/src/game/base/ship.cc b/src/game/base/ship.cc
index a18616e..0bc1b7c 100644
--- a/src/game/base/ship.cc
+++ b/src/game/base/ship.cc
@@ -38,6 +38,9 @@ Ship::Ship(core::Player *owner, const ShipModel *shipmodel) : core::EntityContro
ship_jumpdrive_timer = 0;
ship_jumpdepart = 0;
+ ship_dock = 0;
+ ship_spawn = 0;
+
current_impulse = false;
// apply ship type settings
@@ -289,6 +292,54 @@ void Ship::set_zone(core::Zone *zone)
owner()->set_zone(zone);
}
+void Ship::set_state(int state)
+{
+ EntityControlable::set_state(state);
+
+ if (state != core::Entity::Docked)
+ ship_dock = 0;
+}
+void Ship::set_dock(core::Entity *dock)
+{
+ if (!dock)
+ return;
+
+ ship_dock = dock;
+ get_location().assign(dock->location());
+ get_axis().assign(dock->axis());
+ set_state(core::Entity::Docked);
+
+ // if the dock is not owned by a player. set it as spawn
+ const core::Player *owner = (dock->type() == core::Entity::Controlable ? static_cast<core::EntityControlable *>(dock)->owner() : 0 );
+ if (!owner)
+ set_spawn(dock);
+ reset();
+}
+
+void Ship::launch()
+{
+ if (!ship_dock)
+ return;
+
+ get_axis().assign(ship_dock->axis());
+
+ if (ship_dock->type() == core::Entity::Globe)
+ get_location().assign(ship_dock->location() + (ship_dock->axis().forward() * (planet_safe_distance + this->radius() + ship_dock->radius())));
+ else
+ get_location().assign(ship_dock->location() + (ship_dock->axis().forward() * (this->radius() + ship_dock->radius())));
+
+ set_state(core::Entity::Normal);
+
+ ship_dock = 0;
+
+ reset();
+}
+
+void Ship::set_spawn(core::Entity *spawn)
+{
+ ship_spawn = spawn;
+}
+
void Ship::action (btScalar seconds)
{
//float maxspeed = 0;
diff --git a/src/game/base/ship.h b/src/game/base/ship.h
index 37dae0d..f705231 100644
--- a/src/game/base/ship.h
+++ b/src/game/base/ship.h
@@ -23,6 +23,8 @@ public:
Ship(core::Player *owner, const ShipModel *shipmodel);
~Ship();
+ /* -- inspectors ------------------------------------------- */
+
/// shipmodel
inline const ShipModel *shipmodel() const {
return ship_shipmodel;
@@ -52,7 +54,19 @@ public:
inline const float roll_force() const {
return ship_roll_force;
}
+
+ /// entity the ship is currently docked at
+ inline core::Entity *dock() {
+ return ship_dock;
+ }
+
+ /// (dockable) entity where the ship will respawn if destroyed
+ core::Entity *spawn() {
+ return ship_spawn;
+ }
+ /* -- mutators --------------------------------------------- */
+
/// physics frame
virtual void action (btScalar seconds);
@@ -112,6 +126,17 @@ public:
/// toggle jump drive activation
void func_jump(std::string const & args);
+
+ virtual void set_state(int state);
+ /**
+ * @brief dock the ship at a station, planet or another player's ship_dock
+ * This will set the ship's state to Entity::Docked and reset spawn if required
+ */
+ void set_dock(core::Entity *dock);
+
+ void launch();
+
+ void set_spawn(core::Entity *spawn);
private:
JumpPoint *find_closest_jumppoint();
@@ -138,6 +163,10 @@ private:
float ship_strafe_force;
float ship_turn_force;
float ship_roll_force;
+
+ core::Entity *ship_dock;
+
+ core::Entity *ship_spawn;
};
}