Commit 6de3bb48 authored by Jonathan Michalon's avatar Jonathan Michalon
Browse files

Synchronize others' game at client connection

parent 2deafecc
......@@ -37,7 +37,7 @@ public class Bot : OVCCClient.Client
/* join any open table */
debug ("Trying to join a table...");
try {
join_table (-1);
yield join_table (-1);
} catch (Error e4) {
leave ();
throw e4;
......
......@@ -26,6 +26,8 @@ libovcc_la_SOURCES = ovcc-board.vala \
network/ovcc-network-string-message.vala \
network/ovcc-network-variant-message.vala \
network/ovcc-network-login-message.vala \
network/ovcc-network-join-message.vala \
network/ovcc-network-gamedata-message.vala \
network/ovcc-network-signals.vala \
network/ovcc-network-disconnect-message.vala \
network/ovcc-network-welcome-message.vala \
......
/*
*
* Copyright (C) 2011 Colomban Wendling <ban@herbesfolles.org>
* Jonathan Michalon <studios.chalmion@no-log.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* Login message with login, password and current status
*/
public class OVCC.Network.GamedataMessage : VariantMessage
{
public override MessageType message_type { get { return MessageType.GAMEDATA; } }
public uint[] stack_ids = null;
public string[] player_nicks = null;
public string tiles_filename { get; set; default = null; }
public string tileset_filename { get; set; default = null; }
public State status { get; set; default = State.OK; }
public enum State
{
OK,
FAILED
}
public GamedataMessage (uint[] ids, string[] nicks, string tiles, string tileset)
{
Object (tiles_filename: tiles, tileset_filename: tileset);
stack_ids = ids;
player_nicks = nicks;
}
protected override Variant build_variant ()
{
Variant ids = stack_ids;
Variant nicks = player_nicks;
return new Variant ("(ivvss)", status, ids, nicks, tiles_filename, tileset_filename);
}
protected override void parse_variant (uint8[] data)
{
State s;
Variant ids;
Variant nicks;
string t;
string ts;
parse_data (data, "(ivvss)", out s, out ids, out nicks, out t, out ts);
status = s;
stack_ids = (uint[]) ids;
player_nicks = (string[]) nicks;
tiles_filename = t;
tileset_filename = ts;
}
}
/*
*
* Copyright (C) 2011 Colomban Wendling <ban@herbesfolles.org>
* Jonathan Michalon <studios.chalmion@no-log.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* Login message with login, password and current status
*/
public class OVCC.Network.JoinMessage : VariantMessage
{
public override MessageType message_type { get { return MessageType.JOIN; } }
public int table_index { get; set; default = -1; }
public State status { get; set; default = State.QUERY; }
public enum State
{
QUERY,
OK,
FAILED
}
public JoinMessage (int idx)
{
Object (table_index: idx);
}
protected override Variant build_variant ()
{
return new Variant ("(ii)", status, table_index);
}
protected override void parse_variant (uint8[] data)
{
State s;
int idx;
parse_data (data, "(ii)", out s, out idx);
status = s;
table_index = idx;
}
}
......@@ -42,6 +42,8 @@ namespace OVCC.Network
ERROR,
WELCOME,
LOGIN,
JOIN,
GAMEDATA,
SIGNAL,
DISCONNECT,
INVALID
......@@ -54,6 +56,8 @@ namespace OVCC.Network
typeof (ErrorMessage),
typeof (WelcomeMessage),
typeof (LoginMessage),
typeof (JoinMessage),
typeof (GamedataMessage),
typeof (SignalMessage),
typeof (DisconnectMessage)
};
......
......@@ -106,7 +106,11 @@ namespace OVCC.Network
msg.parse ("s", out nick);
debug ("Adding new player %s", nick);
stop_forward (game_object, SignalType.PLAYER_ADDED);
game_object.add_player (new Player(nick));
if (nick != player_object.nick) {
game_object.add_player (new Player(nick));
} else {
game_object.add_player (player_object);
}
resume_forward (game_object, SignalType.PLAYER_ADDED);
});
signal_received[SignalType.PLAYER_REMOVED.to_string ()].connect ((msg) => {
......
......@@ -91,10 +91,13 @@ namespace OVCC
public Game (TileSet ts, Stack? s = null)
{
var our_stack = s;
if (ts.first == null) {
critical ("Given tileset has no first tile");
}
if (s == null) {
our_stack = new Stack.from_tileset (ts);
}
Object (tileset: ts, stack: our_stack, board: new Board (our_stack.pop ()));
Object (tileset: ts, stack: our_stack, board: new Board (ts.first.dup ()));
stack.item_removed.connect (t => {
this.notify_property ("current-tile");
......@@ -266,5 +269,19 @@ namespace OVCC
return success;
}
public uint[] get_stack_ids ()
{
return stack.get_ids();
}
public string[] get_player_nicks ()
{
string[] nicks = new string[players.length()];
int i = 0;
foreach (Player p in players) {
nicks[i] = p.nick;
}
return nicks;
}
}
}
......@@ -43,21 +43,25 @@ namespace OVCC
this.fill (ts);
}
public Stack.from_tile_ids (SList<uint> ids, TilesDef tiles)
public Stack.from_tile_ids (uint[] ids, TilesDef tiles)
{
if (ids == null) {
warning ("Creating empty stack");
}
foreach (var id in ids) {
add_nth (tiles.get_tile (id), -1);
}
}
public SList<uint> get_id_list ()
public uint[] get_ids ()
{
SList<uint> list = new SList<uint>();
uint[] ids = new uint[this.size];
int i = 0;
foreach (var e in this._stack.head) {
list.prepend (e.id);
ids[i] = e.id;
i++;
}
list.reverse();
return list;
return ids;
}
public void dump ()
......@@ -128,11 +132,6 @@ namespace OVCC
}
return true;
});
if (ts.first == null) {
critical ("Given set has no first tile");
} else {
this.add_nth (ts.first, 0);
}
this.thaw_notify ();
}
}
......
......@@ -84,10 +84,10 @@ namespace OVCCClient
return true;
}
public Game join_table (int index)
public async Game join_table (int index)
throws ServerError
{
game = server.join_table (index, player);
game = yield server.join_table (index, player);
player.joined (game);
......
......@@ -206,17 +206,35 @@ namespace OVCCClient
/* join a table, index -1 means any open table
* The index is typically within the list returned by enumerate_tables() */
public Game join_table (int index, Player player)
public async Game join_table (int index, Player player)
throws ServerError
requires (connection != null)
{
/* FIXME load right tileset and do something with stack... */
TilesDef tiles = new TilesDef ();
TileSet tileset = new TileSet ();
tiles.load (File.new_for_path (TILES_FILE));
tileset.load (tiles, File.new_for_path (TILESET_FILE));
/* call the server */
send_message (new JoinMessage (index));
/* wait for data */
Message msg2 = yield receive_type (MessageType.GAMEDATA);
GamedataMessage data = msg2 as GamedataMessage;
if (data.status != GamedataMessage.State.OK) {
throw new ServerError.COMMUNICATION_FAILED ("Failed to get game data");
}
/* create our game */
tiles.load (File.new_for_path (data.tiles_filename));
tileset.load (tiles, File.new_for_path (data.tileset_filename));
var stack = new Stack.from_tile_ids (data.stack_ids, tiles);
Game game = new Game (tileset, null);
Game game = new Game (tileset, stack);
foreach (var nick in data.player_nicks) {
game.add_player (new Player (nick));
}
/* start listening to game signals */
var signal_handle = new SignalHandle (game, player, input, output);
......
......@@ -55,8 +55,8 @@ public class Client: Object
throws Error
requires (connection != null)
{
game.remove_player (player);
signal_handle = null; /* to break circular reference */
game.remove_player (player);
return connection.socket.close ();
}
......@@ -82,8 +82,6 @@ public class Client: Object
game = game_p;
signal_handle = new SignalHandle (game, player, input, output);
/* the client adds itselves */
// game.add_player (player);
return true;
}
......
......@@ -89,6 +89,17 @@ public class Server: ThreadedSocketService
return ok;
}
private bool handle_join (JoinMessage msg, Client client)
{
client.join(tables.first().data);
debug ("Sending game data");
var data = new GamedataMessage (client.game.get_stack_ids(),
client.game.get_player_nicks(),
TILES_FILE, TILESET_FILE);
client.send (data);
return true;
}
private bool handle_connection (ThreadedSocketService service,
SocketConnection connection,
......@@ -135,10 +146,10 @@ public class Server: ThreadedSocketService
bool logged;
debug ("Login for '%s' with '%s'", (msg as LoginMessage).login,
(msg as LoginMessage).password);
logged = handle_login ((msg as LoginMessage), client);
if (logged) {
client.join(tables.first().data);
}
handle_login ((msg as LoginMessage), client);
break;
case MessageType.JOIN:
handle_join (msg as JoinMessage, client);
break;
case MessageType.SIGNAL:
client.signal_handle.emit_received (msg as SignalMessage);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment