game_machine 0.0.8

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 (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