Skip to content

Commit

Permalink
Sending and receiving partial orders.
Browse files Browse the repository at this point in the history
  • Loading branch information
o01eg committed Jan 31, 2019
1 parent d07ef90 commit 31eb793
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 7 deletions.
4 changes: 4 additions & 0 deletions client/ClientApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ void ClientApp::StartTurn(const SaveGameUIData& ui_data)
void ClientApp::StartTurn(const std::string& save_state_string)
{ m_networking->SendMessage(TurnOrdersMessage(m_orders, save_state_string)); }

void ClientApp::SendPartialOrders() {
m_networking->SendMessage(TurnPartialOrdersMessage(m_orders.ExtractChanges()));
}

void ClientApp::HandleTurnPhaseUpdate(Message::TurnProgressPhase phase_id) {
switch (phase_id) {
case Message::WAITING_FOR_PLAYERS:
Expand Down
3 changes: 3 additions & 0 deletions client/ClientApp.h
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ class ClientApp : public IApp {
/** @brief Send the OrderSet and AI state to the server and start a new turn */
virtual void StartTurn(const std::string& save_state_string);

/** @brief Send turn orders updates to server without starting new turn */
void SendPartialOrders();

/** \brief Handle server acknowledgement of receipt of orders and clear
the orders. */
virtual void HandleTurnPhaseUpdate(Message::TurnProgressPhase phase_id);
Expand Down
9 changes: 7 additions & 2 deletions network/Message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "../universe/Species.h"
#include "../universe/Universe.h"
#include "../util/OptionsDB.h"
#include "../util/OrderSet.h"
#include "../util/Serialize.h"
#include "../util/ScopedTimer.h"
#include "../util/i18n.h"
Expand Down Expand Up @@ -384,10 +385,12 @@ Message TurnOrdersMessage(const OrderSet& orders, const std::string& save_state_
return Message(Message::TURN_ORDERS, os.str());
}

Message TurnPartialOrdersMessage() {
Message TurnPartialOrdersMessage(const std::pair<OrderSet, std::set<int>>& orders_updates) {
std::ostringstream os;
{
freeorion_xml_oarchive oa(os);
Serialize(oa, orders_updates.first);
oa << boost::serialization::make_nvp("deleted", orders_updates.second);
}
return Message(Message::TURN_PARTIAL_ORDERS, os.str());
}
Expand Down Expand Up @@ -956,11 +959,13 @@ void ExtractTurnOrdersMessageData(const Message& msg,
}
}

void ExtractTurnPartialOrdersMessageData(const Message& msg) {
void ExtractTurnPartialOrdersMessageData(const Message& msg, OrderSet& added, std::set<int>& deleted) {
try {
std::istringstream is(msg.Text());
freeorion_xml_iarchive ia(is);
DebugLogger() << "deserializing partial orders";
Deserialize(ia, added);
ia >> BOOST_SERIALIZATION_NVP(deleted);
} catch (const std::exception& err) {
ErrorLogger() << "ExtractTurnPartialOrdersMessageData(const Message& msg) failed! Message probably long, so not outputting to log.\n"
<< "Error: " << err.what();
Expand Down
6 changes: 3 additions & 3 deletions network/Message.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ FO_COMMON_API Message TurnOrdersMessage(const OrderSet& orders, const SaveGameUI
/** creates a TURN_ORDERS message, without UI data but with a state string. */
FO_COMMON_API Message TurnOrdersMessage(const OrderSet& orders, const std::string& save_state_string);

/** creates a TURN_PARTIAL_ORDERS message. \todo give it some data */
FO_COMMON_API Message TurnPartialOrdersMessage();
/** creates a TURN_PARTIAL_ORDERS message with orders changes. */
FO_COMMON_API Message TurnPartialOrdersMessage(const std::pair<OrderSet, std::set<int>>& orders_updates);

/** creates a TURN_PROGRESS message. */
FO_COMMON_API Message TurnProgressMessage(Message::TurnProgressPhase phase_id);
Expand Down Expand Up @@ -405,7 +405,7 @@ FO_COMMON_API void ExtractTurnOrdersMessageData(const Message& msg,
bool& save_state_string_available,
std::string& save_state_string);

FO_COMMON_API void ExtractTurnPartialOrdersMessageData(const Message& msg);
FO_COMMON_API void ExtractTurnPartialOrdersMessageData(const Message& msg, OrderSet& added, std::set<int>& deleted);

FO_COMMON_API void ExtractTurnUpdateMessageData(const Message& msg, int empire_id, int& current_turn, EmpireManager& empires,
Universe& universe, SpeciesManager& species, CombatLogManager& combat_logs,
Expand Down
16 changes: 15 additions & 1 deletion server/ServerApp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,8 @@ void ServerApp::HandleMessage(const Message& msg, PlayerConnectionPtr player_con
case Message::LOBBY_UPDATE: m_fsm->process_event(LobbyUpdate(msg, player_connection)); break;
case Message::SAVE_GAME_INITIATE: m_fsm->process_event(SaveGameRequest(msg, player_connection)); break;
case Message::TURN_ORDERS: m_fsm->process_event(TurnOrders(msg, player_connection)); break;
case Message::TURN_PARTIAL_ORDERS: m_fsm->process_event(TurnPartialOrders(msg, player_connection));break;
case Message::UNREADY: m_fsm->process_event(RevokeReadiness(msg, player_connection)); break;
//case Message::CLIENT_SAVE_DATA: m_fsm->process_event(ClientSaveData(msg, player_connection)); break;
case Message::PLAYER_CHAT: m_fsm->process_event(PlayerChat(msg, player_connection)); break;
case Message::DIPLOMACY: m_fsm->process_event(Diplomacy(msg, player_connection)); break;
case Message::MODERATOR_ACTION: m_fsm->process_event(ModeratorAct(msg, player_connection)); break;
Expand Down Expand Up @@ -1861,6 +1861,20 @@ void ServerApp::ClearEmpireTurnOrders() {
void ServerApp::SetEmpireSaveGameData(int empire_id, std::unique_ptr<PlayerSaveGameData>&& save_game_data)
{ m_turn_sequence[empire_id] = std::make_pair(true, std::move(save_game_data)); }

void ServerApp::UpdatePartialOrders(int empire_id, const OrderSet& added, const std::set<int>& deleted) {
const auto& psgd = m_turn_sequence[empire_id].second;
if (psgd) {
if (psgd->m_orders) {
for (int id : deleted)
psgd->m_orders->erase(id);
for (auto it : added)
psgd->m_orders->insert(it);
} else {
psgd->m_orders = std::make_shared<OrderSet>(added);
}
}
}

void ServerApp::RevokeEmpireTurnReadyness(int empire_id)
{ m_turn_sequence[empire_id].first = false; }

Expand Down
4 changes: 4 additions & 0 deletions server/ServerApp.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ class ServerApp : public IApp {
* \a save_game_data will be freed when all processing is done for the turn */
void SetEmpireSaveGameData(int empire_id, std::unique_ptr<PlayerSaveGameData>&& save_game_data);

/** Updated empire orders without changes in readiness status. Removes all \a deleted orders
* and insert \a added orders. */
void UpdatePartialOrders(int empire_id, const OrderSet& added, const std::set<int>& deleted);

/** Revokes turn order's ready state for the given empire. */
void RevokeEmpireTurnReadyness(int empire_id);

Expand Down
74 changes: 74 additions & 0 deletions server/ServerFSM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2601,6 +2601,80 @@ sc::result WaitingForTurnEnd::react(const TurnOrders& msg) {
return discard_event();
}

sc::result WaitingForTurnEnd::react(const TurnPartialOrders& msg) {
TraceLogger(FSM) << "(ServerFSM) WaitingForTurnEnd.TurnPartialOrders";
ServerApp& server = Server();
const Message& message = msg.m_message;
const PlayerConnectionPtr& sender = msg.m_player_connection;

auto added = std::make_shared<OrderSet>();
std::set<int> deleted;
try {
ExtractTurnPartialOrdersMessageData(message, *added, deleted);
} catch (const std::exception& err) {
// incorrect turn orders. disconnect player with wrong client.
sender->SendMessage(ErrorMessage(UserStringNop("ERROR_INCOMPATIBLE_VERSION")));
server.Networking().Disconnect(sender);
return discard_event();
}

int player_id = sender->PlayerID();
Networking::ClientType client_type = sender->GetClientType();

if (client_type == Networking::CLIENT_TYPE_HUMAN_OBSERVER) {
// observers cannot submit orders. ignore.
ErrorLogger(FSM) << "WaitingForTurnEnd::react(TurnPartialOrders&) received orders from player "
<< sender->PlayerName()
<< "(player id: " << player_id << ") "
<< "who is an observer and should not be sending orders. Orders being ignored.";
sender->SendMessage(ErrorMessage(UserStringNop("ORDERS_FOR_WRONG_EMPIRE"), false));
return discard_event();

} else if (client_type == Networking::INVALID_CLIENT_TYPE) {
// ??? lingering connection? shouldn't get to here. ignore.
ErrorLogger(FSM) << "WaitingForTurnEnd::react(TurnPartialOrders&) received orders from player "
<< sender->PlayerName()
<< "(player id: " << player_id << ") "
<< "who has an invalid player type. The server is confused, and the orders being ignored.";
sender->SendMessage(ErrorMessage(UserStringNop("ORDERS_FOR_WRONG_EMPIRE"), false));
return discard_event();

} else if (client_type == Networking::CLIENT_TYPE_AI_PLAYER ||
client_type == Networking::CLIENT_TYPE_HUMAN_PLAYER)
{
// store empire orders and resume waiting for more
const Empire* empire = GetEmpire(server.PlayerEmpireID(player_id));
if (!empire) {
ErrorLogger(FSM) << "WaitingForTurnEnd::react(TurnPartialOrders&) couldn't get empire for player with id:" << player_id;
sender->SendMessage(ErrorMessage(UserStringNop("EMPIRE_NOT_FOUND_CANT_HANDLE_ORDERS"), false));
return discard_event();
}

int empire_id = empire->EmpireID();

for (const auto& id_and_order : *added) {
auto& order = id_and_order.second;
if (!order) {
ErrorLogger(FSM) << "WaitingForTurnEnd::react(TurnPartialOrders&) couldn't get order from order set!";
continue;
}
if (empire_id != order->EmpireID()) {
ErrorLogger(FSM) << "WaitingForTurnEnd::react(TurnPartialOrders&) received orders from player " << empire->PlayerName() << "(id: "
<< player_id << ") who controls empire " << empire_id
<< " but those orders were for empire " << order->EmpireID() << ". Orders being ignored.";
sender->SendMessage(ErrorMessage(UserStringNop("ORDERS_FOR_WRONG_EMPIRE"), false));
return discard_event();
}
}

TraceLogger(FSM) << "WaitingForTurnEnd.TurnPartialOrders : Received partial orders from player " << player_id;

server.UpdatePartialOrders(empire_id, *added, deleted);
}

return discard_event();
}

sc::result WaitingForTurnEnd::react(const RevokeReadiness& msg) {
TraceLogger(FSM) << "(ServerFSM) WaitingForTurnEnd.RevokeReadiness";
ServerApp& server = Server();
Expand Down
4 changes: 4 additions & 0 deletions server/ServerFSM.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ struct MessageEventBase {
(LeaveGame) \
(SaveGameRequest) \
(TurnOrders) \
(TurnPartialOrders) \
(RevokeReadiness) \
(CombatTurnOrders) \
(RequestCombatLogs) \
Expand Down Expand Up @@ -335,6 +336,7 @@ struct PlayingGame : sc::state<PlayingGame, ServerFSM, WaitingForTurnEnd> {
struct WaitingForTurnEnd : sc::state<WaitingForTurnEnd, PlayingGame, WaitingForTurnEndIdle> {
typedef boost::mpl::list<
sc::custom_reaction<TurnOrders>,
sc::custom_reaction<TurnPartialOrders>,
sc::custom_reaction<RevokeReadiness>,
sc::custom_reaction<CheckTurnEndConditions>
> reactions;
Expand All @@ -343,6 +345,7 @@ struct WaitingForTurnEnd : sc::state<WaitingForTurnEnd, PlayingGame, WaitingForT
~WaitingForTurnEnd();

sc::result react(const TurnOrders& msg);
sc::result react(const TurnPartialOrders& msg);
sc::result react(const RevokeReadiness& msg);
sc::result react(const CheckTurnEndConditions& c);

Expand Down Expand Up @@ -376,6 +379,7 @@ struct ProcessingTurn : sc::state<ProcessingTurn, PlayingGame> {
sc::custom_reaction<ProcessTurn>,
sc::deferral<SaveGameRequest>,
sc::deferral<TurnOrders>,
sc::deferral<TurnPartialOrders>,
sc::deferral<RevokeReadiness>,
sc::deferral<Diplomacy>,
sc::custom_reaction<CheckTurnEndConditions>
Expand Down
16 changes: 16 additions & 0 deletions util/OrderSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,19 @@ void OrderSet::Reset() {
m_last_added_orders.clear();
m_last_deleted_orders.clear();
}

std::pair<OrderSet, std::set<int>> OrderSet::ExtractChanges() {
OrderSet added_orders;
for(int added : m_last_added_orders) {
auto it = m_orders.find(added);
if (it != m_orders.end()) {
added_orders.m_orders.insert(*it);
} else {
m_last_deleted_orders.insert(added);
}
}
m_last_added_orders.clear();
std::set<int> deleted_orders = std::move(m_last_deleted_orders);
m_last_deleted_orders.clear();
return {added_orders, deleted_orders};
}
5 changes: 4 additions & 1 deletion util/OrderSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class FO_COMMON_API OrderSet {
std::size_t size() const { return m_orders.size(); }
bool empty() const { return m_orders.empty(); }
iterator find(const key_type& k) { return m_orders.find(k); }
void erase(const key_type& k){ RescindOrder(k); }
std::pair<iterator,bool> insert (const value_type& val) { return m_orders.insert(val); } ///< direct insert without saving changes
void erase(const key_type& k){ m_orders.erase(k); } ///< direct erase without saving changes
OrderPtr& operator[](std::size_t i);
key_compare key_comp() const { return m_orders.key_comp(); }
//@}
Expand All @@ -74,6 +75,8 @@ class FO_COMMON_API OrderSet {
set. Return true if \p order exists and was successfully removed. */
bool RescindOrder(int order);
void Reset(); ///< clears all orders; should be called at the beginning of a new turn

std::pair<OrderSet, std::set<int>> ExtractChanges(); ///< extract and clear changed orders
//@}

private:
Expand Down

0 comments on commit 31eb793

Please sign in to comment.