game_machine 0.0.10 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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