changed user to player and added first try of the javascript api
This commit is contained in:
parent
7de4fc58cd
commit
bf972de0b5
4 changed files with 206 additions and 20 deletions
177
src/ggs_api.js
Normal file
177
src/ggs_api.js
Normal file
|
@ -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(","));
|
||||||
|
}
|
|
@ -11,7 +11,7 @@
|
||||||
-record(state, { port, table } ).
|
-record(state, { port, table } ).
|
||||||
|
|
||||||
%% API
|
%% 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").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
@ -30,15 +30,15 @@ start_link(Table) ->
|
||||||
define(GameVM, SourceCode) ->
|
define(GameVM, SourceCode) ->
|
||||||
gen_server:cast(GameVM, {define, 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.
|
%% 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
|
%% GameVM = process IS of VM
|
||||||
%% Player = the player running the command
|
%% Player = the player running the command
|
||||||
%% Command = a game command to run
|
%% Command = a game command to run
|
||||||
%% Args = arguments for the Command parameter
|
%% Args = arguments for the Command parameter
|
||||||
user_command(GameVM, Player, Command, Args) ->
|
player_command(GameVM, Player, Command, Args) ->
|
||||||
gen_server:cast(GameVM, {user_command, Player, Command, Args}).
|
gen_server:cast(GameVM, {player_command, Player, Command, Args}).
|
||||||
|
|
||||||
%% @private
|
%% @private
|
||||||
% only for tests
|
% only for tests
|
||||||
|
@ -57,6 +57,8 @@ init([Table]) ->
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
{ok, Port} = js_driver:new(),
|
{ok, Port} = js_driver:new(),
|
||||||
%% @TODO: add here default JS API instead
|
%% @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 }}.
|
{ok, #state { port = Port, table = Table }}.
|
||||||
|
|
||||||
%% private
|
%% private
|
||||||
|
@ -69,10 +71,10 @@ handle_call({eval, SourceCode}, _From, #state { port = Port } = State) ->
|
||||||
handle_cast({define, SourceCode}, #state { port = Port } = State) ->
|
handle_cast({define, SourceCode}, #state { port = Port } = State) ->
|
||||||
ok = js:define(Port, list_to_binary(SourceCode)),
|
ok = js:define(Port, list_to_binary(SourceCode)),
|
||||||
{noreply, State};
|
{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(
|
Arguments = string:concat("'", string:concat(
|
||||||
string:join([js_escape(Player), js_escape(Command), js_escape(Args)], "','"), "'")),
|
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),
|
js_driver:define_js(Port, Js),
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
handle_cast(stop, State) ->
|
handle_cast(stop, State) ->
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
-module(ggs_gamevm_e).
|
-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
|
%% @doc This module is responsible for running the game VM:s. You can issue
|
||||||
%% commands to a vm using this module.
|
%% commands to a vm using this module.
|
||||||
|
|
||||||
|
@ -16,16 +16,16 @@ define(GameVM, SourceCode) ->
|
||||||
GameVM ! {define,SourceCode},
|
GameVM ! {define,SourceCode},
|
||||||
ok.
|
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.
|
%% 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
|
%% GameVM = process IS of VM
|
||||||
%% Player = the player running the command
|
%% Player = the player running the command
|
||||||
%% Command = a game command to run
|
%% Command = a game command to run
|
||||||
%% Args = arguments for the Command parameter
|
%% Args = arguments for the Command parameter
|
||||||
user_command(GameVM, Player, Command, Args) ->
|
player_command(GameVM, Player, Command, Args) ->
|
||||||
Ref = make_ref(),
|
Ref = make_ref(),
|
||||||
GameVM ! {user_command, Player, Command, Args, self(), Ref},
|
GameVM ! {player_command, Player, Command, Args, self(), Ref},
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
%% Helper functions
|
%% Helper functions
|
||||||
|
@ -35,7 +35,7 @@ loop(Table) ->
|
||||||
{define, _SourceCode} ->
|
{define, _SourceCode} ->
|
||||||
io:format("GameVM_e can't define functions, sorry!~n"),
|
io:format("GameVM_e can't define functions, sorry!~n"),
|
||||||
loop(Table);
|
loop(Table);
|
||||||
{user_command, Player, Command, Args, _From, _Ref} ->
|
{player_command, Player, Command, Args, _From, _Ref} ->
|
||||||
erlang:display(Command),
|
erlang:display(Command),
|
||||||
do_stuff(Command, Args, Player, Table),
|
do_stuff(Command, Args, Player, Table),
|
||||||
loop(Table)
|
loop(Table)
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
|
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
terminate/2, code_change/3, notify_all_players/2, notify_game/3,
|
terminate/2, code_change/3]).
|
||||||
get_player_list/1]).
|
|
||||||
|
|
||||||
-record(state, { players, game_vm } ).
|
-record(state, { players, game_vm } ).
|
||||||
|
|
||||||
|
@ -17,7 +16,8 @@
|
||||||
stop/1,
|
stop/1,
|
||||||
notify/3,
|
notify/3,
|
||||||
notify_all_players/2,
|
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) ->
|
notify_game(Table, From, Message) ->
|
||||||
gen_server:cast(Table, {notify_game, Message, From}).
|
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
|
%% @private
|
||||||
init([]) ->
|
init([]) ->
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
GameVM = ggs_gamevm_e:start_link(self()), %% @TODO: Temporary erlang gamevm
|
GameVM = ggs_gamevm:start_link(self()),
|
||||||
{ok, #state {
|
{ok, #state {
|
||||||
game_vm = GameVM,
|
game_vm = GameVM,
|
||||||
players = [] }}.
|
players = [] }}.
|
||||||
|
@ -86,14 +93,14 @@ handle_call(Msg, _From, State) ->
|
||||||
handle_cast({notify, Player, Message}, #state { game_vm = GameVM } = State) ->
|
handle_cast({notify, Player, Message}, #state { game_vm = GameVM } = State) ->
|
||||||
case Message of
|
case Message of
|
||||||
{server, define, Args} ->
|
{server, define, Args} ->
|
||||||
ggs_gamevm_e:define(GameVM, Args);
|
ggs_gamevm:define(GameVM, Args);
|
||||||
{game, Command, Args} ->
|
{game, Command, Args} ->
|
||||||
ggs_gamevm_e:user_command(GameVM, Player, Command, Args)
|
ggs_gamevm:player_command(GameVM, Player, Command, Args)
|
||||||
end,
|
end,
|
||||||
{noreply, State};
|
{noreply, State};
|
||||||
|
|
||||||
handle_cast({notify_game, Message, From}, #state { game_vm = GameVM } = 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};
|
{noreply, State};
|
||||||
|
|
||||||
handle_cast({notify_all_players, Message}, #state{players = Players} = State) ->
|
handle_cast({notify_all_players, Message}, #state{players = Players} = State) ->
|
||||||
|
|
Reference in a new issue