game_machine 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +13 -9
  3. data/config/config.example.yml +8 -1
  4. data/config/game_messages.proto +1 -0
  5. data/config/messages.proto +4 -0
  6. data/games/example/lib/npc.rb +8 -7
  7. data/games/models.rb +3 -0
  8. data/games/models/clan_member.rb +8 -0
  9. data/games/models/clan_profile.rb +9 -0
  10. data/games/models/player.rb +7 -0
  11. data/games/plugins.rb +1 -0
  12. data/games/plugins/team_handler.rb +49 -0
  13. data/games/preload.rb +5 -0
  14. data/java/build.gradle +3 -1
  15. data/java/gradle.properties +1 -1
  16. data/lib/game_machine/actor/base.rb +5 -1
  17. data/lib/game_machine/application.rb +13 -3
  18. data/lib/game_machine/commands/datastore_commands.rb +3 -7
  19. data/lib/game_machine/commands/player_commands.rb +3 -0
  20. data/lib/game_machine/data_store.rb +22 -1
  21. data/lib/game_machine/data_stores/couchbase.rb +18 -1
  22. data/lib/game_machine/endpoints/udp_incoming.rb +0 -1
  23. data/lib/game_machine/game_systems.rb +2 -0
  24. data/lib/game_machine/game_systems/chat.rb +33 -13
  25. data/lib/game_machine/game_systems/chat_manager.rb +24 -3
  26. data/lib/game_machine/game_systems/json_model_persistence.rb +23 -0
  27. data/lib/game_machine/game_systems/region_manager.rb +1 -1
  28. data/lib/game_machine/game_systems/team_manager.rb +421 -0
  29. data/lib/game_machine/handlers/request.rb +4 -0
  30. data/lib/game_machine/model.rb +59 -13
  31. data/lib/game_machine/models.rb +17 -0
  32. data/lib/game_machine/models/create_team.rb +9 -0
  33. data/lib/game_machine/models/destroy_team.rb +8 -0
  34. data/lib/game_machine/models/echo_test.rb +6 -0
  35. data/lib/game_machine/models/end_match.rb +7 -0
  36. data/lib/game_machine/models/find_match.rb +7 -0
  37. data/lib/game_machine/models/join_team.rb +7 -0
  38. data/lib/game_machine/models/leave_team.rb +7 -0
  39. data/lib/game_machine/models/match.rb +9 -0
  40. data/lib/game_machine/models/player_team.rb +9 -0
  41. data/lib/game_machine/models/start_match.rb +8 -0
  42. data/lib/game_machine/models/team.rb +11 -0
  43. data/lib/game_machine/models/team_accept_invite.rb +9 -0
  44. data/lib/game_machine/models/team_invite.rb +8 -0
  45. data/lib/game_machine/models/team_joined.rb +7 -0
  46. data/lib/game_machine/models/team_left.rb +7 -0
  47. data/lib/game_machine/models/teams.rb +7 -0
  48. data/lib/game_machine/models/teams_request.rb +6 -0
  49. data/lib/game_machine/object_db.rb +17 -11
  50. data/lib/game_machine/version.rb +1 -1
  51. data/lib/game_machine/write_behind_cache.rb +1 -1
  52. data/spec/actor/actor_spec.rb +5 -5
  53. data/spec/actor/ref_spec.rb +10 -10
  54. data/spec/client_manager_spec.rb +9 -9
  55. data/spec/commands/chat_commands_spec.rb +1 -1
  56. data/spec/commands/datastore_commands_spec.rb +10 -14
  57. data/spec/commands/navigation_commands_spec.rb +3 -3
  58. data/spec/commands/player_commands_spec.rb +1 -1
  59. data/spec/game_systems/agents/controller_spec.rb +6 -6
  60. data/spec/game_systems/chat_manager_spec.rb +1 -1
  61. data/spec/game_systems/chat_spec.rb +15 -17
  62. data/spec/game_systems/region_manager_spec.rb +31 -21
  63. data/spec/game_systems/team_manager_spec.rb +291 -0
  64. data/spec/grid_spec.rb +11 -1
  65. data/spec/handlers/authentication_spec.rb +1 -10
  66. data/spec/handlers/game_spec.rb +2 -2
  67. data/spec/handlers/request_spec.rb +10 -21
  68. data/spec/hashring_spec.rb +11 -11
  69. data/spec/java_grid_spec.rb +1 -1
  70. data/spec/misc_spec.rb +2 -2
  71. data/spec/model_spec.rb +26 -14
  72. data/spec/write_behind_cache_spec.rb +15 -15
  73. metadata +29 -8
  74. data/lib/game_machine/bot/chat.rb +0 -66
  75. data/lib/game_machine/bot/client.rb +0 -54
  76. data/spec/data_stores/mapdb_spec.rb +0 -46
  77. data/spec/data_stores/redis_spec.rb +0 -44
@@ -22,7 +22,11 @@ module GameMachine
22
22
  aspect %w(ChatInvite Player)
23
23
 
24
24
  def define_update_procs
25
- commands.datastore.define_dbproc(:chat_remove_subscriber) do |current_entity,update_entity|
25
+ commands.datastore.define_dbproc(:chat_remove_subscriber) do |id,current_entity,update_entity|
26
+ if current_entity.nil?
27
+ current_entity = MessageLib::Entity.new.set_id(id)
28
+ end
29
+
26
30
  if current_entity.has_subscribers
27
31
  if subscriber_id_list = current_entity.subscribers.get_subscriber_id_list.to_a
28
32
  current_entity.subscribers.set_subscriber_id_list(nil)
@@ -36,10 +40,15 @@ module GameMachine
36
40
  current_entity
37
41
  end
38
42
 
39
- commands.datastore.define_dbproc(:chat_add_subscriber) do |current_entity,update_entity|
43
+ commands.datastore.define_dbproc(:chat_add_subscriber) do |id,current_entity,update_entity|
44
+ if current_entity.nil?
45
+ current_entity = MessageLib::Entity.new.set_id(id)
46
+ end
47
+
40
48
  unless current_entity.has_subscribers
41
49
  current_entity.set_subscribers(MessageLib::Subscribers.new)
42
50
  end
51
+
43
52
  subscriber_id_list = current_entity.subscribers.get_subscriber_id_list.to_a
44
53
  unless subscriber_id_list.include?(update_entity.id)
45
54
  current_entity.subscribers.add_subscriber_id(update_entity.id)
@@ -54,6 +63,14 @@ module GameMachine
54
63
  end
55
64
 
56
65
  def on_receive(message)
66
+ if message.is_a?(MessageLib::ChatDestroy)
67
+ if @chat_actors.has_key?(message.player_id)
68
+ ask_child(message.player_id,message)
69
+ destroy_child(message.player_id)
70
+ end
71
+ return
72
+ end
73
+
57
74
  if message.has_chat_invite
58
75
  send_invite(message.chat_invite)
59
76
  elsif message.has_chat_register
@@ -85,12 +102,16 @@ module GameMachine
85
102
  if @chat_actors.has_key?(chat_id)
86
103
  forward_chat_request(chat_id,JavaLib::PoisonPill.get_instance)
87
104
  @chat_actors.delete(chat_id)
88
- GameMachine.logger.debug "Chat child for #{chat_id} killed"
105
+ GameMachine.logger.info "Chat child for #{chat_id} killed"
89
106
  else
90
107
  GameMachine.logger.info "chat actor for chat_id #{chat_id} not found"
91
108
  end
92
109
  end
93
110
 
111
+ def ask_child(chat_id,message)
112
+ @chat_actors[chat_id].ask(message,500)
113
+ end
114
+
94
115
  def forward_chat_request(chat_id,message)
95
116
  @chat_actors[chat_id].tell(message,nil)
96
117
  end
@@ -0,0 +1,23 @@
1
+ module GameMachine
2
+ module GameSystems
3
+ class JsonModelPersistence < Actor::Base
4
+ include Commands
5
+
6
+ def on_receive(message)
7
+ json_model = message
8
+ if json_model.id
9
+ if json_model.id.match(/find_by_id/)
10
+ id = json_model.id.sub('find_by_id','')
11
+ if json_model = json_model.class.find(id)
12
+ commands.player.send_message(json_model,message.player_id)
13
+ end
14
+ else
15
+ json_model.save
16
+ end
17
+ else
18
+ unhandled(message)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -5,7 +5,7 @@ module GameMachine
5
5
  include GameMachine::Commands
6
6
  include GameMachine::Models
7
7
 
8
- attr_reader :regions, :servers
8
+ attr_accessor :regions, :servers
9
9
  def post_init(*args)
10
10
  @regions = {}
11
11
  @servers = {}
@@ -0,0 +1,421 @@
1
+ module GameMachine
2
+ module GameSystems
3
+ class TeamManager < Actor::Base
4
+ include Models
5
+ include Commands
6
+
7
+ attr_reader :team_handler
8
+ def post_init(*args)
9
+ if Application.config.team_handler
10
+ @team_handler = Application.config.team_handler.constantize.new
11
+ end
12
+ define_update_procs
13
+ commands.misc.client_manager_register(self.class.name)
14
+ end
15
+
16
+ def self.match_id_for(team_names)
17
+ team_names.sort.join('_')
18
+ end
19
+
20
+ def chat_channel(topic,flags)
21
+ MessageLib::ChatChannel.new.set_name(topic).set_flags(flags)
22
+ end
23
+
24
+ def player_entity(player_id)
25
+ MessageLib::Entity.new.set_player(MessageLib::Player.new.set_id(player_id))
26
+ end
27
+
28
+ def flags
29
+ 'subscribers'
30
+ end
31
+
32
+ def leave_chat(topic,player_id)
33
+ leave_chat = MessageLib::LeaveChat.new.add_chat_channel(chat_channel(topic,flags))
34
+ entity = player_entity(player_id).set_leave_chat(leave_chat)
35
+ ChatManager.find.tell(entity)
36
+ end
37
+
38
+ def join_chat(topic,player_id)
39
+ join_chat = MessageLib::JoinChat.new.add_chat_channel(chat_channel(topic,flags))
40
+ entity = player_entity(player_id).set_join_chat(join_chat)
41
+ ChatManager.find.tell(entity)
42
+ end
43
+
44
+ def send_team_joined(team_name,player_id)
45
+ commands.player.send_message(TeamJoined.new(:name => team_name),player_id)
46
+ end
47
+
48
+ def send_team_left(team_name,player_id)
49
+ commands.player.send_message(TeamLeft.new(:name => team_name),player_id)
50
+ end
51
+
52
+ def create_player_team(team_name,player_id)
53
+ player_team = PlayerTeam.new(:id => player_id, :name => team_name)
54
+ player_team.save!
55
+ end
56
+
57
+ def send_team(message)
58
+ if player_team = PlayerTeam.find!(message.player_id)
59
+ if team = Team.find!(player_team.name)
60
+ commands.player.send_message(team,message.player_id)
61
+ end
62
+ end
63
+ end
64
+
65
+ def teams_request(message)
66
+ if teams = Teams.find('teams')
67
+ teams = handler_teams_filter(teams,message)
68
+ commands.player.send_message(teams,message.player_id)
69
+ end
70
+ send_team(message)
71
+ end
72
+
73
+ def destroy_player_team(player_id)
74
+ if player_team = PlayerTeam.find!(player_id)
75
+ player_team.destroy!
76
+ end
77
+ end
78
+
79
+ def team_id(team_name)
80
+ Uniqueid.generate_token(team_name)
81
+ end
82
+
83
+ def default_max_members
84
+ 100
85
+ end
86
+
87
+ def can_add_member?(team_name,player_id)
88
+ return true unless team_handler
89
+ team_handler.can_add_member?(team_name, player_id)
90
+ end
91
+
92
+ def can_create_team?(team_name,player_id)
93
+ return true unless team_handler
94
+ team_handler.can_create_team?(team_name, player_id)
95
+ end
96
+
97
+ def handler_update_teams
98
+ return true unless team_handler
99
+ team_handler.update_teams
100
+ end
101
+
102
+ def destroy_on_owner_leave?
103
+ return true unless team_handler
104
+ team_handler.destroy_on_owner_leave?
105
+ end
106
+
107
+ def handler_teams_filter(teams,teams_request)
108
+ return teams unless team_handler
109
+ team_handler.teams_filter(teams,teams_request)
110
+ end
111
+
112
+ def handler_find_match(team_name)
113
+ return true unless team_handler
114
+ team_handler.match!(team_name)
115
+ end
116
+
117
+ def handler_match_started(match)
118
+ return true unless team_handler
119
+ team_handler.match_started(match)
120
+ end
121
+
122
+ def create_team(message)
123
+ unless can_create_team?(message.name,message.player_id)
124
+ return false
125
+ end
126
+
127
+ if team = Team.find!(message.name)
128
+ send_team_joined(team.name,message.player_id)
129
+ return false
130
+ end
131
+
132
+ message.max_members ||= default_max_members
133
+
134
+ team = Team.new(
135
+ :id => message.name,
136
+ :team_id => team_id(message.name),
137
+ :name => message.name,
138
+ :owner => message.owner,
139
+ :access => message.access,
140
+ :max_members => message.max_members,
141
+ :destroy_on_owner_leave => destroy_on_owner_leave?,
142
+ :members => [message.owner]
143
+ )
144
+
145
+ create_player_team(team.name,message.player_id)
146
+ if team.access == 'private'
147
+ team.invite_id = Uniqueid.generate_token(team.name)
148
+ end
149
+
150
+ team.save!
151
+ commands.datastore.call_dbproc(:team_add_team,'teams',team.to_storage_entity,false)
152
+ join_chat(team.name,team.owner)
153
+ send_team_joined(team.name,message.player_id)
154
+ handler_update_teams
155
+ end
156
+
157
+ def member_disconnected(message)
158
+ if player_team = PlayerTeam.find!(message.player_id)
159
+ leave = LeaveTeam.new(
160
+ :name => player_team.name,
161
+ :player_id => message.player_id
162
+ )
163
+ leave_team(leave)
164
+ end
165
+ end
166
+
167
+ def destroy_team(message,force=false)
168
+ if team = Team.find!(message.name)
169
+ if team.owner == message.player_id || force
170
+ team.members.each do |member|
171
+ leave_chat(message.name,member)
172
+ destroy_player_team(member)
173
+ send_team_left(team.name,member)
174
+ end
175
+ commands.datastore.call_dbproc(:team_remove_team,'teams',team.to_storage_entity,false)
176
+ team.destroy!
177
+ handler_update_teams
178
+
179
+ # team destroyed ends match
180
+ if team.match_id
181
+ end_match(EndMatch.new(:match_id => team.match_id))
182
+ end
183
+ end
184
+ end
185
+ unless force
186
+ send_team_left(message.name,message.player_id)
187
+ end
188
+ end
189
+
190
+ def join_team(message,invite_accepted=false)
191
+ unless can_add_member?(message.name,message.player_id)
192
+ return false
193
+ end
194
+
195
+ if team = Team.find!(message.name)
196
+
197
+ if (team.max_members.nil? || team.max_members == 0)
198
+ team.max_members = default_max_members
199
+ end
200
+
201
+ if team.members.size >= team.max_members
202
+ return
203
+ end
204
+
205
+ if team.access == 'public' || invite_accepted
206
+ unless team.members.include?(message.player_id)
207
+ team.members << message.player_id
208
+ team.save!
209
+ create_player_team(team.name,message.player_id)
210
+ commands.datastore.call_dbproc(:team_update_team,'teams',team.to_storage_entity,false)
211
+ end
212
+ join_chat(team.name,message.player_id)
213
+ send_team_joined(message.name,message.player_id)
214
+ end
215
+ end
216
+ end
217
+
218
+ def leave_team(message)
219
+ if team = Team.find!(message.name)
220
+ if message.player_id == team.owner && destroy_on_owner_leave?
221
+ destroy_team(
222
+ DestroyTeam.new(
223
+ :name => team.name,
224
+ :player_id => message.player_id
225
+ )
226
+ )
227
+ return
228
+ end
229
+
230
+
231
+ # Last member, just destroy
232
+ if team.members.include?(message.player_id) && team.members.size == 1
233
+ destroy_team(
234
+ DestroyTeam.new(
235
+ :name => team.name,
236
+ :player_id => message.player_id
237
+ ),
238
+ true
239
+ )
240
+ return
241
+ end
242
+
243
+ team.members.delete_if {|member| member == message.player_id}
244
+
245
+ # Reassign owner if they leave
246
+ if team.owner == message.player_id
247
+ team.owner = team.members.first
248
+ end
249
+
250
+ team.save!
251
+ commands.datastore.call_dbproc(:team_update_team,'teams',team.to_storage_entity,false)
252
+ destroy_player_team(message.player_id)
253
+ send_team_left(message.name,message.player_id)
254
+ leave_chat(message.name,message.player_id)
255
+ else
256
+ send_team_left(message.name,message.player_id)
257
+ end
258
+ end
259
+
260
+ def team_invite(message)
261
+ if team = Team.find!(message.name)
262
+ if message.player_id == team.owner
263
+ message.invite_id = team.invite_id
264
+ commands.player.send_message(message,message.invitee)
265
+ end
266
+ end
267
+ end
268
+
269
+ def team_accept_invite(message)
270
+ if team = Team.find!(message.name)
271
+ if message.invite_id == team.invite_id
272
+ join_team(JoinTeam.new(:name => team.name, :player_id => message.player_id),true)
273
+ end
274
+ end
275
+ end
276
+
277
+ def end_match(message)
278
+ if message.player_id
279
+ return
280
+ end
281
+
282
+ if match = Match.find!(message.match_id)
283
+ match.teams.each do |team|
284
+ if team = Team.find!(team.name)
285
+ team.match_id = nil
286
+ team.save!
287
+ end
288
+ end
289
+ match.destroy
290
+ end
291
+ end
292
+
293
+ # Called internally or from another actor to start an already defined match
294
+ def start_match(message)
295
+ # Don't accept requests from clients
296
+ if message.player_id
297
+ return
298
+ end
299
+
300
+ match_id = self.class.match_id_for(message.team_names)
301
+ if match = Match.find!(match_id)
302
+ GameMachine.logger.warn "Match #{match_id} already created"
303
+ return
304
+ end
305
+
306
+ teams = message.team_names.collect {|name| Team.find!(name)}.compact
307
+ if teams.size != message.team_names.size
308
+ GameMachne.logger.warn "#{self.class.name} Unable to find all teams for match"
309
+ return
310
+ end
311
+
312
+ server = Akka.instance.hashring.bucket_for(match_id)
313
+ server = server.sub('akka.tcp://cluster@','').split(':').first
314
+
315
+ match = Match.new(
316
+ :id => match_id,
317
+ :teams => teams,
318
+ :server => server,
319
+ :game_handler => message.game_handler
320
+ )
321
+
322
+ teams.each do |team|
323
+ team.match_id = match_id
324
+ team.match_server = server
325
+ team.save
326
+ commands.datastore.call_dbproc(:team_update_team,'teams',team.to_storage_entity,false)
327
+ end
328
+
329
+ match.save
330
+ handler_match_started(match)
331
+ GameMachine.logger.info "#{self.class.name} Match #{match} started"
332
+ end
333
+
334
+ def find_match(message)
335
+ if team = Team.find(message.team_name)
336
+ if s = handler_find_match(message.team_name)
337
+ GameMachine.logger.info "Match found: #{s}"
338
+ start_match(s)
339
+ end
340
+ end
341
+ end
342
+
343
+ def on_receive(message)
344
+ if message.is_a?(CreateTeam)
345
+ create_team(message)
346
+ send_team(message)
347
+ elsif message.is_a?(DestroyTeam)
348
+ destroy_team(message)
349
+ elsif message.is_a?(TeamInvite)
350
+ team_invite(message)
351
+ elsif message.is_a?(TeamAcceptInvite)
352
+ team_accept_invite(message)
353
+ elsif message.is_a?(JoinTeam)
354
+ join_team(message)
355
+ send_team(message)
356
+ elsif message.is_a?(LeaveTeam)
357
+ leave_team(message)
358
+ elsif message.is_a?(TeamsRequest)
359
+ teams_request(message)
360
+ elsif message.is_a?(FindMatch)
361
+ find_match(message)
362
+ elsif message.is_a?(StartMatch)
363
+ start_match(message)
364
+ elsif message.is_a?(EndMatch)
365
+ end_match(message)
366
+ elsif message.is_a?(MessageLib::ClientManagerEvent)
367
+ if message.event == 'disconnected'
368
+ member_disconnected(message)
369
+ GameMachine.logger.info "#{self.class.name} #{message.player_id} removed from team(disconnected)"
370
+ end
371
+ else
372
+ unhandled(message)
373
+ end
374
+ end
375
+
376
+ def define_update_procs
377
+ commands.datastore.define_dbproc(:team_update_team) do |id,current_entity,update_entity|
378
+ if current_entity.nil?
379
+ teams = Teams.new(:teams => [],:id => id)
380
+ else
381
+ teams = Teams.from_entity(current_entity,:json_storage)
382
+ end
383
+
384
+ team = Team.from_entity(update_entity,:json_storage)
385
+ team_to_update = teams.teams.select {|t| t.name == team.name}.first
386
+ if team_to_update
387
+ teams.teams.delete_if {|t| t.name == team.name}
388
+ teams.teams << team
389
+ end
390
+ teams.to_storage_entity
391
+ end
392
+
393
+ commands.datastore.define_dbproc(:team_add_team) do |id,current_entity,update_entity|
394
+ if current_entity.nil?
395
+ teams = Teams.new(:teams => [],:id => id)
396
+ else
397
+ teams = Teams.from_entity(current_entity,:json_storage)
398
+ end
399
+
400
+ team = Team.from_entity(update_entity,:json_storage)
401
+ teams.teams.delete_if {|t| t.name == team.name}
402
+ teams.teams << team
403
+ teams.to_storage_entity
404
+ end
405
+
406
+ commands.datastore.define_dbproc(:team_remove_team) do |id,current_entity,update_entity|
407
+ if current_entity.nil?
408
+ teams = Teams.new(:teams => [],:id => id)
409
+ else
410
+ teams = Teams.from_entity(current_entity,:json_storage)
411
+ end
412
+
413
+ team = Team.from_entity(update_entity,:json_storage)
414
+ teams.teams.delete_if {|t| t.name == team.name}
415
+ teams.to_storage_entity
416
+ end
417
+
418
+ end
419
+ end
420
+ end
421
+ end