Merge branch 'master' into jonte_rewrite

Conflicts:
	src/ggs_coordinator.erl
	src/ggs_gamevm_e.erl
	src/ggs_table.erl
This commit is contained in:
Jonatan Pålsson 2011-02-24 11:38:36 +01:00
commit 97c7e39b4a
23 changed files with 306 additions and 272 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
*.dump
*.beam
Mnesia.*
*.swo

21
HOWTO
View file

@ -1,21 +0,0 @@
PREREQUISITES:
python version 2.x set to default.
INSTALL
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)
3. cd GGS/
4. git submodule init
5. git submodule update
6. cd erlang_js
7. make
8. make test (Optional. It has to work though.)
10. cd ../
11. ./build
12.
USAGE
1. start a second terminal
2. in new terminal do command: ./python_client 9000
3. back to first terminal
4. ./start

44
Makefile Normal file
View file

@ -0,0 +1,44 @@
ERLC=erlc
ERLCFLAGS=-o
SRCDIR=src
TESTDIR=tests
BEAMDIR=ebin
all: compile erlang_js
compile:
mkdir -p $(BEAMDIR) ;
$(ERLC) $(ERLCFLAGS) $(BEAMDIR) $(SRCDIR)/*.erl ;
erlang_js: force_look
cd erlang_js ; $(MAKE) $(MFLAGS);
test:
echo "==> test $(MOD)" ;
mkdir -p $(BEAMDIR) ;
ifeq ($(strip $(MOD)),)
$(ERLC) $(ERLCFLAGS) $(BEAMDIR) $(TESTDIR)/*.erl ;
cd $(BEAMDIR) ; erl -noinput -eval 'eunit:test({dir, "."}, [verbose]), init:stop()' ;
else
$(ERLC) $(ERLCFLAGS) $(BEAMDIR) $(TESTDIR)/$(MOD)_test.erl ;
cd $(BEAMDIR) ; erl -noinput -eval 'eunit:test($(MOD)_test, [verbose]), init:stop()' ;
endif
clean:
rm -rf $(BEAMDIR)/*.beam ;
rm -rf erl_crush.dump ;
echo "==> clean ggs" ;
$(MAKE) -C erlang_js/ clean
run:
erl \
-sname ggs \
-mnesia dir '"/tmp/ggs"' \
-boot start_sasl \
-pa erlang_js/ebin/ \
-pa ebin \
-pa src \
-s start_ggs
force_look:
true

34
README
View file

@ -1,3 +1,35 @@
GGS is a Generic Game Server
Check out http://ggs-kandidat.blogspot.com/
Check out http://ggs-kandidat.blogspot.com/
PREREQUISITES:
python version 2.x set to default.
INSTALL
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)
3. cd GGS/
4. git submodule init
5. git submodule update
USAGE
1. start a second terminal
2. in new terminal do command: ./python_client 9000
3. back to first terminal
4. make run
MAKE
To compile modules (even erlang_js):
make
To run server:
make run
To clean (even erlang_js):
make clean
To compile and run all tests:
make test
To compile and run one test:
make test MOD=ggs_modulename # (must have /tests/ggs_modulename_test.erl)

6
build
View file

@ -1,6 +0,0 @@
#!/usr/bin/env bash
for i in `find src -name "*.erl"`
do
erlc -o ebin $i
done

View file

@ -1,8 +0,0 @@
#!/usr/bin/env bash
./build
for i in `find tests -name "*.erl"`
do
erlc -o ebin_test $i
done

17
client
View file

@ -1,17 +0,0 @@
#!/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

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

View file

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

View file

@ -1,6 +0,0 @@
%% gamedb.hrl
-record(player, {id, name}).

View file

@ -1,12 +0,0 @@
1. From terminal: erl -mnesia dir '"/home/user/dir/to/GGS/GameDB.Player"'
2. mnesia:create_schema([node()]).
3. mnesia:start().
4. c(gamedb).
5. gamedb:init().
6. mnesia:info().
7. gamedb:test_player().
Last output should be:
Player name: Tux
{atomic,ok}

View file

@ -91,7 +91,6 @@ handle_cast({stop, _Reason}, State) ->
%% @TODO: Implement me
%handle_cast({remove_player, Player}) ->
% {noreply, State#co_state{
handle_cast(_Message, State) ->
{noreply, State}.

91
src/ggs_db.erl Normal file
View file

@ -0,0 +1,91 @@
%%%%----------------------------------------------------
%%% @author Mattias Pettersson <mattiaspgames@gmail.com>
%%% @copyright 2011 Mattias Pettersson
%%% @doc Database for runtime game variable storage.
%%% @end
-module(ggs_db).
-export([init/0,stop/0,setItem/4,getItem/3,removeItem/3,key/3,clear/2,clear/1,length/2]).
%-include("ggs_db.hrl").
-record(data, {key, value}).
%%-----------------------------------------------------
%% Creation
%%-----------------------------------------------------
init() ->
% mnesia:create_schema([node()]),
mnesia:start(),
mnesia:create_table(data, [{attributes, record_info(fields, data)}]).
stop() ->
mnesia:stop().
%%-----------------------------------------------------
%% Insertions
%%-----------------------------------------------------
setItem(GameToken,Ns,Key,Value) ->
Fun = fun() ->
Data = #data{key = {GameToken,Ns,Key}, value = Value},
mnesia:write(Data)
end,
mnesia:transaction(Fun).
%%-----------------------------------------------------
%% Deletions
%%-----------------------------------------------------
removeItem(GameToken,Ns,Key) ->
Fun = fun() ->
mnesia:delete({data,{GameToken,Ns,Key}})
end,
mnesia:transaction(Fun).
clear(GameToken,Ns) ->
Fun = fun() ->
Keys = mnesia:all_keys(data),
Rest = lists:filter(fun({A,B,_}) -> ((A==GameToken) and (B==Ns)) end, Keys),
lists:map(fun({A,B,C}) -> removeItem(A,B,C) end, Rest)
end,
{atomic, Ret} = mnesia:transaction(Fun),
Ret.
clear(GameToken) ->
Fun = fun() ->
Keys = mnesia:all_keys(data),
Rest = lists:filter(fun({A,_,_}) -> (A==GameToken) end, Keys),
lists:map(fun({A,B,C}) -> removeItem(A,B,C) end, Rest)
end,
{atomic, Ret} = mnesia:transaction(Fun),
Ret.
%%-----------------------------------------------------
%% Queries
%%-----------------------------------------------------
getItem(GameToken,Ns,Key) ->
Fun = fun() ->
mnesia:read(data, {GameToken,Ns,Key})
end,
case mnesia:transaction(Fun) of
{atomic, []} ->
{error};
{atomic, [Ret]} ->
Ret#data.value
end.
length(GameToken,Ns) ->
Fun = fun() ->
Keys = mnesia:all_keys(data),
length(lists:filter(fun({A,B,_}) -> ((A==GameToken) and (B==Ns)) end, Keys))
end,
{atomic, Ret} = mnesia:transaction(Fun),
Ret.
key(GameToken,Ns,Position) ->
Fun = fun() ->
Keys = mnesia:all_keys(data),
Rest = lists:filter(fun({A,B,_}) -> ((A==GameToken) and (B==Ns)) end, Keys),
lists:nth(Position, Rest)
end,
{atomic, Ret} = mnesia:transaction(Fun),
Ret.

5
src/ggs_db.hrl Normal file
View file

@ -0,0 +1,5 @@
%% gamedb.hrl
-record(data, {key, value}).

View file

@ -97,34 +97,3 @@ code_change(_OldVsn, State, _Extra) ->
js_escape(S) ->
lists:flatmap(fun($\') -> [$\\, $\']; (X) -> [X] end, S).
%% ----------------------------------------------------------------------
% Tests
start_link_test() ->
erlang_js:start(), %% @TODO: should only be done once
GameVM = start_link(test_table),
?assertNot(GameVM =:= undefined).
define_test() ->
GameVM = start_link(test_table),
define(GameVM, "function hello(test) { return test; }"),
?assertMatch(<<"jeena">>, gen_server:call(GameVM, {eval, "hello('jeena')"})).
stop_test() ->
GameVM = start_link(test_table),
ok = stop(GameVM).
user_command_test() ->
GameVM = start_link(test_table),
define(GameVM, "var t = '';\nfunction userCommand(user, command, args) { t = user + command + args; }\n"),
user_command(GameVM, "'jeena", "thecommand", "theargs'"),
?assertMatch(<<"'jeenathecommandtheargs'">>, gen_server:call(GameVM, {eval, "t;"})).
js_erlang_test() ->
GameVM = start_link(test_table),
define(GameVM, "var t = '';\nfunction userCommand(user, command, args) { t = callErlang('erlang time') + ''; }\n"),
user_command(GameVM, "", "", ""),
{A, B, C} = erlang:time(),
T = "{" ++ integer_to_list(A) ++ ", " ++ integer_to_list(B) ++ ", " ++ integer_to_list(C) ++ "}",
?assertMatch(T, binary_to_list(gen_server:call(GameVM, {eval, "t;"}))).

View file

@ -12,12 +12,13 @@
%% API
-export([start_link/0,
add_player/2,
remove_player/2,
stop/1,
notify/3]).
add_player/2,
remove_player/2,
stop/1,
notify/3,
notify_all_players/2,
notify_game/3]).
-include_lib("eunit/include/eunit.hrl").
%% ----------------------------------------------------------------------
% API implementation
@ -25,6 +26,7 @@
% @doc returns a new table
start_link() ->
{ok, Pid} = gen_server:start_link(?MODULE, [], []),
Pid.
%% @private
call(Pid, Msg) ->
@ -96,9 +98,10 @@ handle_cast({notify_game, Message, From}, #state { game_vm = GameVM } = State) -
{noreply, State};
handle_cast({notify_all_players, Message}, #state{players = Players} = State) ->
lists:foreach(fun(P) ->
ggs_player:notify(P, "Server", Message)
end, Players),
lists:foreach(
fun(P) -> ggs_player:notify(P, "Server", Message) end,
Players
),
{noreply, State};
handle_cast(stop, State) ->
@ -120,80 +123,3 @@ terminate(_Reason, _State) ->
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% @TODO: Please put these tests in a separate file. We can't compile this file if
%% they contain errors from switching vms
%% ----------------------------------------------------------------------
% Tests
%<<<<<<< HEAD
%start_link_test() ->
% Table = start_link(),
% ?assertNot(Table =:= undefined).
%add_player_test() ->
% Table = start_link(),
% Player = test_player,
% add_player(Table, Player),
% {ok, [Player]} = gen_server:call(Table, get_player_list).
%remove_player_test() ->
% Table = start_link(),
% Player = test_player,
% Player2 = test_player2,
% add_player(Table, Player),
% {ok, [Player]} = gen_server:call(Table, get_player_list),
% add_player(Table, Player2),
% {ok, [Player2, Player]} = gen_server:call(Table, get_player_list),
% remove_player(Table, Player),
% {ok, [Player2]} = gen_server:call(Table, get_player_list),
% remove_player(Table, Player2),
% {ok, []} = gen_server:call(Table, get_player_list).
%
%stop_test() ->
% Table = start_link(),
% ok = stop(Table).
% @private
%notify_test() ->
% Table = start_link(),
% Player = test_player,
% Message = {server, define, "function helloWorld(x) { }"},
% ok = notify(Table, Player, Message).
%=======
%%start_link_test() ->
% Table = start_link("123", none),
% ?assertNot(Table =:= undefined).
%
%add_player_test() ->
% Table = start_link("123", none),
% Player = test_player,
% add_player(Table, Player),
% {ok, [Player]} = gen_server:call(Table, get_player_list).
%remove_player_test() ->
% Table = start_link("123", none),
% Player = test_player,
% Player2 = test_player2,
% add_player(Table, Player),
% {ok, [Player]} = gen_server:call(Table, get_player_list),
% add_player(Table, Player2),
% {ok, [Player2, Player]} = gen_server:call(Table, get_player_list),
% remove_player(Table, Player),
% {ok, [Player2]} = gen_server:call(Table, get_player_list),
% remove_player(Table, Player2),
% {ok, []} = gen_server:call(Table, get_player_list).
%
%stop_test() ->
% Table = start_link("123", none),
% ok = stop(Table).
%
%% @private
%notify_test() ->
% Table = start_link("123", none),
% Player = test_player,
% Message = {server, define, "function helloWorld(x) { }"},
% ok = notify(Table, Player, Message).
%>>>>>>> jonte_rewrite
%Message2 = {game, "helloWorld", "test"},
%ok = notify(Table, Player, Message2).

3
start
View file

@ -1,3 +0,0 @@
#!/usr/bin/env bash
erl -sname ggs -mnesia -boot start_sasl -pa erlang_js/ebin/ -pa ebin -pa src -s start_ggs

View file

@ -1,3 +0,0 @@
#!/usr/bin/env bash
erl -boot start_sasl -pa ebin_test -pa erlang_js/ebin/ -pa ebin -pa src -eval 'ggs_coordinator_test:test().'

View file

@ -1,3 +0,0 @@
#!/usr/bin/env bash
erl -boot start_sasl -pa ebin_test -pa erlang_js/ebin/ -pa erlv8/ebin -pa ebin -pa src

47
tests/ggs_db_test.erl Normal file
View file

@ -0,0 +1,47 @@
-module(ggs_db_test).
%-compile({no_auto_import,[get/1,set/2]}).
-include_lib("eunit/include/eunit.hrl").
%ggs_db_test_() ->
% {spawn,
% {setup, fun setup/0, fun cleanup/1,[ fun ggs_db_test/0 ]}
% }.
%Key should be a tuple of two elements
getItem_setItem_test() ->
ggs_db:init(),
ggs_db:setItem("dbname","nsname","keyname1","Hello"),
ggs_db:setItem("dbname","nsname","keyname2","Hello2"),
ggs_db:setItem("dbname2","nsname","keyname1","Hello3"),
ggs_db:setItem("dbname2","nsname","keyname1","Hello4"),
ggs_db:setItem("dbname3","nsname","keyname1","Hello5"),
"Hello" = ggs_db:getItem("dbname","nsname","keyname1").
%Test the length function of our database
length_test() ->
ggs_db:setItem(1,1,2,"112"),
ggs_db:setItem(1,2,2,"122"),
ggs_db:setItem(1,1,3,"113"),
ggs_db:setItem(1,1,4,"114"),
?assertEqual(ggs_db:length(1,1), 3).
%Test if we can remove correctly from the database
removeItem_test() ->
ggs_db:removeItem(1,1,4),
?assertNot(ggs_db:getItem(1,1,4) =:= "114").
%Test the key function
key_test() ->
?assert(ggs_db:key(1,1,2) =:= {1,1,2}).
%Test the clear function(for gametoken and ns)
clear_test() ->
ggs_db:clear(1,1),
?assert(ggs_db:length(1,1) =:= 0).
%Test the clear function(gametoken)
clear_GameToken_test() ->
ggs_db:clear(1),
?assert((ggs_db:length(1,1) + ggs_db:length(1,2)) =:= 0),
ggs_db:stop().

31
tests/ggs_gamevm_test.erl Normal file
View file

@ -0,0 +1,31 @@
-module(ggs_gamevm_test).
-include_lib("eunit/include/eunit.hrl").
start_link_test() ->
erlang_js:start(), %% @TODO: should only be done once
GameVM = start_link(test_table),
?assertNot(GameVM =:= undefined).
define_test() ->
GameVM = start_link(test_table),
define(GameVM, "function hello(test) { return test; }"),
?assertMatch(<<"jeena">>, gen_server:call(GameVM, {eval, "hello('jeena')"})).
stop_test() ->
GameVM = start_link(test_table),
ok = stop(GameVM).
user_command_test() ->
GameVM = start_link(test_table),
define(GameVM, "var t = '';\nfunction userCommand(user, command, args) { t = user + command + args; }\n"),
user_command(GameVM, "'jeena", "thecommand", "theargs'"),
?assertMatch(<<"'jeenathecommandtheargs'">>, gen_server:call(GameVM, {eval, "t;"})).
js_erlang_test() ->
GameVM = start_link(test_table),
define(GameVM, "var t = '';\nfunction userCommand(user, command, args) { t = callErlang('erlang time') + ''; }\n"),
user_command(GameVM, "", "", ""),
{A, B, C} = erlang:time(),
T = "{" ++ integer_to_list(A) ++ ", " ++ integer_to_list(B) ++ ", " ++ integer_to_list(C) ++ "}",
?assertMatch(T, binary_to_list(gen_server:call(GameVM, {eval, "t;"}))).

View file

@ -1,5 +1,5 @@
-module(ggs_player_test).
-include_lib("eunit/include/eunit.hrl").
-import(ggs_player).
%% @doc start_link should always return ok for any valid socket. A valid socket
%% should always return {ok, Pid} and {error, Reason} otherwise.
@ -9,9 +9,9 @@ start_link_test() ->
%% @doc Given that start_link returned {ok, Player}. Notify shall always return ok and
%% deliver a specified message through the socket.
notify_test() ->
Player = start_link("bad arg"),
Player = ggs_player:start_link("bad arg"),
Message = {"something", ""},
Ret = ggs_player:notify(Player, self(), Message)
Ret = ggs_player:notify(Player, self(), Message),
?assertNot(ok =:= Ret).
%% @doc Given that start_link returned {ok, Player}. get_token shall always return a valid
@ -22,6 +22,6 @@ get_token_test() ->
%% @doc Given that start_link returned {ok, Pid}. There shouldn't be possible to
%% execute this function with the same Player and Table arguments twice.
stop_test() ->
Player = start_link(something),
Player = ggs_player:start_link(something),
Table = test,
ok = stop(Player, Table).
ok = ggs_player:stop(Player, Table).

38
tests/ggs_table_test.erl Normal file
View file

@ -0,0 +1,38 @@
-module(ggs_table_test).
-include_lib("eunit/include/eunit.hrl").
start_link_test() ->
Table = ggs_table:start_link(),
?assertNot(Table =:= undefined).
add_player_test() ->
Table = ggs_table:start_link(),
Player = test_player,
ggs_table:add_player(Table, Player),
{ok, [Player]} = gen_server:call(Table, get_player_list).
remove_player_test() ->
Table = ggs_table:start_link(),
Player = test_player,
Player2 = test_player2,
ggs_table:add_player(Table, Player),
{ok, [Player]} = gen_server:call(Table, get_player_list),
ggs_table:add_player(Table, Player2),
{ok, [Player2, Player]} = gen_server:call(Table, get_player_list),
ggs_table:remove_player(Table, Player),
{ok, [Player2]} = gen_server:call(Table, get_player_list),
ggs_table:remove_player(Table, Player2),
{ok, []} = gen_server:call(Table, get_player_list).
stop_test() ->
Table = ggs_table:start_link(),
ok = ggs_table:stop(Table).
notify_test() ->
Table = ggs_table:start_link(),
Player = test_player,
Message = {server, define, "function helloWorld(x) { }"},
ok = ggs_table:notify(Table, Player, Message),
Message2 = {game, "helloWorld", "test"},
ok = ggs_table:notify(Table, Player, Message2).