n2o_game.erl 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. -module(n2o_game).
  2. -author('Maxim Sokhatsky').
  3. -include_lib("n2o/include/wf.hrl").
  4. -include_lib("server/include/requests.hrl").
  5. -include_lib("server/include/game_okey.hrl").
  6. -include_lib("server/include/game_tavla.hrl").
  7. -export([init/4]).
  8. -export([stream/3]).
  9. -export([info/3]).
  10. -export([terminate/2]).
  11. -define(PERIOD, 1000).
  12. init(_Transport, Req, _Opts, _Active) ->
  13. put(actions,[]),
  14. Ctx = wf_context:init_context(Req),
  15. NewCtx = wf_core:fold(init,Ctx#context.handlers,Ctx),
  16. wf_context:context(NewCtx),
  17. Res = ets:update_counter(globals,onlineusers,{2,1}),
  18. wf:reg(broadcast,wf:peer(Req)),
  19. wf:send(broadcast,{counter,Res}),
  20. Req1 = wf:header(<<"Access-Control-Allow-Origin">>, <<"*">>, NewCtx#context.req),
  21. {ok, Req1, NewCtx}.
  22. %% {'KamfMessage',23,game_event,[{game,undefined},{event,okey_tile_taken},{args,[{player,<<"dusler">>},{pile,0},{revealed,null},{pile_height,43}]}]}
  23. is_proplist([]) -> true;
  24. is_proplist([{K,_}|L]) when is_atom(K) -> is_proplist(L);
  25. is_proplist(_) -> false.
  26. stream(<<"ping">>, Req, State) ->
  27. wf:info("ping received~n"),
  28. {reply, <<"pong">>, Req, State};
  29. stream({text,Data}, Req, State) ->
  30. wf:info("Text Received ~p",[Data]),
  31. self() ! Data,
  32. {ok, Req,State};
  33. stream({binary,Info}, Req, State) ->
  34. wf:info("Binary Received: ~p",[Info]),
  35. Pro = binary_to_term(Info,[safe]),
  36. wf:info("N2O Unknown Event: ~p",[Pro]),
  37. case Pro of
  38. {client,M} -> info({client,M},Req,State);
  39. _ ->
  40. Pickled = proplists:get_value(pickle,Pro),
  41. Linked = proplists:get_value(linked,Pro),
  42. Depickled = wf:depickle(Pickled),
  43. wf:info("Depickled: ~p",[Depickled]),
  44. case Depickled of
  45. #ev{module=Module,name=Function,payload=Parameter,trigger=Trigger} ->
  46. case Function of
  47. control_event -> lists:map(fun({K,V})-> put(K,V) end,Linked),
  48. Module:Function(Trigger, Parameter);
  49. api_event -> Module:Function(Parameter,Linked,State);
  50. event -> lists:map(fun({K,V})-> put(K,V) end,Linked),
  51. Module:Function(Parameter);
  52. UserCustomEvent -> Module:Function(Parameter,Trigger,State) end;
  53. _Ev -> wf:error("N2O allows only #ev{} events") end,
  54. Actions = get(actions),
  55. wf_context:clear_actions(),
  56. Render = wf:render(Actions),
  57. GenActions = get(actions),
  58. RenderGenActions = wf:render(GenActions),
  59. wf_context:clear_actions(),
  60. {reply, [Render,RenderGenActions], Req, State} end;
  61. stream(Data, Req, State) ->
  62. wf:info("Data Received ~p",[Data]),
  63. self() ! Data,
  64. {ok, Req,State}.
  65. render_actions(InitActions) ->
  66. RenderInit = wf:render(InitActions),
  67. InitGenActions = get(actions),
  68. RenderInitGenActions = wf:render(InitGenActions),
  69. wf_context:clear_actions(),
  70. [RenderInit,RenderInitGenActions].
  71. info({client,Message}, Req, State) ->
  72. GamePid = get(game_session),
  73. game_session:process_request(GamePid, Message),
  74. wf:info("Client Message: ~p",[Message]),
  75. {reply,[],Req,State};
  76. info({send_message,Message}, Req, State) ->
  77. wf:info("Game Message: ~p",[Message]),
  78. Ret = io_lib:format("~p",[Message]),
  79. T = wf:js_escape(Ret),
  80. {reply,io_lib:format("console.log('~s')",[T]),Req,State};
  81. info(Pro, Req, State) ->
  82. Render =
  83. case Pro of
  84. {flush,Actions} ->
  85. % wf:info("Comet Actions: ~p",[Actions]),
  86. wf:render(Actions);
  87. <<"N2O,",Rest/binary>> ->
  88. Module = State#context.module, Module:event(init),
  89. InitActions = get(actions),
  90. wf_context:clear_actions(),
  91. Pid = wf:depickle(Rest),
  92. %wf:info("Transition Pid: ~p",[Pid]),
  93. case Pid of
  94. undefined ->
  95. %wf:info("Path: ~p",[wf:path(Req)]),
  96. %wf:info("Module: ~p",[Module]),
  97. Elements = try Module:main() catch C:E -> wf:error_page(C,E) end,
  98. wf_core:render(Elements),
  99. render_actions(InitActions);
  100. Transition ->
  101. X = Pid ! {'N2O',self()},
  102. R = receive Actions -> [ render_actions(InitActions) | wf:render(Actions) ]
  103. after 100 ->
  104. QS = element(14, Req),
  105. wf:redirect(case QS of <<>> -> ""; _ -> "" ++ "?" ++ wf:to_list(QS) end),
  106. []
  107. end,
  108. R
  109. end;
  110. <<"PING">> -> [];
  111. Unknown ->
  112. wf:info("Unknown WS Info Message ~p", [Unknown]),
  113. M = State#context.module,
  114. catch M:event(Unknown),
  115. Actions = get(actions),
  116. wf_context:clear_actions(),
  117. wf:render(Actions) end,
  118. GenActions = get(actions),
  119. wf_context:clear_actions(),
  120. RenderGenActions = wf:render(GenActions),
  121. wf_context:clear_actions(),
  122. {reply, [Render,RenderGenActions], Req, State}.
  123. terminate(_Req, _State=#context{module=Module}) ->
  124. % wf:info("Bullet Terminated~n"),
  125. Res = ets:update_counter(globals,onlineusers,{2,-1}),
  126. wf:send(broadcast,{counter,Res}),
  127. catch Module:event(terminate),
  128. ok.