Now we can reconnect to a JSVM\!

This commit is contained in:
Jonatan Pålsson 2011-02-14 19:47:28 +01:00
commit 56c70c38b7
27 changed files with 381 additions and 40 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
*.swp *.swp
*.dump *.dump
*.beam *.beam
Mnesia.*

2
HOWTO
View file

@ -3,7 +3,7 @@ python version 2.x set to default.
INSTALL INSTALL
1. Cd into directory where you to have the project 1. Cd into directory where you to have the project
2. git-clone git@github.com:jeena/GGS.git (remember to have a local key) 2. git clone git@github.com:jeena/GGS.git (remember to have a local key)
3. cd GGS/ 3. cd GGS/
4. git submodule init 4. git submodule init
5. git submodule update 5. git submodule update

2
build
View file

@ -3,4 +3,4 @@
for i in `find src -name "*.erl"` for i in `find src -name "*.erl"`
do do
erlc -o ebin $i erlc -o ebin $i
done done

17
client Normal file
View file

@ -0,0 +1,17 @@
#!/usr/bin/env ruby -wKU
require 'socket' # Sockets are in standard library
hostname = 'localhost'
port = 7000
s = TCPSocket.open(hostname, port)
s.print(q.chop)
while line = s.gets # Read lines from the socket
puts "Got Echo: " + line.chop # And print with platform line terminator
end
s.close # Close the socket when done

View file

@ -12,8 +12,16 @@
function init() { function init() {
GameServer.addGame(game_name, main()); GameServer.addGame(game_name, main());
GameServer.addClient(game_name, new TicTacToeClient(frames.player1.document.getElementById("p1"), GameServer)); GameServer.addClient(
GameServer.addClient(game_name, new TicTacToeClient(frames.player2.document.getElementById("p2"), GameServer)); game_name,
new TicTacToeClient(frames.player1.document.getElementById("p1"),
GameServer
));
GameServer.addClient(
game_name,
new TicTacToeClient(frames.player2.document.getElementById("p2"),
GameServer
));
} }
</script> </script>
<link rel="stylesheet" href="css/screen.css" type="text/css" media="screen"> <link rel="stylesheet" href="css/screen.css" type="text/css" media="screen">

View file

@ -90,4 +90,4 @@ TicTacToeClient.prototype.updateBoard = function(gameBoardData) {
this.spots[k++].innerHTML = t; this.spots[k++].innerHTML = t;
} }
} }
} }

View file

View file

@ -1,12 +1,6 @@
- background image - background
- subimages for game_area:s
- subimages for game markers (X or 0)
- rectangle collision on game_area:s
- redraw background then all game_area:s - redraw background then all game_area:s
- board_state: a hashtable where key is game_area_index
and value is either'x' 'o' or ' '
board contains nr_of_squares = 9
board contains array of squares with nr_of_squares elements board contains array of squares with nr_of_squares elements
board contains x, y, width and height board contains x, y, width and height
board contains a frame board contains a frame

15
games/tic-tac-toe/data.py Normal file
View file

@ -0,0 +1,15 @@
def greatest_sequence(match, pattern):
m = match
p = pattern
size = 0
max_size = 0
for p in pattern:
if m == p:
size += 1
else:
if size > max_size:
max_size = size
size = 0
return max_size

BIN
games/tic-tac-toe/data.pyc Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 187 B

Before After
Before After

View file

@ -0,0 +1,15 @@
from pygame.mouse import get_pos
from point import Point
class Player(object):
def __init__(self, id, shape, board):
self.shape = shape
self.board = board
self.id = id
def turn(self):
#Ask mouse for position
board.make_turn(Point(get_pos()[0],get_pos()[1]))

View file

@ -0,0 +1,23 @@
#server.py
import json
from socket import socket, AF_INET, SOCK_STREAM
class server(object):
def __init__(self, port=None):
self.port = port
self.world = GGS.init()
self.socket = socket(AF_INET, SOCK_STREAM)
self.socket.connect(("www.???.com", 80))
def turn(self, id, index):
rows = sqrt(board.nr_of_rectangles)
x = int(index / rows)
y = int(index % rows)
json.dumps({"x": x, "y": y}
world.callCommand("tictactoe", "set", json.dumps({"x": x, "y": y}))
sent = 0
length = len(
while sent

View file

@ -0,0 +1,14 @@
import unittest
import data
class TestData(unittest.TestCase):
def setUp(self):
array = [0,1,1,1,3,4,5,2,2,3,3,3,3,3,33,4,2,2]
self.assertTrue(data.greatest_sequence(array, 3) == 5)
if __name__ == '__main__':
unittest.main()

View file

@ -4,6 +4,7 @@ from point import Point
from pygame.image import load from pygame.image import load
from pygame.rect import Rect from pygame.rect import Rect
from pygame import Surface from pygame import Surface
from data import greatest_sequence
#inherits Board. #inherits Board.
#Used for displaying the board on the screen and interact with it #Used for displaying the board on the screen and interact with it
@ -47,4 +48,14 @@ class TicTacToeBoard(Board):
game_rectangle.state = 'o' game_rectangle.state = 'o'
self.players_turn = (self.players_turn + 1) % 2 self.players_turn = (self.players_turn + 1) % 2
"""
def turn(self, mouse_point):
if player.id != players_turn:
print "Other players turn"
else:
for game_rectangle in self.game_rectangles:
if (mouse_point.inside(game_rectangle) and
game_rectangle.state == ' '):
server.turn(player.id, game_rectangle.index)
"""

Binary file not shown.

BIN
mnesia/.gamedb.erl.swp Normal file

Binary file not shown.

View file

@ -1,26 +1,45 @@
%Test Mnesia %%%%----------------------------------------------------
%%% @author Mattias Pettersson <mattiaspgames@gmail.com>
%%% @copyright 2011 Mattias Pettersson
%%% @doc Database for runtime game variable storage.
%%% @end
Test Mnesia
-module(gamedb). -module(gamedb).
-import(mnesia). -import(mnesia).
-export([init/0,insert_player/1,example_player/0,read_player/1,test_player/0]). -export([init/0,insert_player/1,example_player/0,read_player/1,test_player/0]).
-include("gamedb.hrl"). -include("gamedb.hrl").
%%-----------------------------------------------------
%% Creation
%%-----------------------------------------------------
init() -> init() ->
mnesia:create_table(player, [{attributes, record_info(fields, player)}]). mnesia:create_table(player, [{attributes, record_info(fields, player)}]).
%%-----------------------------------------------------
%% Test
%%-----------------------------------------------------
test_player() -> test_player() ->
insert_player(example_player()), insert_player(example_player()),
read_player(0001). read_player(0001).
example_player() ->
#player{id = 0001,
name = "Tux"}.
%%-----------------------------------------------------
%% Insertions
%%-----------------------------------------------------
insert_player(Player) -> insert_player(Player) ->
Fun = fun() -> Fun = fun() ->
mnesia:write(Player) mnesia:write(Player)
end, end,
mnesia:transaction(Fun). mnesia:transaction(Fun).
example_player() ->
#player{id = 0001,
name = "Tux"}.
%%-----------------------------------------------------
%% Querries
%%-----------------------------------------------------
read_player(Player_Key) -> read_player(Player_Key) ->
Fun = fun() -> Fun = fun() ->
[P] = mnesia:read(player, Player_Key), [P] = mnesia:read(player, Player_Key),

View file

@ -29,9 +29,9 @@ s.send(
"Token: %s\n\ "Token: %s\n\
Server-Command: define\n\ Server-Command: define\n\
Content-Type: text\n\ Content-Type: text\n\
Content-Length: 42\n\ Content-Length: 49\n\
\n\ \n\
function myFun() {return 'Hello world!' ;}" % token) function myFun() {return 'Hello World!' ;}" % token)
fs = s.makefile() fs = s.makefile()
data = fs.readline() data = fs.readline()
print "Token:", token print "Token:", token
@ -54,6 +54,8 @@ print "Data: ", ' '.join(data.split(" ")[1:])
s.close() s.close()
time.sleep(2)
HOST = 'localhost' # The remote host HOST = 'localhost' # The remote host
PORT = int(sys.argv[1]) # The same port as used by the server PORT = int(sys.argv[1]) # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

23
python_client_reconnect Executable file
View file

@ -0,0 +1,23 @@
#!/usr/bin/env python
import sys, time, socket
HOST = 'localhost' # The remote host
PORT = int(sys.argv[1]) # The same port as used by the server
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
# Call that function!
print "Calling myFun"
s.send(
"Token: %s\n\
Server-Command: call\n\
Content-Type: text\n\
Content-Length: 6\n\
\n\
myFun" % raw_input("Token >> "))
fs = s.makefile()
data = fs.readline()
print "Data: ", ' '.join(data.split(" ")[1:])
s.close()

BIN
src/.ggs_connection.erl.swp Normal file

Binary file not shown.

170
src/ggs_network.erl Normal file
View file

@ -0,0 +1,170 @@
%%%----------------------------------------------------
%%% @author Jonatan Pålsson <Jonatan.p@gmail.com>
%%% @copyright 2010 Jonatan Pålsson
%%% @doc RPC over TCP server
%%% @end
%%%----------------------------------------------------
%%% @author Mattias Pettersson <mattiaspgames@gmail.com>
%%% @doc Socket module for GGS
%%% @end
%%%----------------------------------------------------
-module(ggs_network).
-behaviour(gen_server).
%define
-define(SERVER, ?MODULE).
-define(DEFAULT_PORT, 1055).
% export
-export([start_link/0,start_link/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2]).
%-export([get_count/1,crash/0,vms/0,hello/0,echo/0]).
-export([get_count/1]).
-export([send/3, send/4]).
-export([stop/0]).
%% gen_server callbacks
-export([terminate/2, code_change/3]).
%state
-record(state, {port, lsock, client_vm_map = []}).
%%-----------------------------------------------------
%% @doc Starts gen_server
%% @end
%%-----------------------------------------------------
start_link() ->
start_link(?DEFAULT_PORT).
start_link(Port) ->
process_flag(trap_exit, true),
gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []).
%%-----------------------------------------------------
%% Creation
%%-----------------------------------------------------
init([Port]) ->
{ok, LSock} = gen_tcp:listen(Port, [{active, true},
{reuseaddr, true}]),
{ok, #state{port = Port, lsock = LSock}, 0}.
%%-----------------------------------------------------
%% @doc Fetches the number of requests made to this server
%% @spec get_count() -> {ok, Count}
%% where
%% Count = integer()
%% @end
%%-----------------------------------------------------
get_count(get_count) ->
gen_server:call(?SERVER, get_count).
%crash() -> gen_server:call(?SERVER, crash).
%vms() -> gen_server:call(?SERVER, vms).
%hello() -> gen_server:call(?SERVER, hello).
%echo() -> gen_server:call(?SERVER, {echo, RefID, _, MSG}).
%%-----------------------------------------------------
%% @doc Stops the server.
%% @spec stop() -> ok
%% @end
%%-----------------------------------------------------
stop() ->
gen_server:cast(?SERVER, stop).
%%-----------------------------------------------------
%% Handlers
%%-----------------------------------------------------
handle_call(get_count, _From, State) ->
{reply, {ok, State#state.client_vm_map}, State}.
handle_cast(stop, State) ->
{stop, normal, State}.
handle_info({tcp, Socket, RawData}, State) -> %parameters coming from gen_server
NewState = do_JSCall(Socket, RawData, State), %TODO
OldMap = State#state.client_vm_map,
io:format("Old map: ~p NewState: ~p~n", [OldMap, NewState]),
{noreply, State#state{client_vm_map = OldMap ++ [NewState]}};
handle_info(timeout, #state{lsock = LSock} = State) ->
{ok, _Sock} = gen_tcp:accept(LSock),
{noreply, State}.
%%-----------------------------------------------------
%% TCP Calls
%%-----------------------------------------------------
send(Socket, RefID, String) ->
gen_tcp:send(Socket, io_lib:fwrite("~p ~p~n", [RefID,String])).
send(Socket, RefID, String1, String2) ->
gen_tcp:send(Socket, io_lib:fwrite("~p ~p ~p~n", [RefID, String1, String2])).
%%-----------------------------------------------------
%% gen_server callbacks
%%-----------------------------------------------------
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%-----------------------------------------------------
%% Internal functions
%%-----------------------------------------------------
do_JSCall(Socket, Data, State) ->
JSVM = js_runner:boot(),
js_runner:define(JSVM, "function userCommand(cmd, par) {return cmd+' '+ par}"),
Parsed = ggs_protocol:parse(Data),
NewState = case Parsed of
{cmd, Command, Parameter} ->
% Set the new state to []
Ret = js_runner:call(JSVM, "userCommand",
[list_to_binary(Command),
list_to_binary(Parameter)]),
send(Socket, "RefID", "JS says: ", Ret),
[];
% Set the new state to the reference generated, and JSVM associated
{hello} ->
Client = getRef(),
send(Socket, Client, "__ok_hello"),
{Client, JSVM};
{echo, RefID, _, MSG} ->
send(Socket, RefID, "Your VM is ", getJSVM(RefID, State)),
[];
{crash, Zero} ->
10/Zero;
{vms} ->
send(Socket, "RefID", State);
% Set the new state to []
Other ->
send(Socket, "RefID", "__error"),
[]
end,
% Return the new state
NewState.
%%-----------------------------------------------------
%% Helpers
%%-----------------------------------------------------
getRef() ->
{A1,A2,A3} = now(),
random:seed(A1, A2, A3),
random:uniform(1000).
%%-----------------------------------------------------
%% Helpers
%%-----------------------------------------------------
getJSVM(RefID, State) ->
VMs = State#state.client_vm_map,
{value, {_,VM}} = lists:keysearch(RefID, 1, VMs),
VM.

View file

@ -90,8 +90,8 @@ handle_cast(stop, State) ->
% Handle javascript defines % Handle javascript defines
handle_cast({srv_cmd, "define", Headers, Data}, State) -> handle_cast({srv_cmd, "define", Headers, Data}, State) ->
Token = ggs_protocol:getToken(Headers), Token = ggs_protocol:getToken(Headers),
JSVM = getJSVM(Token, State), GameVM = getJSVM(Token, State),
js_runner:define(JSVM, Data), ggs_vm_runner:define(GameVM, Data),
send(State#state.lsock, "Token", "Okay, defined that for you!"), send(State#state.lsock, "Token", "Okay, defined that for you!"),
{noreply, State}; {noreply, State};
@ -99,21 +99,21 @@ handle_cast({srv_cmd, "define", Headers, Data}, State) ->
handle_cast({srv_cmd, "call", Headers, Data}, State) -> handle_cast({srv_cmd, "call", Headers, Data}, State) ->
Token = ggs_protocol:getToken(Headers), Token = ggs_protocol:getToken(Headers),
io:format("Got call request: ~p~n", [Data]), io:format("Got call request: ~p~n", [Data]),
JSVM = getJSVM(Token, State), GameVM = getJSVM(Token, State),
erlang:display(erlang:port_info(JSVM)), Ret = ggs_vm_runner:user_command(GameVM, "User", Data, []),
{ok, Ret} = js_runner:call(JSVM, Data, []),%Payload, []),
send(State#state.lsock, Token, "JS says:", binary_to_list(Ret)), send(State#state.lsock, Token, "JS says:", binary_to_list(Ret)),
{noreply, State}; {noreply, State};
% Set the new state to the reference generated, and JSVM associated % Set the new state to the reference generated, and JSVM associated
handle_cast({srv_cmd, "hello", Headers, Data}, State) -> handle_cast({srv_cmd, "hello", Headers, Data}, State) ->
JSVM = js_runner:boot(), GameVM = ggs_vm_runner:start_link(),
Client = getRef(), Client = getRef(),
send(State#state.lsock, Client, "This is your refID"), send(State#state.lsock, Client, "This is your refID"),
OldMap = State#state.client_vm_map, OldMap = State#state.client_vm_map,
NewState = State#state{client_vm_map = OldMap ++ [{Client, JSVM}]}, NewState = State#state{client_vm_map = OldMap ++ [{Client, GameVM}]},
gen_server:cast(ggs_backup, {set_backup, NewState}), gen_server:cast(ggs_backup, {set_backup, NewState}),
{noreply, NewState}. {noreply, NewState}.
%%----------------------------------------------------- %%-----------------------------------------------------
%% Helpers %% Helpers
%%----------------------------------------------------- %%-----------------------------------------------------

42
src/ggs_vm_runner.erl Normal file
View file

@ -0,0 +1,42 @@
-module(ggs_vm_runner).
-export([start_link/0, define/2, user_command/4]).
%Mattias
start_link() ->
erlang_js:start(),
PortPid = spawn_link( fun() ->
process_flag(trap_exit, true),
{ok, Port} = js_driver:new(),
js:define(Port, <<"function userCommand(user, command, args){return 'Hello world';}">>),
loop(Port)
end ),
PortPid.
loop(Port) ->
receive
{define, SourceCode} ->
ok = js:define(Port, list_to_binary(SourceCode)),
loop(Port);
{user_command, User, Command, Args, From, Ref} ->
{ok, Ret} = js:call(Port, <<"userCommand">>,
[ list_to_binary(User),
list_to_binary(Command),
list_to_binary(Args)
]),
From ! {Ref, Ret},
loop(Port)
end.
define(GameVM, SourceCode) ->
GameVM ! {define,SourceCode}.
user_command(GameVM, User, Command, Args) ->
Ref = make_ref(),
GameVM ! {user_command, User, Command, Args, self(), Ref},
receive
{Ref, RetVal} ->
RetVal;
Other -> Other
end.

View file

@ -1,13 +0,0 @@
-module(js_runner).
-export([define/2,call/3, boot/0]).
boot() ->
erlang_js:start(),
{ok, Port} = js_driver:new(),
Port.
define(Port, Data) ->
ok = js:define(Port, list_to_binary(Data)).
call(Port, Func, Params) ->
js:call(Port, list_to_binary(Func), Params).