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.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +72 -0
- data/Rakefile +38 -0
- data/bin/game_machine +79 -0
- data/config/cluster.conf +65 -0
- data/config/config.example.yml +93 -0
- data/config/game_messages.proto +45 -0
- data/config/messages.proto +339 -0
- data/config/regions.example.yml +9 -0
- data/config/standalone.conf +36 -0
- data/db/do_not_delete +0 -0
- data/game_machine.gemspec +38 -0
- data/games/example/boot.rb +6 -0
- data/games/example/data/game_data.yml +13 -0
- data/games/example/lib/aggressive_npc.rb +176 -0
- data/games/example/lib/authentication_handler.rb +69 -0
- data/games/example/lib/chatbot.rb +61 -0
- data/games/example/lib/combat_controller.rb +145 -0
- data/games/example/lib/example_controller.rb +21 -0
- data/games/example/lib/game.rb +85 -0
- data/games/example/lib/models/attack.rb +9 -0
- data/games/example/lib/models/combat_update.rb +11 -0
- data/games/example/lib/models/player_command.rb +7 -0
- data/games/example/lib/models/user.rb +11 -0
- data/games/example/lib/models/vitals.rb +17 -0
- data/games/example/lib/npc.rb +111 -0
- data/games/example/lib/npc_group.rb +42 -0
- data/games/example/lib/npc_movement.rb +116 -0
- data/games/example/lib/player_manager.rb +58 -0
- data/games/example/lib/player_register.rb +80 -0
- data/games/example/lib/tracking_handler.rb +17 -0
- data/games/example/lib/zone_manager.rb +57 -0
- data/games/preload.rb +8 -0
- data/integration_tests/basic_spec.rb +68 -0
- data/integration_tests/bot_spec.rb +18 -0
- data/integration_tests/chat_spec.rb +45 -0
- data/integration_tests/distributed_spec.rb +34 -0
- data/integration_tests/entity_tracking_spec.rb +48 -0
- data/integration_tests/mono_spec.rb +16 -0
- data/integration_tests/objectdb_spec.rb +55 -0
- data/integration_tests/tcp_client_spec.rb +71 -0
- data/integration_tests/udp_client_spec.rb +61 -0
- data/integration_tests/udp_spec.rb +20 -0
- data/integration_tests/udt_client_spec.rb +23 -0
- data/integration_tests/udt_spec.rb +31 -0
- data/java/.gitignore +1 -0
- data/java/build.gradle +93 -0
- data/java/component.erb +396 -0
- data/java/gradle.properties +6 -0
- data/java/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/java/gradle/wrapper/gradle-wrapper.properties +6 -0
- data/java/gradlew +164 -0
- data/java/gradlew.bat +90 -0
- data/java/local_lib/protostuff-compiler-1.0.7-jarjar.jar +0 -0
- data/java/settings.gradle +2 -0
- data/java/src/main/java/com/game_machine/core/ActorFactory.java +25 -0
- data/java/src/main/java/com/game_machine/core/ActorUtil.java +39 -0
- data/java/src/main/java/com/game_machine/core/CommandProxy.java +9 -0
- data/java/src/main/java/com/game_machine/core/EntitySerializer.java +66 -0
- data/java/src/main/java/com/game_machine/core/EventStreamHandler.java +43 -0
- data/java/src/main/java/com/game_machine/core/GameMachineLoader.java +25 -0
- data/java/src/main/java/com/game_machine/core/Grid.java +195 -0
- data/java/src/main/java/com/game_machine/core/GridValue.java +30 -0
- data/java/src/main/java/com/game_machine/core/IActorFactory.java +7 -0
- data/java/src/main/java/com/game_machine/core/NetMessage.java +28 -0
- data/java/src/main/java/com/game_machine/core/UdpServer.java +97 -0
- data/java/src/main/java/com/game_machine/core/UdpServerHandler.java +90 -0
- data/java/src/main/resources/game_machine.java.stg +738 -0
- data/java/src/main/resources/logback.xml +14 -0
- data/java/src/main/resources/logging.properties +3 -0
- data/java/src/main/resources/protostuff.properties +7 -0
- data/lib/game_machine.rb +85 -0
- data/lib/game_machine/actor.rb +7 -0
- data/lib/game_machine/actor/base.rb +184 -0
- data/lib/game_machine/actor/builder.rb +108 -0
- data/lib/game_machine/actor/development.rb +31 -0
- data/lib/game_machine/actor/factory.rb +35 -0
- data/lib/game_machine/actor/mono_actor.rb +89 -0
- data/lib/game_machine/actor/ref.rb +81 -0
- data/lib/game_machine/actor/reloadable.rb +98 -0
- data/lib/game_machine/actor/system.rb +32 -0
- data/lib/game_machine/akka.rb +98 -0
- data/lib/game_machine/app_config.rb +49 -0
- data/lib/game_machine/application.rb +181 -0
- data/lib/game_machine/auth_handlers/base.rb +21 -0
- data/lib/game_machine/auth_handlers/public.rb +34 -0
- data/lib/game_machine/bot/chat.rb +66 -0
- data/lib/game_machine/bot/client.rb +54 -0
- data/lib/game_machine/client_manager.rb +204 -0
- data/lib/game_machine/clients.rb +4 -0
- data/lib/game_machine/clients/client.rb +45 -0
- data/lib/game_machine/clients/tcp_client.rb +25 -0
- data/lib/game_machine/clients/test_client.rb +151 -0
- data/lib/game_machine/clients/udp_client.rb +25 -0
- data/lib/game_machine/clients/udt_client.rb +34 -0
- data/lib/game_machine/cluster_monitor.rb +115 -0
- data/lib/game_machine/commands.rb +23 -0
- data/lib/game_machine/commands/base.rb +21 -0
- data/lib/game_machine/commands/chat_commands.rb +88 -0
- data/lib/game_machine/commands/datastore_commands.rb +60 -0
- data/lib/game_machine/commands/grid_commands.rb +35 -0
- data/lib/game_machine/commands/message_helper.rb +25 -0
- data/lib/game_machine/commands/misc_commands.rb +29 -0
- data/lib/game_machine/commands/navigation_commands.rb +24 -0
- data/lib/game_machine/commands/player_commands.rb +28 -0
- data/lib/game_machine/commands/proxy.rb +16 -0
- data/lib/game_machine/console.rb +3 -0
- data/lib/game_machine/console/build.rb +74 -0
- data/lib/game_machine/console/install.rb +92 -0
- data/lib/game_machine/console/server.rb +120 -0
- data/lib/game_machine/data_store.rb +52 -0
- data/lib/game_machine/data_stores/couchbase.rb +18 -0
- data/lib/game_machine/data_stores/mapdb.rb +49 -0
- data/lib/game_machine/data_stores/memory.rb +35 -0
- data/lib/game_machine/data_stores/redis.rb +46 -0
- data/lib/game_machine/endpoints.rb +6 -0
- data/lib/game_machine/endpoints/mono_gateway.rb +87 -0
- data/lib/game_machine/endpoints/tcp.rb +51 -0
- data/lib/game_machine/endpoints/tcp_handler.rb +75 -0
- data/lib/game_machine/endpoints/udp.rb +88 -0
- data/lib/game_machine/endpoints/udp_incoming.rb +113 -0
- data/lib/game_machine/endpoints/udp_outgoing.rb +46 -0
- data/lib/game_machine/game_loader.rb +46 -0
- data/lib/game_machine/game_systems.rb +14 -0
- data/lib/game_machine/game_systems/agents/controller.rb +118 -0
- data/lib/game_machine/game_systems/chat.rb +256 -0
- data/lib/game_machine/game_systems/chat_manager.rb +108 -0
- data/lib/game_machine/game_systems/chat_topic.rb +36 -0
- data/lib/game_machine/game_systems/devnull.rb +13 -0
- data/lib/game_machine/game_systems/entity_loader.rb +12 -0
- data/lib/game_machine/game_systems/entity_tracking.rb +133 -0
- data/lib/game_machine/game_systems/local_echo.rb +16 -0
- data/lib/game_machine/game_systems/objectdb_proxy.rb +61 -0
- data/lib/game_machine/game_systems/private_chat.rb +20 -0
- data/lib/game_machine/game_systems/region_manager.rb +91 -0
- data/lib/game_machine/game_systems/region_service.rb +94 -0
- data/lib/game_machine/game_systems/region_settings.rb +13 -0
- data/lib/game_machine/game_systems/remote_echo.rb +14 -0
- data/lib/game_machine/game_systems/stress_test.rb +21 -0
- data/lib/game_machine/grid.rb +60 -0
- data/lib/game_machine/grid_replicator.rb +31 -0
- data/lib/game_machine/handlers/authentication.rb +55 -0
- data/lib/game_machine/handlers/game.rb +63 -0
- data/lib/game_machine/handlers/request.rb +80 -0
- data/lib/game_machine/hashring.rb +48 -0
- data/lib/game_machine/helpers/game_message.rb +159 -0
- data/lib/game_machine/helpers/state_machine.rb +29 -0
- data/lib/game_machine/java_lib.rb +51 -0
- data/lib/game_machine/logger.rb +39 -0
- data/lib/game_machine/message_buffer.rb +58 -0
- data/lib/game_machine/message_queue.rb +63 -0
- data/lib/game_machine/model.rb +125 -0
- data/lib/game_machine/models.rb +3 -0
- data/lib/game_machine/models/player_status_update.rb +8 -0
- data/lib/game_machine/models/region.rb +9 -0
- data/lib/game_machine/mono_server.rb +20 -0
- data/lib/game_machine/navigation.rb +4 -0
- data/lib/game_machine/navigation/detour.rb +20 -0
- data/lib/game_machine/navigation/detour_navmesh.rb +53 -0
- data/lib/game_machine/navigation/detour_path.rb +53 -0
- data/lib/game_machine/navigation/path.rb +31 -0
- data/lib/game_machine/object_db.rb +67 -0
- data/lib/game_machine/protobuf.rb +6 -0
- data/lib/game_machine/protobuf/game_messages.rb +24 -0
- data/lib/game_machine/protobuf/generate.rb +113 -0
- data/lib/game_machine/protobuf_extensions/entity_helper.rb +11 -0
- data/lib/game_machine/reloadable_monitor.rb +26 -0
- data/lib/game_machine/restart_watcher.rb +17 -0
- data/lib/game_machine/ruby_extensions/nilclass.rb +10 -0
- data/lib/game_machine/ruby_extensions/string.rb +17 -0
- data/lib/game_machine/scheduler.rb +23 -0
- data/lib/game_machine/securerandom.rb +6 -0
- data/lib/game_machine/settings.rb +11 -0
- data/lib/game_machine/system_monitor.rb +19 -0
- data/lib/game_machine/system_stats.rb +24 -0
- data/lib/game_machine/uniqueid.rb +23 -0
- data/lib/game_machine/vector.rb +95 -0
- data/lib/game_machine/version.rb +3 -0
- data/lib/game_machine/write_behind_cache.rb +164 -0
- data/mono/bin/csharp/common.xslt +109 -0
- data/mono/bin/csharp/csharp.xslt +628 -0
- data/mono/bin/csharp/descriptor.proto +533 -0
- data/mono/bin/csharp/protobuf-net.dll +0 -0
- data/mono/bin/csharp/protobuf-net.pdb +0 -0
- data/mono/bin/csharp/protobuf-net.xml +2879 -0
- data/mono/bin/csharp/protogen.exe.config +3 -0
- data/mono/bin/csharp/protogen.pdb +0 -0
- data/mono/bin/csharp/protogen_csharp.exe +0 -0
- data/mono/bin/csharp/vb.xslt +745 -0
- data/mono/bin/csharp/xml.xslt +26 -0
- data/mono/server/Makefile +6 -0
- data/mono/server/NLog.config +12 -0
- data/mono/server/NLog.dll +0 -0
- data/mono/server/actor.cs +37 -0
- data/mono/server/build.bat +3 -0
- data/mono/server/cscompmgd.dll +0 -0
- data/mono/server/iactor.cs +11 -0
- data/mono/server/message_router.cs +67 -0
- data/mono/server/message_util.cs +29 -0
- data/mono/server/messages.cs +1888 -0
- data/mono/server/protobuf-net.dll +0 -0
- data/mono/server/proxy_client.cs +73 -0
- data/mono/server/proxy_server.cs +30 -0
- data/mono/server/test_actor.cs +33 -0
- data/pathfinding/bin/premake4 +0 -0
- data/pathfinding/include/mesh_loader.h +28 -0
- data/pathfinding/include/pathfind.h +167 -0
- data/pathfinding/main.cpp +39 -0
- data/pathfinding/mesh_loader.cpp +108 -0
- data/pathfinding/pathfind.cpp +174 -0
- data/pathfinding/pathfinder.cs +66 -0
- data/pathfinding/premake4.lua +109 -0
- data/script/server.sh +109 -0
- data/script/watch.sh +11 -0
- data/spec/actor/actor_spec.rb +73 -0
- data/spec/actor/builder_spec.rb +56 -0
- data/spec/actor/ref_spec.rb +83 -0
- data/spec/application_spec.rb +7 -0
- data/spec/client_manager_spec.rb +171 -0
- data/spec/commands/chat_commands_spec.rb +38 -0
- data/spec/commands/datastore_commands_spec.rb +91 -0
- data/spec/commands/grid_commands_spec.rb +37 -0
- data/spec/commands/navigation_commands_spec.rb +51 -0
- data/spec/commands/player_commands_spec.rb +48 -0
- data/spec/commands_spec.rb +38 -0
- data/spec/data_stores/mapdb_spec.rb +46 -0
- data/spec/data_stores/redis_spec.rb +44 -0
- data/spec/game_systems/agents/controller_spec.rb +84 -0
- data/spec/game_systems/agents/test_agent.rb +10 -0
- data/spec/game_systems/agents/test_agent_config.rb +29 -0
- data/spec/game_systems/chat_manager_spec.rb +66 -0
- data/spec/game_systems/chat_spec.rb +187 -0
- data/spec/game_systems/entity_tracking_spec.rb +64 -0
- data/spec/game_systems/region_manager_spec.rb +138 -0
- data/spec/grid_spec.rb +37 -0
- data/spec/handlers/authentication_spec.rb +36 -0
- data/spec/handlers/game_spec.rb +49 -0
- data/spec/handlers/request_spec.rb +65 -0
- data/spec/hashring_spec.rb +59 -0
- data/spec/integration_helper.rb +120 -0
- data/spec/java_grid_spec.rb +89 -0
- data/spec/message_buffer_spec.rb +67 -0
- data/spec/message_expectations.rb +47 -0
- data/spec/message_queue_spec.rb +23 -0
- data/spec/misc_spec.rb +71 -0
- data/spec/model_spec.rb +103 -0
- data/spec/mono_spec.rb +36 -0
- data/spec/mono_test.rb +18 -0
- data/spec/navigation/detour_navmesh_spec.rb +34 -0
- data/spec/navigation/detour_path_spec.rb +25 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/udp_server_spec.rb +10 -0
- data/spec/write_behind_cache_spec.rb +109 -0
- data/web/app.rb +131 -0
- data/web/config/trinidad.yml +4 -0
- data/web/controllers/auth_controller.rb +19 -0
- data/web/controllers/base_controller.rb +16 -0
- data/web/controllers/index_controller.rb +7 -0
- data/web/controllers/log_controller.rb +47 -0
- data/web/controllers/messages_controller.rb +59 -0
- data/web/controllers/player_register_controller.rb +15 -0
- data/web/log/development.log +1339 -0
- data/web/tmp/restart.txt +0 -0
- data/web/views/game_messages.haml +45 -0
- data/web/views/index.haml +6 -0
- data/web/views/layout.haml +41 -0
- data/web/views/logs.haml +32 -0
- data/web/views/player_register.haml +22 -0
- data/web/views/player_registered.haml +2 -0
- data/web/views/register_layout.haml +22 -0
- data/web/views/restart.haml +35 -0
- metadata +576 -0
@@ -0,0 +1,36 @@
|
|
1
|
+
|
2
|
+
standalone {
|
3
|
+
default-pinned-dispatcher {
|
4
|
+
executor = thread-pool-executor
|
5
|
+
type = PinnedDispatcher
|
6
|
+
thread-pool-executor.keep-alive-time = 315360000s
|
7
|
+
# note that disabling core timeout altogether doesn't work
|
8
|
+
# until ticket 2856 is fixed
|
9
|
+
thread-pool-executor.allow-core-timeout = off
|
10
|
+
}
|
11
|
+
|
12
|
+
akka {
|
13
|
+
actor.debug.unhandled = "on"
|
14
|
+
jvm-exit-on-fatal-error=false
|
15
|
+
loglevel = "WARNING"
|
16
|
+
|
17
|
+
actor {
|
18
|
+
serializers {
|
19
|
+
java = "akka.serialization.JavaSerializer"
|
20
|
+
bytes = "akka.serialization.ByteArraySerializer"
|
21
|
+
myown = "com.game_machine.core.EntitySerializer"
|
22
|
+
}
|
23
|
+
|
24
|
+
serialization-bindings {
|
25
|
+
"[B" = bytes
|
26
|
+
"java.io.Serializable" = java
|
27
|
+
"com.dyuproject.protostuff.Message" = myown
|
28
|
+
"GameMachine.Messages.ClientMessage" = myown
|
29
|
+
"GameMachine.Messages.Entity" = myown
|
30
|
+
"GameMachine.Messages.ObjectdbGet" = myown
|
31
|
+
"GameMachine.Messages.ObjectdbPut" = myown
|
32
|
+
"GameMachine.Messages.ObjectdbUpdate" = myown
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
data/db/do_not_delete
ADDED
File without changes
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'game_machine/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "game_machine"
|
8
|
+
gem.version = GameMachine::VERSION
|
9
|
+
gem.authors = ["Chris Ochs"]
|
10
|
+
gem.email = ["chris@ochsnet.com"]
|
11
|
+
gem.homepage = "https://github.com/gamemachine/gamemachine"
|
12
|
+
gem.summary = %q{Game Machine}
|
13
|
+
gem.description = %q{game server}
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/).reject { |f| f =~ /^(games\/physics_experiments)/ }
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features|integration_tests)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'i18n'
|
21
|
+
gem.add_dependency 'rjack-logback'
|
22
|
+
gem.add_dependency 'settingslogic'
|
23
|
+
gem.add_dependency 'consistent-hashing'
|
24
|
+
gem.add_dependency 'json'
|
25
|
+
gem.add_dependency 'ffi'
|
26
|
+
gem.add_dependency 'sinatra'
|
27
|
+
gem.add_dependency 'sinatra-contrib'
|
28
|
+
gem.add_dependency 'haml'
|
29
|
+
gem.add_dependency 'webrick'
|
30
|
+
|
31
|
+
gem.add_development_dependency 'rake'
|
32
|
+
gem.add_development_dependency 'rspec'
|
33
|
+
gem.add_development_dependency 'rspec-mocks'
|
34
|
+
gem.add_development_dependency 'rspec-expectations'
|
35
|
+
gem.add_development_dependency 'descriptive_statistics'
|
36
|
+
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'benchmark'
|
2
|
+
module Example
|
3
|
+
class AggressiveNpc < Npc
|
4
|
+
include GameMachine::Commands
|
5
|
+
include Models
|
6
|
+
|
7
|
+
attr_reader :target_id
|
8
|
+
|
9
|
+
def post_init
|
10
|
+
@target_id = nil
|
11
|
+
@check_home_counter = 0
|
12
|
+
@check_home_interval = 5
|
13
|
+
@acquire_target_counter = 0
|
14
|
+
@acquire_target_interval = 5
|
15
|
+
@agro_radius = 15
|
16
|
+
@leash_radius = 30
|
17
|
+
|
18
|
+
movement.speed_scale = 4
|
19
|
+
@last_attack = Time.now.to_i
|
20
|
+
@attack_interval = 2
|
21
|
+
end
|
22
|
+
|
23
|
+
def log(msg)
|
24
|
+
GameMachine.logger.info "#{id} #{msg}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def set_spawn_point
|
28
|
+
position.x = rand(1000) + 1
|
29
|
+
position.y = rand(1000) + 1
|
30
|
+
#position.z = 40
|
31
|
+
end
|
32
|
+
|
33
|
+
def has_target?
|
34
|
+
target_id.nil? ? false : true
|
35
|
+
end
|
36
|
+
|
37
|
+
def update_target
|
38
|
+
if target = players.fetch(target_id,nil)
|
39
|
+
movement.update_target(target[:vector])
|
40
|
+
true
|
41
|
+
else
|
42
|
+
@target_id = nil
|
43
|
+
false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def choose_target
|
48
|
+
if player = sorted_players.first
|
49
|
+
if position.distance(player[:vector]) <= @agro_radius
|
50
|
+
movement.set_target(player[:vector])
|
51
|
+
@target_id = player[:id]
|
52
|
+
#log("target chosen #{@target_id}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def leash?
|
58
|
+
if @check_home_counter >= @check_home_interval
|
59
|
+
@check_home_counter = 0
|
60
|
+
if movement.position.distance(home) > @leash_radius
|
61
|
+
return true
|
62
|
+
elsif movement.current_target &&
|
63
|
+
(movement.position.distance(movement.current_target) > @leash_radius)
|
64
|
+
return true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
false
|
68
|
+
end
|
69
|
+
|
70
|
+
def go_home!
|
71
|
+
log("going home")
|
72
|
+
@target_id = 'home'
|
73
|
+
movement.set_target(@home)
|
74
|
+
end
|
75
|
+
|
76
|
+
def going_home?
|
77
|
+
@target_id == 'home'
|
78
|
+
end
|
79
|
+
|
80
|
+
def reached_home?
|
81
|
+
going_home? && movement.reached_target
|
82
|
+
end
|
83
|
+
|
84
|
+
def reset_target
|
85
|
+
movement.drop_target
|
86
|
+
@target_id = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
def attack_target
|
90
|
+
if Time.now.to_i - @last_attack < @attack_interval
|
91
|
+
return
|
92
|
+
end
|
93
|
+
|
94
|
+
attack = Attack.new(
|
95
|
+
:target => target_id,
|
96
|
+
:attacker => id,
|
97
|
+
:combat_ability => 'bite'
|
98
|
+
)
|
99
|
+
CombatController.find.tell(attack)
|
100
|
+
#log("attacked target #{target_id}")
|
101
|
+
@last_attack = Time.now.to_i
|
102
|
+
end
|
103
|
+
|
104
|
+
def update
|
105
|
+
return if dead
|
106
|
+
if going_home?
|
107
|
+
if reached_home?
|
108
|
+
log("home reached")
|
109
|
+
reset_target
|
110
|
+
else
|
111
|
+
movement.update_target(home)
|
112
|
+
movement.update
|
113
|
+
end
|
114
|
+
return
|
115
|
+
end
|
116
|
+
|
117
|
+
if leash?
|
118
|
+
log("leashed!")
|
119
|
+
reset_target
|
120
|
+
go_home!
|
121
|
+
return
|
122
|
+
end
|
123
|
+
|
124
|
+
# if we have a target, acquire their location every tick, otherwise only
|
125
|
+
# check every acquire_target_interval updates
|
126
|
+
if has_target? || @acquire_target_counter >= @acquire_target_interval
|
127
|
+
movement.updates_between_move = 1
|
128
|
+
check_players
|
129
|
+
if has_players?
|
130
|
+
unless has_target?
|
131
|
+
choose_target
|
132
|
+
end
|
133
|
+
else
|
134
|
+
# No players but we have a player target? Player must have logged out
|
135
|
+
# or otherwise disappeared, so we need to reset
|
136
|
+
if @target_id && @target_id != 'home'
|
137
|
+
GameMachine.logger.info "#{id} No players but has target!?? (target: #{@target_id})"
|
138
|
+
reset_target
|
139
|
+
go_home!
|
140
|
+
elsif movement.position.distance(home) > 0
|
141
|
+
GameMachine.logger.info "#{id} No players but is #{position.distance(home)} from home (target: #{@target_id})"
|
142
|
+
reset_target
|
143
|
+
go_home!
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
@acquire_target_counter = 0
|
148
|
+
else
|
149
|
+
movement.updates_between_move = 20
|
150
|
+
end
|
151
|
+
|
152
|
+
if has_target?
|
153
|
+
if movement.distance_to_target <= 3
|
154
|
+
attack_target
|
155
|
+
end
|
156
|
+
|
157
|
+
if movement.reached_target
|
158
|
+
reset_target
|
159
|
+
else
|
160
|
+
if update_target
|
161
|
+
movement.update
|
162
|
+
else
|
163
|
+
# Target out of range for some reason (logged out, etc..)
|
164
|
+
GameMachine.logger.info "#{id} lost target! #{@target_id}"
|
165
|
+
reset_target
|
166
|
+
go_home!
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
@acquire_target_counter += 1
|
172
|
+
@check_home_counter += 1
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
# This class is set in the configuration.
|
3
|
+
|
4
|
+
# This is a simple implementation that works together with the built in
|
5
|
+
# user registration and login via http. User data is stored in the object database.
|
6
|
+
|
7
|
+
# The minimum necessary to implement is the authtoken_for method. That method can
|
8
|
+
# block as it is only called once when the client first connects and is cached
|
9
|
+
# internally after that. So you could make an external http call for example.
|
10
|
+
require 'digest/md5'
|
11
|
+
module Example
|
12
|
+
class AuthenticationHandler
|
13
|
+
include Models
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@sessions = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns true is authorized, false if not
|
20
|
+
def authorize(username,password)
|
21
|
+
GameMachine.logger.info "authorize: #{username} #{password}"
|
22
|
+
if user = User.find(username,5000)
|
23
|
+
GameMachine.logger.info "user: #{user.id} #{user.password}"
|
24
|
+
if password == user.password
|
25
|
+
@sessions[username] = authtoken(username,password)
|
26
|
+
user.authtoken = @sessions[username]
|
27
|
+
user.save
|
28
|
+
return @sessions[username]
|
29
|
+
else
|
30
|
+
GameMachine.logger.info "user: #{user.id} password does not match"
|
31
|
+
false
|
32
|
+
end
|
33
|
+
else
|
34
|
+
GameMachine.logger.info "user: #{username} not found"
|
35
|
+
false
|
36
|
+
end
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a session token for a logged in user. This must be a string and
|
41
|
+
# should not be too long, as it gets sent with every message.
|
42
|
+
def authtoken_for(username)
|
43
|
+
if authtoken = @sessions.fetch(username,nil)
|
44
|
+
return authtoken
|
45
|
+
|
46
|
+
# user authenticated on different server, we have to look up their authtoken
|
47
|
+
# and save it in the local sessions hash
|
48
|
+
elsif user = User.find(username)
|
49
|
+
if user.authtoken
|
50
|
+
@sessions[username] = authtoken
|
51
|
+
return user.authtoken
|
52
|
+
else
|
53
|
+
GameMachine.logger.info "Authoken for #{username} is nil"
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
else
|
57
|
+
GameMachine.logger.info "User #{username} not found"
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def authtoken(username,password)
|
65
|
+
Digest::MD5.hexdigest("#{username}#{password}#{rand(10000)}")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
|
2
|
+
# Shows how to use the messaging/chat system programmatically from the server.
|
3
|
+
# Also shows how to use the schedular to send ourselves a recurring message that
|
4
|
+
# we can use to trigger recurring actions.
|
5
|
+
|
6
|
+
module Example
|
7
|
+
class Chatbot < GameMachine::Actor::Base
|
8
|
+
include GameMachine
|
9
|
+
include GameMachine::Commands
|
10
|
+
|
11
|
+
attr_reader :topic, :chatbot_id
|
12
|
+
def post_init(*args)
|
13
|
+
@topic = args.first
|
14
|
+
@chatbot_id = 'overlord'
|
15
|
+
|
16
|
+
# On the server side we use register, which takes our chat id
|
17
|
+
# and the name of this actor.
|
18
|
+
commands.chat.register(chatbot_id,'Example::Chatbot')
|
19
|
+
|
20
|
+
# Then we send a regular join request
|
21
|
+
commands.chat.join('global',chatbot_id)
|
22
|
+
|
23
|
+
# Send ourselves a 'doit' message every few seconds
|
24
|
+
schedule_message('doit',50,:seconds)
|
25
|
+
end
|
26
|
+
|
27
|
+
def message_queue
|
28
|
+
MessageQueue.find
|
29
|
+
end
|
30
|
+
|
31
|
+
def on_receive(message)
|
32
|
+
|
33
|
+
# This is our scheduled message
|
34
|
+
if message.is_a?(String)
|
35
|
+
if message == 'doit'
|
36
|
+
commands.chat.send_group_message('global','Would you like to play a game?',chatbot_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Status update we get from chat system, we don't care..
|
40
|
+
elsif message.has_chat_channels
|
41
|
+
|
42
|
+
# Must be a chat message
|
43
|
+
elsif message.has_chat_message
|
44
|
+
|
45
|
+
# ignore our own messages
|
46
|
+
sender_id = message.chat_message.sender_id
|
47
|
+
unless sender_id == chatbot_id
|
48
|
+
text = message.chat_message.message
|
49
|
+
GameMachine.logger.info "Chatbot received text #{text}"
|
50
|
+
|
51
|
+
# Respond with a private message
|
52
|
+
if text.match(/shut up/)
|
53
|
+
reply = 'Same to you!'
|
54
|
+
commands.chat.send_private_message(reply,sender_id)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
|
2
|
+
# Handles all the combat. Npc controllers and clients send Attack messages
|
3
|
+
# to this actor which calculates damage, persists any changes, and sends out
|
4
|
+
# combat updates to all players in the area as well as to any npc's that were
|
5
|
+
# hit.
|
6
|
+
|
7
|
+
# If the attack combat_ability is 'aoe', we use the aoe grid which is a
|
8
|
+
# secondary grid with a smaller radius. Currently we use the attacker as the
|
9
|
+
# point to query on, but it could be easily extended to use any point, so you
|
10
|
+
# could have aoe damage with a center anywhere you want it to be.
|
11
|
+
|
12
|
+
|
13
|
+
module Example
|
14
|
+
class CombatController < GameMachine::Actor::Base
|
15
|
+
include GameMachine::Commands
|
16
|
+
include Models
|
17
|
+
|
18
|
+
attr_reader :aoe_grid
|
19
|
+
def post_init(*args)
|
20
|
+
@aoe_grid = GameMachine::Grid.find_or_create('aoe')
|
21
|
+
end
|
22
|
+
|
23
|
+
def hit?
|
24
|
+
return true
|
25
|
+
chance = rand(0..10)
|
26
|
+
chance >= 5 ? true : false
|
27
|
+
end
|
28
|
+
|
29
|
+
def damage(entity_type)
|
30
|
+
if entity_type == 'player'
|
31
|
+
rand(1..8)
|
32
|
+
else
|
33
|
+
rand(20..120)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_receive(message)
|
38
|
+
if message.is_a?(Attack)
|
39
|
+
attack = message
|
40
|
+
attacker_vitals = Vitals.find(attack.attacker)
|
41
|
+
|
42
|
+
if attacker_vitals.entity_type == 'player'
|
43
|
+
player_id = attack.attacker
|
44
|
+
else
|
45
|
+
player_id = attack.target
|
46
|
+
end
|
47
|
+
|
48
|
+
# gets our targets. Does range query if aoe
|
49
|
+
targets = find_targets(attack,attacker_vitals)
|
50
|
+
#GameMachine.logger.info "targets #{targets.map{|target| target.id}.join(',')}"
|
51
|
+
|
52
|
+
# calculates/applies damage and returns a combat update for each hit
|
53
|
+
combat_updates = attack_targets(targets,attack)
|
54
|
+
|
55
|
+
# Get all players within our larger radius so we can send them the updates
|
56
|
+
neighbors = commands.grid.get_neighbors_for(attack.attacker)
|
57
|
+
|
58
|
+
combat_updates.each do |combat_update|
|
59
|
+
GameMachine.logger.info "#{combat_update.attacker} hit #{combat_update.target} for #{combat_update.damage} #{attack.combat_ability} damage"
|
60
|
+
commands.player.send_message(combat_update,player_id)
|
61
|
+
|
62
|
+
if neighbors
|
63
|
+
neighbors.each do |neighbor|
|
64
|
+
next if neighbor.id == player_id
|
65
|
+
commands.player.send_message(combat_update,neighbor.id)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def attack_targets(targets,attack)
|
74
|
+
combat_updates = []
|
75
|
+
|
76
|
+
targets.each do |target_vitals|
|
77
|
+
|
78
|
+
if target_vitals.entity_type.blank?
|
79
|
+
target_vitals.entity_type = 'npc'
|
80
|
+
GameMachine.logger.info "#{target_vitals.id} has no entity type, fixing"
|
81
|
+
end
|
82
|
+
if hit?
|
83
|
+
dmg = damage(target_vitals.entity_type)
|
84
|
+
next if dmg == 0
|
85
|
+
if target_vitals.health - dmg <= 0
|
86
|
+
target_vitals.health = 0
|
87
|
+
else
|
88
|
+
target_vitals.health -= dmg
|
89
|
+
end
|
90
|
+
target_vitals.save
|
91
|
+
#GameMachine.logger.info "#{target_vitals.id}(#{target_vitals.entity_type}) has #{target_vitals.health}"
|
92
|
+
|
93
|
+
combat_update = CombatUpdate.new(
|
94
|
+
:target => target_vitals.id,
|
95
|
+
:attacker => attack.attacker,
|
96
|
+
:damage => dmg,
|
97
|
+
:target_health => target_vitals.health
|
98
|
+
)
|
99
|
+
combat_updates << combat_update
|
100
|
+
|
101
|
+
if target_vitals.entity_type == 'npc'
|
102
|
+
if npc_group_actor = Game.npcs.fetch(target_vitals.id,nil)
|
103
|
+
GameMachine::Actor::Base.find(npc_group_actor).tell(combat_update)
|
104
|
+
else
|
105
|
+
GameMachine.logger.info "group actor for #{target_vitals.id} not found"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
111
|
+
combat_updates
|
112
|
+
end
|
113
|
+
|
114
|
+
# If it's an aoe attack, use our aoe grid to find targets in range, otherwise
|
115
|
+
# use the specified target
|
116
|
+
def find_targets(attack,attacker)
|
117
|
+
targets = []
|
118
|
+
|
119
|
+
# npc's only hit players, players hit everything
|
120
|
+
if attacker.entity_type == 'npc'
|
121
|
+
search_type = 'player'
|
122
|
+
else
|
123
|
+
search_type = nil
|
124
|
+
end
|
125
|
+
|
126
|
+
if attack.combat_ability == 'aoe'
|
127
|
+
if grid_value = @aoe_grid.get(attack.attacker)
|
128
|
+
@aoe_grid.neighbors(grid_value.x,grid_value.y,search_type).each do |grid_value|
|
129
|
+
next if grid_value.id == attack.attacker
|
130
|
+
if target_vitals = Vitals.find(grid_value.id)
|
131
|
+
targets << target_vitals
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
else
|
136
|
+
if target_vitals = Vitals.find(attack.target)
|
137
|
+
targets << target_vitals
|
138
|
+
end
|
139
|
+
end
|
140
|
+
targets
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|