From bf972de0b54a9402b8fda2e16890076edd87f841 Mon Sep 17 00:00:00 2001 From: Jeena Paradies Date: Fri, 25 Feb 2011 20:01:40 +0100 Subject: [PATCH] changed user to player and added first try of the javascript api --- src/ggs_api.js | 177 +++++++++++++++++++++++++++++++++++++++++++ src/ggs_gamevm.erl | 16 ++-- src/ggs_gamevm_e.erl | 12 +-- src/ggs_table.erl | 21 +++-- 4 files changed, 206 insertions(+), 20 deletions(-) create mode 100644 src/ggs_api.js diff --git a/src/ggs_api.js b/src/ggs_api.js new file mode 100644 index 0000000..21c3ddd --- /dev/null +++ b/src/ggs_api.js @@ -0,0 +1,177 @@ +function _GGS(tableToken) { + + this.tableToken = tableToken; + + function Storage(type) { + if (type == "world" || type == "localStorage" || type == "players") { + this.type = type; + this.tableToken = tableToken; + var self = this; + + return { + setItem: function(key, value) { + if(this.type != "players") + callErlang("ggs_db setItem " + escapeErlang([self.tableToken, self.type, key, value])); + else + throw "No such method setItem()"; + }, + getItem: function(key) { + return callErlang("ggs_db getItem " + escapeErlang([self.tableToken, self.type, key])); + }, + key: function(position) { + return callErlang("ggs_db key " + escapeErlang([self.tableToken, self.type, position])); + }, + length: { + get: function() { + return callErlang("ggs_db length " + escapeErlang([self.tableToken, self.type])); + } + }, + removeItem: function(key) { + if(this.type != "players") + callErlang("ggs_db removeItem " + escapeErlang([self.tableToken, self.type, key])); + else + throw "No such method removeItem()"; + }, + clear: function() { + if(this.type != "players") + callErlang("ggs_db clear " + escapeErlang([self.tableToken, self.type])); + else + throw "No such method clear()"; + } + } + } else throw "GGS: No such storage available " + type; + } + + var world = new Storage("world"); + this.__defineGetter__("world", function() { + return world; + }); + + + var localStorage = new Storage("localStorage"); + this.__defineGetter__("localStorage", function() { + return localStorage; + }); + + var players = new Storage("players"); + this.__defineGetter__("players", function() { + return players; + }); + + var tableToken = this.tableToken; + this.__defineGetter__("tableToken", function() { + return tableToken; + }) + +} + +function _GGS.prototype.sendCommandToAll(command, args) { + var message = "{" + command + "," + args + "}"; + callErlang("ggs_table send_command_to_all " + escapeErlang([this.tableToken, message])); +} + +function _GGS.prototype.serverLog(message) { + callErlang("error_logger info_msg " + escapeErlang([message])) +} + +function escapeErlang(args) { + var str = JSON.stringify(args); + str = str.replace("'", "\\\'"); + return "'" + str "'"; +} + + + +function Player(token) { + + var playerToken = token; + this.__defineGetter__("id", function() { + return playerToken; + }); + + return { + sendCommand: function(command, args) { + callErlang("ggs_table send_command " + escapeErlang(GGS.tableToken, command, args)); + } + } +} + + + + +// ------------ Player stuff ------------- +// TODO: remove this later on + +function playerCommand(player, command, args) { + switch(command) { + case "greet": + player.sendCommand("notification", "Welcome on our server!"); + var new_nick = args; + if(validNick(new_nick)) { + newNick(new_nick); + GGS.sendCommandToAll("joined", new_nick); + } + break; + case "chat": + GGS.sendCommandToAll("chat", args); + break; + case "uname": + player.sendCommand("notice", callErlang("os cmd [\"uname -a\"]")) + break; + case "lplayers": + listUsers(player); + break; + case "nick": + if(validNick(new_nick)) { + newNick(new_nick); + GGS.sendCommandToAll("nickchange", old_nick + "," + nicks[player.id]); + } + break; + default: + player.sendCommand("error", "Command not found"); + break; + } +} + +function validNick(new_nick) { + if(new_nick.lastIndexOf(",") != -1) { + player.sendCommand("error", "Mallformed nick " + new_nick); + return false; + } + + var nicks_s = GGS.localStorage("nicks"); + var nicks = {}; + if(nicks_s != "") { // if not the first player + nicks = JSON.parse(nicks_s); + } + for (var id in nicks) { + if (nicks[id] == new_nick) { + player.sendCommand("error", "Nick " + new_nick + " is already taken"); + return false; + } + } + + return true; +} + + +function newNick(new_nick) { + var nicks_s = GGS.localStorage("nicks"); + var nicks = {}; + if(nicks_s != "") { // if not the first player + nicks = JSON.parse(nicks_s); + } + + nicks[player.id] = new_nick; + old_nick = nicks[player.id]; + GGS.localStorage.setItem("nicks", JSON.stringify(nicks)); +} + +function listUsers(player) { + var nicks = JSON.parse(GGS.localStorage.getItem("nicks")); + var nicks_a = []; + for(var id in nicks) { + nicks_a.push(nicks[id]) + } + player.sendCommand("nicklist", nicks_a.join(",")); +} diff --git a/src/ggs_gamevm.erl b/src/ggs_gamevm.erl index babee27..354e7aa 100644 --- a/src/ggs_gamevm.erl +++ b/src/ggs_gamevm.erl @@ -11,7 +11,7 @@ -record(state, { port, table } ). %% API --export([start_link/1, define/2, user_command/4, stop/1, call_js/2]). +-export([start_link/1, define/2, player_command/4, stop/1, call_js/2]). -include_lib("eunit/include/eunit.hrl"). @@ -30,15 +30,15 @@ start_link(Table) -> define(GameVM, SourceCode) -> gen_server:cast(GameVM, {define, SourceCode}). -%% @doc Execute a user command on the specified VM. This function is +%% @doc Execute a player command on the specified VM. This function is %% asynchronous, and returns ok. -%% @spec user_command(GameVM, User, Command, Args) -> ok +%% @spec player_command(GameVM, User, Command, Args) -> ok %% GameVM = process IS of VM %% Player = the player running the command %% Command = a game command to run %% Args = arguments for the Command parameter -user_command(GameVM, Player, Command, Args) -> - gen_server:cast(GameVM, {user_command, Player, Command, Args}). +player_command(GameVM, Player, Command, Args) -> + gen_server:cast(GameVM, {player_command, Player, Command, Args}). %% @private % only for tests @@ -57,6 +57,8 @@ init([Table]) -> process_flag(trap_exit, true), {ok, Port} = js_driver:new(), %% @TODO: add here default JS API instead + {ok, JSAPISourceCode} = file:read_file("ggs_api.js"), + ok = js:define(Port, JSAPISourceCode), {ok, #state { port = Port, table = Table }}. %% private @@ -69,10 +71,10 @@ handle_call({eval, SourceCode}, _From, #state { port = Port } = State) -> handle_cast({define, SourceCode}, #state { port = Port } = State) -> ok = js:define(Port, list_to_binary(SourceCode)), {noreply, State}; -handle_cast({user_command, Player, Command, Args}, #state { port = Port } = State) -> +handle_cast({player_command, Player, Command, Args}, #state { port = Port } = State) -> Arguments = string:concat("'", string:concat( string:join([js_escape(Player), js_escape(Command), js_escape(Args)], "','"), "'")), - Js = list_to_binary(string:concat(string:concat("userCommand(", Arguments), ");")), + Js = list_to_binary(string:concat(string:concat("playerCommand(", Arguments), ");")), js_driver:define_js(Port, Js), {noreply, State}; handle_cast(stop, State) -> diff --git a/src/ggs_gamevm_e.erl b/src/ggs_gamevm_e.erl index 08f9855..10dd74b 100644 --- a/src/ggs_gamevm_e.erl +++ b/src/ggs_gamevm_e.erl @@ -1,5 +1,5 @@ -module(ggs_gamevm_e). --export([start_link/1, define/2, user_command/4]). +-export([start_link/1, define/2, player_command/4]). %% @doc This module is responsible for running the game VM:s. You can issue %% commands to a vm using this module. @@ -16,16 +16,16 @@ define(GameVM, SourceCode) -> GameVM ! {define,SourceCode}, ok. -%% @doc Execute a user command on the specified VM. This function is +%% @doc Execute a player command on the specified VM. This function is %% asynchronous, and returns ok. -%% @spec user_command(GameVM, User, Command, Args) -> ok +%% @spec player_command(GameVM, User, Command, Args) -> ok %% GameVM = process IS of VM %% Player = the player running the command %% Command = a game command to run %% Args = arguments for the Command parameter -user_command(GameVM, Player, Command, Args) -> +player_command(GameVM, Player, Command, Args) -> Ref = make_ref(), - GameVM ! {user_command, Player, Command, Args, self(), Ref}, + GameVM ! {player_command, Player, Command, Args, self(), Ref}, ok. %% Helper functions @@ -35,7 +35,7 @@ loop(Table) -> {define, _SourceCode} -> io:format("GameVM_e can't define functions, sorry!~n"), loop(Table); - {user_command, Player, Command, Args, _From, _Ref} -> + {player_command, Player, Command, Args, _From, _Ref} -> erlang:display(Command), do_stuff(Command, Args, Player, Table), loop(Table) diff --git a/src/ggs_table.erl b/src/ggs_table.erl index dbd16f7..d86abb5 100644 --- a/src/ggs_table.erl +++ b/src/ggs_table.erl @@ -5,8 +5,7 @@ %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3, notify_all_players/2, notify_game/3, - get_player_list/1]). + terminate/2, code_change/3]). -record(state, { players, game_vm } ). @@ -17,7 +16,8 @@ stop/1, notify/3, notify_all_players/2, - notify_game/3]). + notify_game/3, + get_player_list/1]). %% ---------------------------------------------------------------------- @@ -58,12 +58,19 @@ notify_all_players(Table, Message) -> notify_game(Table, From, Message) -> gen_server:cast(Table, {notify_game, Message, From}). +send_command(TableToken, PlayerToken, Command, Args) -> + gen_logger:not_implemented(). + +send_command_to_all(TableToken, Command, Args) -> + gen_logger:not_implemented(). + + %% ---------------------------------------------------------------------- %% @private init([]) -> process_flag(trap_exit, true), - GameVM = ggs_gamevm_e:start_link(self()), %% @TODO: Temporary erlang gamevm + GameVM = ggs_gamevm:start_link(self()), {ok, #state { game_vm = GameVM, players = [] }}. @@ -86,14 +93,14 @@ handle_call(Msg, _From, State) -> handle_cast({notify, Player, Message}, #state { game_vm = GameVM } = State) -> case Message of {server, define, Args} -> - ggs_gamevm_e:define(GameVM, Args); + ggs_gamevm:define(GameVM, Args); {game, Command, Args} -> - ggs_gamevm_e:user_command(GameVM, Player, Command, Args) + ggs_gamevm:player_command(GameVM, Player, Command, Args) end, {noreply, State}; handle_cast({notify_game, Message, From}, #state { game_vm = GameVM } = State) -> - ggs_gamevm_e:user_command(GameVM, From, Message, ""), + ggs_gamevm:player_command(GameVM, From, Message, ""), {noreply, State}; handle_cast({notify_all_players, Message}, #state{players = Players} = State) ->