game_machine 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (273) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +72 -0
  4. data/Rakefile +38 -0
  5. data/bin/game_machine +79 -0
  6. data/config/cluster.conf +65 -0
  7. data/config/config.example.yml +93 -0
  8. data/config/game_messages.proto +45 -0
  9. data/config/messages.proto +339 -0
  10. data/config/regions.example.yml +9 -0
  11. data/config/standalone.conf +36 -0
  12. data/db/do_not_delete +0 -0
  13. data/game_machine.gemspec +38 -0
  14. data/games/example/boot.rb +6 -0
  15. data/games/example/data/game_data.yml +13 -0
  16. data/games/example/lib/aggressive_npc.rb +176 -0
  17. data/games/example/lib/authentication_handler.rb +69 -0
  18. data/games/example/lib/chatbot.rb +61 -0
  19. data/games/example/lib/combat_controller.rb +145 -0
  20. data/games/example/lib/example_controller.rb +21 -0
  21. data/games/example/lib/game.rb +85 -0
  22. data/games/example/lib/models/attack.rb +9 -0
  23. data/games/example/lib/models/combat_update.rb +11 -0
  24. data/games/example/lib/models/player_command.rb +7 -0
  25. data/games/example/lib/models/user.rb +11 -0
  26. data/games/example/lib/models/vitals.rb +17 -0
  27. data/games/example/lib/npc.rb +111 -0
  28. data/games/example/lib/npc_group.rb +42 -0
  29. data/games/example/lib/npc_movement.rb +116 -0
  30. data/games/example/lib/player_manager.rb +58 -0
  31. data/games/example/lib/player_register.rb +80 -0
  32. data/games/example/lib/tracking_handler.rb +17 -0
  33. data/games/example/lib/zone_manager.rb +57 -0
  34. data/games/preload.rb +8 -0
  35. data/integration_tests/basic_spec.rb +68 -0
  36. data/integration_tests/bot_spec.rb +18 -0
  37. data/integration_tests/chat_spec.rb +45 -0
  38. data/integration_tests/distributed_spec.rb +34 -0
  39. data/integration_tests/entity_tracking_spec.rb +48 -0
  40. data/integration_tests/mono_spec.rb +16 -0
  41. data/integration_tests/objectdb_spec.rb +55 -0
  42. data/integration_tests/tcp_client_spec.rb +71 -0
  43. data/integration_tests/udp_client_spec.rb +61 -0
  44. data/integration_tests/udp_spec.rb +20 -0
  45. data/integration_tests/udt_client_spec.rb +23 -0
  46. data/integration_tests/udt_spec.rb +31 -0
  47. data/java/.gitignore +1 -0
  48. data/java/build.gradle +93 -0
  49. data/java/component.erb +396 -0
  50. data/java/gradle.properties +6 -0
  51. data/java/gradle/wrapper/gradle-wrapper.jar +0 -0
  52. data/java/gradle/wrapper/gradle-wrapper.properties +6 -0
  53. data/java/gradlew +164 -0
  54. data/java/gradlew.bat +90 -0
  55. data/java/local_lib/protostuff-compiler-1.0.7-jarjar.jar +0 -0
  56. data/java/settings.gradle +2 -0
  57. data/java/src/main/java/com/game_machine/core/ActorFactory.java +25 -0
  58. data/java/src/main/java/com/game_machine/core/ActorUtil.java +39 -0
  59. data/java/src/main/java/com/game_machine/core/CommandProxy.java +9 -0
  60. data/java/src/main/java/com/game_machine/core/EntitySerializer.java +66 -0
  61. data/java/src/main/java/com/game_machine/core/EventStreamHandler.java +43 -0
  62. data/java/src/main/java/com/game_machine/core/GameMachineLoader.java +25 -0
  63. data/java/src/main/java/com/game_machine/core/Grid.java +195 -0
  64. data/java/src/main/java/com/game_machine/core/GridValue.java +30 -0
  65. data/java/src/main/java/com/game_machine/core/IActorFactory.java +7 -0
  66. data/java/src/main/java/com/game_machine/core/NetMessage.java +28 -0
  67. data/java/src/main/java/com/game_machine/core/UdpServer.java +97 -0
  68. data/java/src/main/java/com/game_machine/core/UdpServerHandler.java +90 -0
  69. data/java/src/main/resources/game_machine.java.stg +738 -0
  70. data/java/src/main/resources/logback.xml +14 -0
  71. data/java/src/main/resources/logging.properties +3 -0
  72. data/java/src/main/resources/protostuff.properties +7 -0
  73. data/lib/game_machine.rb +85 -0
  74. data/lib/game_machine/actor.rb +7 -0
  75. data/lib/game_machine/actor/base.rb +184 -0
  76. data/lib/game_machine/actor/builder.rb +108 -0
  77. data/lib/game_machine/actor/development.rb +31 -0
  78. data/lib/game_machine/actor/factory.rb +35 -0
  79. data/lib/game_machine/actor/mono_actor.rb +89 -0
  80. data/lib/game_machine/actor/ref.rb +81 -0
  81. data/lib/game_machine/actor/reloadable.rb +98 -0
  82. data/lib/game_machine/actor/system.rb +32 -0
  83. data/lib/game_machine/akka.rb +98 -0
  84. data/lib/game_machine/app_config.rb +49 -0
  85. data/lib/game_machine/application.rb +181 -0
  86. data/lib/game_machine/auth_handlers/base.rb +21 -0
  87. data/lib/game_machine/auth_handlers/public.rb +34 -0
  88. data/lib/game_machine/bot/chat.rb +66 -0
  89. data/lib/game_machine/bot/client.rb +54 -0
  90. data/lib/game_machine/client_manager.rb +204 -0
  91. data/lib/game_machine/clients.rb +4 -0
  92. data/lib/game_machine/clients/client.rb +45 -0
  93. data/lib/game_machine/clients/tcp_client.rb +25 -0
  94. data/lib/game_machine/clients/test_client.rb +151 -0
  95. data/lib/game_machine/clients/udp_client.rb +25 -0
  96. data/lib/game_machine/clients/udt_client.rb +34 -0
  97. data/lib/game_machine/cluster_monitor.rb +115 -0
  98. data/lib/game_machine/commands.rb +23 -0
  99. data/lib/game_machine/commands/base.rb +21 -0
  100. data/lib/game_machine/commands/chat_commands.rb +88 -0
  101. data/lib/game_machine/commands/datastore_commands.rb +60 -0
  102. data/lib/game_machine/commands/grid_commands.rb +35 -0
  103. data/lib/game_machine/commands/message_helper.rb +25 -0
  104. data/lib/game_machine/commands/misc_commands.rb +29 -0
  105. data/lib/game_machine/commands/navigation_commands.rb +24 -0
  106. data/lib/game_machine/commands/player_commands.rb +28 -0
  107. data/lib/game_machine/commands/proxy.rb +16 -0
  108. data/lib/game_machine/console.rb +3 -0
  109. data/lib/game_machine/console/build.rb +74 -0
  110. data/lib/game_machine/console/install.rb +92 -0
  111. data/lib/game_machine/console/server.rb +120 -0
  112. data/lib/game_machine/data_store.rb +52 -0
  113. data/lib/game_machine/data_stores/couchbase.rb +18 -0
  114. data/lib/game_machine/data_stores/mapdb.rb +49 -0
  115. data/lib/game_machine/data_stores/memory.rb +35 -0
  116. data/lib/game_machine/data_stores/redis.rb +46 -0
  117. data/lib/game_machine/endpoints.rb +6 -0
  118. data/lib/game_machine/endpoints/mono_gateway.rb +87 -0
  119. data/lib/game_machine/endpoints/tcp.rb +51 -0
  120. data/lib/game_machine/endpoints/tcp_handler.rb +75 -0
  121. data/lib/game_machine/endpoints/udp.rb +88 -0
  122. data/lib/game_machine/endpoints/udp_incoming.rb +113 -0
  123. data/lib/game_machine/endpoints/udp_outgoing.rb +46 -0
  124. data/lib/game_machine/game_loader.rb +46 -0
  125. data/lib/game_machine/game_systems.rb +14 -0
  126. data/lib/game_machine/game_systems/agents/controller.rb +118 -0
  127. data/lib/game_machine/game_systems/chat.rb +256 -0
  128. data/lib/game_machine/game_systems/chat_manager.rb +108 -0
  129. data/lib/game_machine/game_systems/chat_topic.rb +36 -0
  130. data/lib/game_machine/game_systems/devnull.rb +13 -0
  131. data/lib/game_machine/game_systems/entity_loader.rb +12 -0
  132. data/lib/game_machine/game_systems/entity_tracking.rb +133 -0
  133. data/lib/game_machine/game_systems/local_echo.rb +16 -0
  134. data/lib/game_machine/game_systems/objectdb_proxy.rb +61 -0
  135. data/lib/game_machine/game_systems/private_chat.rb +20 -0
  136. data/lib/game_machine/game_systems/region_manager.rb +91 -0
  137. data/lib/game_machine/game_systems/region_service.rb +94 -0
  138. data/lib/game_machine/game_systems/region_settings.rb +13 -0
  139. data/lib/game_machine/game_systems/remote_echo.rb +14 -0
  140. data/lib/game_machine/game_systems/stress_test.rb +21 -0
  141. data/lib/game_machine/grid.rb +60 -0
  142. data/lib/game_machine/grid_replicator.rb +31 -0
  143. data/lib/game_machine/handlers/authentication.rb +55 -0
  144. data/lib/game_machine/handlers/game.rb +63 -0
  145. data/lib/game_machine/handlers/request.rb +80 -0
  146. data/lib/game_machine/hashring.rb +48 -0
  147. data/lib/game_machine/helpers/game_message.rb +159 -0
  148. data/lib/game_machine/helpers/state_machine.rb +29 -0
  149. data/lib/game_machine/java_lib.rb +51 -0
  150. data/lib/game_machine/logger.rb +39 -0
  151. data/lib/game_machine/message_buffer.rb +58 -0
  152. data/lib/game_machine/message_queue.rb +63 -0
  153. data/lib/game_machine/model.rb +125 -0
  154. data/lib/game_machine/models.rb +3 -0
  155. data/lib/game_machine/models/player_status_update.rb +8 -0
  156. data/lib/game_machine/models/region.rb +9 -0
  157. data/lib/game_machine/mono_server.rb +20 -0
  158. data/lib/game_machine/navigation.rb +4 -0
  159. data/lib/game_machine/navigation/detour.rb +20 -0
  160. data/lib/game_machine/navigation/detour_navmesh.rb +53 -0
  161. data/lib/game_machine/navigation/detour_path.rb +53 -0
  162. data/lib/game_machine/navigation/path.rb +31 -0
  163. data/lib/game_machine/object_db.rb +67 -0
  164. data/lib/game_machine/protobuf.rb +6 -0
  165. data/lib/game_machine/protobuf/game_messages.rb +24 -0
  166. data/lib/game_machine/protobuf/generate.rb +113 -0
  167. data/lib/game_machine/protobuf_extensions/entity_helper.rb +11 -0
  168. data/lib/game_machine/reloadable_monitor.rb +26 -0
  169. data/lib/game_machine/restart_watcher.rb +17 -0
  170. data/lib/game_machine/ruby_extensions/nilclass.rb +10 -0
  171. data/lib/game_machine/ruby_extensions/string.rb +17 -0
  172. data/lib/game_machine/scheduler.rb +23 -0
  173. data/lib/game_machine/securerandom.rb +6 -0
  174. data/lib/game_machine/settings.rb +11 -0
  175. data/lib/game_machine/system_monitor.rb +19 -0
  176. data/lib/game_machine/system_stats.rb +24 -0
  177. data/lib/game_machine/uniqueid.rb +23 -0
  178. data/lib/game_machine/vector.rb +95 -0
  179. data/lib/game_machine/version.rb +3 -0
  180. data/lib/game_machine/write_behind_cache.rb +164 -0
  181. data/mono/bin/csharp/common.xslt +109 -0
  182. data/mono/bin/csharp/csharp.xslt +628 -0
  183. data/mono/bin/csharp/descriptor.proto +533 -0
  184. data/mono/bin/csharp/protobuf-net.dll +0 -0
  185. data/mono/bin/csharp/protobuf-net.pdb +0 -0
  186. data/mono/bin/csharp/protobuf-net.xml +2879 -0
  187. data/mono/bin/csharp/protogen.exe.config +3 -0
  188. data/mono/bin/csharp/protogen.pdb +0 -0
  189. data/mono/bin/csharp/protogen_csharp.exe +0 -0
  190. data/mono/bin/csharp/vb.xslt +745 -0
  191. data/mono/bin/csharp/xml.xslt +26 -0
  192. data/mono/server/Makefile +6 -0
  193. data/mono/server/NLog.config +12 -0
  194. data/mono/server/NLog.dll +0 -0
  195. data/mono/server/actor.cs +37 -0
  196. data/mono/server/build.bat +3 -0
  197. data/mono/server/cscompmgd.dll +0 -0
  198. data/mono/server/iactor.cs +11 -0
  199. data/mono/server/message_router.cs +67 -0
  200. data/mono/server/message_util.cs +29 -0
  201. data/mono/server/messages.cs +1888 -0
  202. data/mono/server/protobuf-net.dll +0 -0
  203. data/mono/server/proxy_client.cs +73 -0
  204. data/mono/server/proxy_server.cs +30 -0
  205. data/mono/server/test_actor.cs +33 -0
  206. data/pathfinding/bin/premake4 +0 -0
  207. data/pathfinding/include/mesh_loader.h +28 -0
  208. data/pathfinding/include/pathfind.h +167 -0
  209. data/pathfinding/main.cpp +39 -0
  210. data/pathfinding/mesh_loader.cpp +108 -0
  211. data/pathfinding/pathfind.cpp +174 -0
  212. data/pathfinding/pathfinder.cs +66 -0
  213. data/pathfinding/premake4.lua +109 -0
  214. data/script/server.sh +109 -0
  215. data/script/watch.sh +11 -0
  216. data/spec/actor/actor_spec.rb +73 -0
  217. data/spec/actor/builder_spec.rb +56 -0
  218. data/spec/actor/ref_spec.rb +83 -0
  219. data/spec/application_spec.rb +7 -0
  220. data/spec/client_manager_spec.rb +171 -0
  221. data/spec/commands/chat_commands_spec.rb +38 -0
  222. data/spec/commands/datastore_commands_spec.rb +91 -0
  223. data/spec/commands/grid_commands_spec.rb +37 -0
  224. data/spec/commands/navigation_commands_spec.rb +51 -0
  225. data/spec/commands/player_commands_spec.rb +48 -0
  226. data/spec/commands_spec.rb +38 -0
  227. data/spec/data_stores/mapdb_spec.rb +46 -0
  228. data/spec/data_stores/redis_spec.rb +44 -0
  229. data/spec/game_systems/agents/controller_spec.rb +84 -0
  230. data/spec/game_systems/agents/test_agent.rb +10 -0
  231. data/spec/game_systems/agents/test_agent_config.rb +29 -0
  232. data/spec/game_systems/chat_manager_spec.rb +66 -0
  233. data/spec/game_systems/chat_spec.rb +187 -0
  234. data/spec/game_systems/entity_tracking_spec.rb +64 -0
  235. data/spec/game_systems/region_manager_spec.rb +138 -0
  236. data/spec/grid_spec.rb +37 -0
  237. data/spec/handlers/authentication_spec.rb +36 -0
  238. data/spec/handlers/game_spec.rb +49 -0
  239. data/spec/handlers/request_spec.rb +65 -0
  240. data/spec/hashring_spec.rb +59 -0
  241. data/spec/integration_helper.rb +120 -0
  242. data/spec/java_grid_spec.rb +89 -0
  243. data/spec/message_buffer_spec.rb +67 -0
  244. data/spec/message_expectations.rb +47 -0
  245. data/spec/message_queue_spec.rb +23 -0
  246. data/spec/misc_spec.rb +71 -0
  247. data/spec/model_spec.rb +103 -0
  248. data/spec/mono_spec.rb +36 -0
  249. data/spec/mono_test.rb +18 -0
  250. data/spec/navigation/detour_navmesh_spec.rb +34 -0
  251. data/spec/navigation/detour_path_spec.rb +25 -0
  252. data/spec/spec_helper.rb +40 -0
  253. data/spec/udp_server_spec.rb +10 -0
  254. data/spec/write_behind_cache_spec.rb +109 -0
  255. data/web/app.rb +131 -0
  256. data/web/config/trinidad.yml +4 -0
  257. data/web/controllers/auth_controller.rb +19 -0
  258. data/web/controllers/base_controller.rb +16 -0
  259. data/web/controllers/index_controller.rb +7 -0
  260. data/web/controllers/log_controller.rb +47 -0
  261. data/web/controllers/messages_controller.rb +59 -0
  262. data/web/controllers/player_register_controller.rb +15 -0
  263. data/web/log/development.log +1339 -0
  264. data/web/tmp/restart.txt +0 -0
  265. data/web/views/game_messages.haml +45 -0
  266. data/web/views/index.haml +6 -0
  267. data/web/views/layout.haml +41 -0
  268. data/web/views/logs.haml +32 -0
  269. data/web/views/player_register.haml +22 -0
  270. data/web/views/player_registered.haml +2 -0
  271. data/web/views/register_layout.haml +22 -0
  272. data/web/views/restart.haml +35 -0
  273. metadata +576 -0
@@ -0,0 +1,256 @@
1
+ module GameMachine
2
+ module GameSystems
3
+ class Chat < Actor::Base
4
+ include GameMachine::Commands
5
+
6
+ def self.subscribers_for_topic(topic)
7
+ datastore = GameMachine::Commands::DatastoreCommands.new
8
+ if entity = datastore.get("chat_topic_#{topic}")
9
+ entity.subscribers || MessageLib::Subscribers.new
10
+ else
11
+ MessageLib::Subscribers.new
12
+ end
13
+ end
14
+
15
+ attr_reader :chat_id, :registered_as
16
+ def post_init(*args)
17
+ @chat_id = args.first
18
+ @registered_as = args.last
19
+ @topic_handlers = {}
20
+
21
+ # Update these values from the datastore, as this state needs to
22
+ # persist between restarts
23
+ @subscriptions = get_subscriptions
24
+ @channel_flags = get_flags
25
+
26
+ # Make sure we re-create our state from the persisted state if we died
27
+ load_state
28
+ end
29
+
30
+ def load_state
31
+ @subscriptions.each do |name|
32
+ flags = flags_for_channel(name).join('|')
33
+ join_channel(name,flags)
34
+ end
35
+ end
36
+
37
+ def on_receive(entity)
38
+ if entity.has_join_chat
39
+ join_channels(entity.join_chat.get_chat_channel_list)
40
+ send_status
41
+ end
42
+
43
+ if entity.has_chat_message
44
+ send_message(entity.chat_message)
45
+ end
46
+
47
+ if entity.has_leave_chat
48
+ leave_channels(entity.leave_chat.get_chat_channel_list)
49
+ send_status
50
+ end
51
+
52
+ if entity.has_chat_status
53
+ send_status
54
+ end
55
+ end
56
+
57
+ # flags = subscribers
58
+ def send_status
59
+ channels = MessageLib::ChatChannels.new
60
+ @subscriptions.each do |name|
61
+ flags = @channel_flags.fetch(name,[])
62
+ channel = MessageLib::ChatChannel.new.set_name(name)
63
+ if flags.include?('subscribers')
64
+ channel.set_subscribers(self.class.subscribers_for_topic(name))
65
+ end
66
+ channels.add_chat_channel(channel)
67
+ end
68
+ if registered_as == 'player'
69
+ commands.player.send_message(channels,chat_id)
70
+ else
71
+ message = MessageLib::Entity.new.set_id(chat_id).set_chat_channels(channels)
72
+ Actor::Base.find(registered_as).tell(message,get_self)
73
+ end
74
+ end
75
+
76
+ def message_queue
77
+ MessageQueue.find
78
+ end
79
+
80
+ def topic_handler_for(name)
81
+ @topic_handlers.fetch(name,nil)
82
+ end
83
+
84
+ def create_topic_handler(topic)
85
+ name = "topic#{chat_id}#{topic}"
86
+ builder = Actor::Builder.new(GameSystems::ChatTopic,chat_id,registered_as)
87
+ ref = builder.with_parent(context).with_name(name).start
88
+ actor_ref = Actor::Ref.new(ref,GameSystems::ChatTopic.name)
89
+ @topic_handlers[topic] = actor_ref
90
+ end
91
+
92
+ def remove_subscriber(subscriber_id,topic)
93
+ stored_entity_id = "chat_topic_#{topic}"
94
+ entity = MessageLib::Entity.new.set_id(subscriber_id)
95
+ commands.datastore.call_dbproc(:chat_remove_subscriber,stored_entity_id,entity,false)
96
+ end
97
+
98
+ def add_subscriber(subscriber_id,topic)
99
+ stored_entity_id = "chat_topic_#{topic}"
100
+ entity = MessageLib::Entity.new.set_id(subscriber_id)
101
+ commands.datastore.call_dbproc(:chat_add_subscriber,stored_entity_id,entity,false)
102
+ end
103
+
104
+ def save_subscriptions
105
+ entity_id = "subscriptions_#{chat_id}"
106
+ channels = MessageLib::ChatChannels.new
107
+ @subscriptions.each do |name|
108
+ channel = MessageLib::ChatChannel.new.set_name(name)
109
+ channels.add_chat_channel(channel)
110
+ end
111
+ entity = MessageLib::Entity.new.set_id(entity_id).set_chat_channels(channels)
112
+ commands.datastore.put(entity)
113
+ end
114
+
115
+ def get_subscriptions
116
+ subscriptions = Set.new
117
+ entity_id = "subscriptions_#{chat_id}"
118
+ if entity = commands.datastore.get(entity_id)
119
+ if chat_channels = entity.chat_channels.get_chat_channel_list
120
+ chat_channels.each do |channel|
121
+ subscriptions.add(channel.name)
122
+ end
123
+ end
124
+ end
125
+ subscriptions
126
+ end
127
+
128
+ def parse_channel_flags(flags)
129
+ flags.split('|')
130
+ end
131
+
132
+ def channel_flags_id(name)
133
+ "channel_flags#{@chat_id}#{name}"
134
+ end
135
+
136
+ def flags_for_channel(channel_name)
137
+ @channel_flags.fetch(channel_name,[])
138
+ end
139
+
140
+ def get_flags
141
+ {}.tap do |flags|
142
+ @subscriptions.each do |name|
143
+ if entity = commands.datastore.get(channel_flags_id(name))
144
+ flags[name] = parse_channel_flags(entity.params)
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ def set_channel_flags(name,flags)
151
+ return if flags.nil?
152
+ @channel_flags[name] = parse_channel_flags(flags)
153
+ flags_id = channel_flags_id(name)
154
+ entity = MessageLib::Entity.new.set_id(flags_id).set_params(flags)
155
+ commands.datastore.put(entity)
156
+ end
157
+
158
+ def delete_channel_flags(channel_name)
159
+ flags_id = channel_flags_id(channel_name)
160
+ commands.datastore.delete(flags_id)
161
+ end
162
+
163
+ def invite_exists?(channel_name,invite_id)
164
+ key = "invite_#{channel_name}_#{invite_id}"
165
+ commands.datastore.get(key)
166
+ end
167
+
168
+ def join_channels(chat_channels)
169
+ chat_channels.each do |channel|
170
+ if @topic_handlers[channel.name]
171
+ GameMachine.logger.info "Topic handler exists for #{channel.name}, not creating"
172
+ next
173
+ end
174
+
175
+ GameMachine.logger.info "Join request #{channel.name}"
176
+ # Private channels. format priv_[chat_id]_[channel name]
177
+ # Players can create private channels with their player id, other
178
+ # players must have an invite to join someone elses private channel
179
+ if channel.name.match(/^priv/)
180
+ if channel.name.match(/^priv_#{chat_id}/)
181
+ join_channel(channel.name,channel.flags)
182
+ elsif channel.invite_id
183
+ if invite_exists?(channel.name,channel.invite_id)
184
+ join_channel(channel.name,channel.flags)
185
+ else
186
+ GameMachine.logger.info "Invite id #{channel.invite_id} not found"
187
+ end
188
+ end
189
+ else
190
+ join_channel(channel.name,channel.flags)
191
+ end
192
+ end
193
+ end
194
+
195
+ def join_channel(name,flags)
196
+ create_topic_handler(name)
197
+ message = MessageLib::Subscribe.new.set_topic(name)
198
+ message_queue.tell(message,topic_handler_for(name).actor)
199
+ @subscriptions.add(name)
200
+ save_subscriptions
201
+ add_subscriber(chat_id,name)
202
+ set_channel_flags(name,flags)
203
+ GameMachine.logger.info "Player #{chat_id} Joined channel #{name} with flags #{flags}"
204
+ end
205
+
206
+ def leave_channels(chat_channels)
207
+ chat_channels.each do |channel|
208
+ if topic_handler = topic_handler_for(channel.name)
209
+ message = MessageLib::Unsubscribe.new.set_topic(channel.name)
210
+ message_queue.tell(message,topic_handler_for(channel.name).actor)
211
+ @subscriptions.delete_if {|sub| sub == channel.name}
212
+ save_subscriptions
213
+ remove_subscriber(chat_id,channel.name)
214
+ topic_handler.tell(JavaLib::PoisonPill.get_instance)
215
+ @topic_handlers.delete(channel.name)
216
+ delete_channel_flags(channel.name)
217
+ else
218
+ GameMachine.logger.info "leave_channel: no topic handler found for #{channel.name}"
219
+ end
220
+ end
221
+ end
222
+
223
+ def send_private_message(chat_message)
224
+ GameMachine.logger.info "Sending private chat message #{chat_message.message} to #{chat_message.chat_channel.name}"
225
+ entity = MessageLib::Entity.new
226
+ player = MessageLib::Player.new.set_id(chat_message.chat_channel.name)
227
+ entity.set_id(player.id)
228
+ entity.set_player(player)
229
+ entity.set_chat_message(chat_message)
230
+ entity.set_send_to_player(true)
231
+ commands.player.send_message(entity)
232
+ end
233
+
234
+ def send_group_message(chat_message)
235
+ topic = chat_message.chat_channel.name
236
+ if topic_handler = topic_handler_for(topic)
237
+ entity = MessageLib::Entity.new.set_id('0').set_chat_message(chat_message)
238
+ publish = MessageLib::Publish.new
239
+ publish.set_topic(topic).set_message(entity)
240
+ message_queue.tell(publish,topic_handler_for(topic).actor)
241
+ else
242
+ GameMachine.logger.info "send_message: no topic handler found for #{topic}"
243
+ end
244
+ end
245
+
246
+ def send_message(chat_message)
247
+ if chat_message.type == 'group'
248
+ send_group_message(chat_message)
249
+ elsif chat_message.type == 'private'
250
+ send_private_message(chat_message)
251
+ end
252
+ end
253
+
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,108 @@
1
+ module GameMachine
2
+ module GameSystems
3
+
4
+ # @note All chat system requests go through the ChatManager
5
+ # Chat can be topic based or private player to player messages
6
+ # Topics are automatically created by the first player to send a join
7
+ # request to a topic that does not already exist.
8
+ # Chat topic channels are distributed across the cluster, and guaranteed
9
+ # to be delivered.
10
+ #
11
+ # @aspects ChatMessage Player
12
+ # @aspects JoinChat Player
13
+ # @aspects LeaveChat Player
14
+ class ChatManager < Actor::Base
15
+ include GameMachine::Commands
16
+
17
+
18
+ aspect %w(ChatMessage Player)
19
+ aspect %w(JoinChat Player)
20
+ aspect %w(LeaveChat Player)
21
+ aspect %w(ChatStatus Player)
22
+ aspect %w(ChatInvite Player)
23
+
24
+ def define_update_procs
25
+ commands.datastore.define_dbproc(:chat_remove_subscriber) do |current_entity,update_entity|
26
+ if current_entity.has_subscribers
27
+ if subscriber_id_list = current_entity.subscribers.get_subscriber_id_list.to_a
28
+ current_entity.subscribers.set_subscriber_id_list(nil)
29
+ subscriber_id_list.each do |name|
30
+ unless name == update_entity.id
31
+ current_entity.subscribers.add_subscriber_id(name)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ current_entity
37
+ end
38
+
39
+ commands.datastore.define_dbproc(:chat_add_subscriber) do |current_entity,update_entity|
40
+ unless current_entity.has_subscribers
41
+ current_entity.set_subscribers(MessageLib::Subscribers.new)
42
+ end
43
+ current_entity.subscribers.add_subscriber_id(update_entity.id)
44
+ current_entity
45
+ end
46
+ end
47
+
48
+ def post_init(*args)
49
+ @chat_actors = {}
50
+ define_update_procs
51
+ end
52
+
53
+ def on_receive(message)
54
+ if message.has_chat_invite
55
+ send_invite(message.chat_invite)
56
+ elsif message.has_chat_register
57
+ unless @chat_actors.has_key?(message.chat_register.chat_id)
58
+ create_child(message.chat_register.chat_id,message.chat_register.register_as)
59
+ end
60
+ else
61
+ unless @chat_actors.has_key?(message.player.id)
62
+ create_child(message.player.id)
63
+ end
64
+ forward_chat_request(message.player.id,message)
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ # TODO implement expiring cache store for stuff like this (invites)
71
+ # We cannot just delete the invite when everyone leaves the channel,
72
+ # because we have no way of knowing when everyone has left
73
+ def send_invite(chat_invite)
74
+ invite_id = Uniqueid.generate_token(chat_invite.inviter)
75
+ stored_id = "invite_#{chat_invite.channel_name}_#{invite_id}"
76
+ commands.datastore.put(MessageLib::Entity.new.set_id(stored_id))
77
+ chat_invite.set_invite_id(invite_id)
78
+ commands.player.send_message(chat_invite,chat_invite.invitee)
79
+ end
80
+
81
+ def destroy_child(chat_id)
82
+ if @chat_actors.has_key?(chat_id)
83
+ forward_chat_request(chat_id,JavaLib::PoisonPill.get_instance)
84
+ @chat_actors.delete(chat_id)
85
+ GameMachine.logger.debug "Chat child for #{chat_id} killed"
86
+ else
87
+ GameMachine.logger.info "chat actor for chat_id #{chat_id} not found"
88
+ end
89
+ end
90
+
91
+ def forward_chat_request(chat_id,message)
92
+ @chat_actors[chat_id].tell(message,nil)
93
+ end
94
+
95
+ def child_name(chat_id)
96
+ "chat#{chat_id}"
97
+ end
98
+
99
+ def create_child(chat_id,register_as='player')
100
+ name = child_name(chat_id)
101
+ builder = Actor::Builder.new(GameSystems::Chat,chat_id,register_as)
102
+ child = builder.with_parent(context).with_name(name).start
103
+ @chat_actors[chat_id] = Actor::Ref.new(child,GameSystems::Chat.name)
104
+ GameMachine.logger.debug "Chat child for #{chat_id} created"
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,36 @@
1
+ module GameMachine
2
+ module GameSystems
3
+ class ChatTopic < Actor::Base
4
+ include Commands
5
+
6
+ attr_reader :chat_id, :registered_as
7
+ def post_init(*args)
8
+ @chat_id = args.first
9
+ @registered_as = args.last
10
+ end
11
+
12
+ def on_receive(message)
13
+ if message.is_a?(MessageLib::Entity) && message.has_chat_message
14
+ receive_chat_message(message.chat_message)
15
+ elsif message.is_a?(JavaLib::DistributedPubSubMediator::SubscribeAck)
16
+ else
17
+ unhandled(message)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def receive_chat_message(chat_message)
24
+ GameMachine.logger.debug "Sending chat message #{chat_message.message} to #{chat_id}"
25
+ if registered_as == 'player'
26
+ commands.player.send_message(chat_message,chat_id)
27
+ else
28
+ message = MessageLib::Entity.new.set_id(chat_id).set_chat_message(chat_message)
29
+ Actor::Base.find(registered_as).tell(message,get_self)
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,13 @@
1
+ module GameMachine
2
+ module GameSystems
3
+ class Devnull < Actor::Base
4
+
5
+ def post_init(*args)
6
+ end
7
+
8
+ def on_receive(message)
9
+ GameMachine.logger.debug("Devnull got #{message}")
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module GameMachine
2
+ module GameSystems
3
+ class EntityLoader < Actor::Base
4
+
5
+ def on_receive(entity_list)
6
+ entity_list.entity.each do |entity|
7
+ ObjectDb.put(entity.id,entity)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,133 @@
1
+ module GameMachine
2
+ module GameSystems
3
+ # @note Handles player location tracking and neighbor requests.
4
+ # The client must explicitly send a TrackEntit component to the server
5
+ # to be tracked, it doesn't happen automatically.
6
+ #
7
+ # @aspects TrackEntity
8
+ # @aspects GetNeighbors
9
+ class EntityTracking < Actor::Base
10
+ include GameMachine::Commands
11
+
12
+ aspect %w(TrackEntity)
13
+ aspect %w(GetNeighbors)
14
+
15
+
16
+
17
+ EXTRA = java.util.concurrent.ConcurrentHashMap.new
18
+ attr_reader :grid, :extra_params, :aoe_grid
19
+
20
+ def post_init
21
+ if handler_klass = Application.config.entity_tracking_handler
22
+ @tracking_handler = handler_klass.constantize.new
23
+ end
24
+ @entity_updates = []
25
+ @grid = Grid.find_or_create('default')
26
+ @aoe_grid = Grid.find_or_create('aoe')
27
+ @paths = {}
28
+ @width = grid.get_width
29
+ @cell_count = grid.get_cell_count
30
+ commands.misc.client_manager_register(self.class.name)
31
+ end
32
+
33
+ def on_receive(message)
34
+ if message.is_a?(MessageLib::Entity)
35
+ if message.get_neighbors
36
+ send_neighbors(message)
37
+ end
38
+
39
+ # If a tracking handler is defined, it must return true to have
40
+ # the player location saved
41
+ if message.track_entity
42
+ #GameMachine.logger.info "#{message.player.id} tracked"
43
+ if @tracking_handler && message.entity_type == 'player'
44
+ if @tracking_handler.verify(message)
45
+ set_entity_location(message)
46
+ end
47
+ else
48
+ set_entity_location(message)
49
+ end
50
+ end
51
+ elsif message.is_a?(MessageLib::ClientManagerEvent)
52
+ if message.event == 'disconnected'
53
+ @grid.remove(message.player_id)
54
+ @aoe_grid.remove(message.player_id)
55
+ EXTRA.delete(message.player_id)
56
+ GameMachine.logger.info "#{message.player_id} removed from grid"
57
+ end
58
+ else
59
+ unhandled(message)
60
+ end
61
+ end
62
+
63
+ private
64
+
65
+ def set_entity_location(entity)
66
+ vector = entity.vector3
67
+ @grid.set(entity.id,vector.x,vector.y,vector.z,entity.entity_type)
68
+ @aoe_grid.set(entity.id,vector.x,vector.y,vector.z,entity.entity_type)
69
+ if entity.track_entity.has_track_extra
70
+ track_extra = entity.track_entity.track_extra
71
+ EXTRA[entity.id] = track_extra
72
+ end
73
+ end
74
+
75
+ def location_entity(grid_value)
76
+ entity = MessageLib::Entity.new.set_id(grid_value.id)
77
+
78
+ entity.set_vector3(
79
+ MessageLib::Vector3.new.
80
+ set_x(grid_value.x).
81
+ set_y(grid_value.y).
82
+ set_z(grid_value.z)
83
+ )
84
+
85
+ if EXTRA.has_key?(grid_value.id)
86
+ track_extra = EXTRA.fetch(grid_value.id)
87
+ entity.set_track_extra(track_extra)
88
+ end
89
+ entity
90
+ end
91
+
92
+ def send_neighbors(message)
93
+ type = message.get_neighbors.neighbor_type
94
+ x = message.get_neighbors.vector3.x
95
+ y = message.get_neighbors.vector3.y
96
+
97
+ # Either .net or java protobufs have a bug with 0 floats
98
+ if x.nil?
99
+ x = 0
100
+ end
101
+ if y.nil?
102
+ y = 0
103
+ end
104
+ search_results = grid.neighbors(x,y,type)
105
+
106
+ neighbors = search_results.map do |grid_value|
107
+ location_entity(grid_value)
108
+ end
109
+
110
+ if neighbors.empty?
111
+ return
112
+ end
113
+
114
+ if message.has_player
115
+ send_neighbors_to_player(neighbors,message.player)
116
+ end
117
+ end
118
+
119
+ def send_neighbors_to_player(neighbors,player)
120
+ neighbors.each_slice(30) do |group|
121
+ entity = MessageLib::Entity.new.set_neighbors(
122
+ MessageLib::Neighbors.new.set_entity_list(group)
123
+ )
124
+ entity.set_id(player.id)
125
+ entity.set_player(player)
126
+ entity.set_send_to_player(true)
127
+ commands.player.send_message(entity,player.id)
128
+ end
129
+ end
130
+
131
+ end
132
+ end
133
+ end