game_machine 0.0.11 → 1.0.2
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 +4 -4
- data/Gemfile +12 -1
- data/Gemfile.lock +32 -47
- data/Rakefile +0 -27
- data/bin/bundle_run.sh +1 -0
- data/bin/game_machine +29 -27
- data/config/cluster.conf +6 -5
- data/config/default.conf +164 -0
- data/config/game_machine.sql +33 -0
- data/config/game_messages.proto +87 -25
- data/config/gamecloud.conf +140 -0
- data/config/messages.proto +46 -53
- data/config/test.conf +149 -0
- data/game_machine.gemspec +10 -5
- data/games/boot.rb +3 -0
- data/games/example/data/game_data.yml +4 -4
- data/games/example/lib/aggressive_npc.rb +1 -1
- data/games/example/lib/game.rb +1 -2
- data/games/example/lib/player_register.rb +1 -1
- data/games/routes.rb +9 -0
- data/games/tutorial/boot.rb +12 -0
- data/games/tutorial/item_manager.rb +256 -0
- data/games/tutorial/object_store.rb +55 -0
- data/games/tutorial/seed.rb +52 -0
- data/games/tutorial/sql_store.rb +30 -0
- data/java/project/build.gradle +134 -0
- data/java/project/component.erb +719 -0
- data/java/{gradle.properties → project/gradle.properties} +1 -1
- data/java/project/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/java/{gradle → project/gradle}/wrapper/gradle-wrapper.properties +2 -2
- data/java/{gradlew → project/gradlew} +0 -0
- data/java/{gradlew.bat → project/gradlew.bat} +0 -0
- data/java/project/local_lib/AdminUi.jar +0 -0
- data/java/{local_lib/protostuff-compiler-1.0.7-jarjar.jar → project/local_lib/protostuff-compiler-1.0.8-jarjar.jar} +0 -0
- data/java/project/local_lib/sigar/libsigar-amd64-freebsd-6.so +0 -0
- data/java/project/local_lib/sigar/libsigar-amd64-linux.so +0 -0
- data/java/project/local_lib/sigar/libsigar-amd64-solaris.so +0 -0
- data/java/project/local_lib/sigar/libsigar-ia64-hpux-11.sl +0 -0
- data/java/project/local_lib/sigar/libsigar-ia64-linux.so +0 -0
- data/java/project/local_lib/sigar/libsigar-pa-hpux-11.sl +0 -0
- data/java/project/local_lib/sigar/libsigar-ppc-aix-5.so +0 -0
- data/java/project/local_lib/sigar/libsigar-ppc-linux.so +0 -0
- data/java/project/local_lib/sigar/libsigar-ppc64-aix-5.so +0 -0
- data/java/project/local_lib/sigar/libsigar-ppc64-linux.so +0 -0
- data/java/project/local_lib/sigar/libsigar-s390x-linux.so +0 -0
- data/java/project/local_lib/sigar/libsigar-sparc-solaris.so +0 -0
- data/java/project/local_lib/sigar/libsigar-sparc64-solaris.so +0 -0
- data/java/project/local_lib/sigar/libsigar-universal-macosx.dylib +0 -0
- data/java/project/local_lib/sigar/libsigar-universal64-macosx.dylib +0 -0
- data/java/project/local_lib/sigar/libsigar-x86-freebsd-5.so +0 -0
- data/java/project/local_lib/sigar/libsigar-x86-freebsd-6.so +0 -0
- data/java/project/local_lib/sigar/libsigar-x86-linux.so +0 -0
- data/java/project/local_lib/sigar/libsigar-x86-solaris.so +0 -0
- data/java/project/local_lib/sigar/sigar-amd64-winnt.dll +0 -0
- data/java/project/local_lib/sigar/sigar-x86-winnt.dll +0 -0
- data/java/project/local_lib/sigar/sigar-x86-winnt.lib +0 -0
- data/java/project/model.erb +99 -0
- data/java/{settings.gradle → project/settings.gradle} +0 -0
- data/java/project/src/main/java/com/game_machine/authentication/DefaultAuthenticator.java +28 -0
- data/java/project/src/main/java/com/game_machine/authentication/PlayerAuthenticator.java +6 -0
- data/java/project/src/main/java/com/game_machine/authentication/PublicAuthenticator.java +20 -0
- data/java/{src → project/src}/main/java/com/game_machine/core/ActorFactory.java +0 -0
- data/java/{src → project/src}/main/java/com/game_machine/core/ActorUtil.java +13 -0
- data/java/project/src/main/java/com/game_machine/core/AuthorizedPlayers.java +23 -0
- data/java/project/src/main/java/com/game_machine/core/ClientMessageDecoder.java +36 -0
- data/java/project/src/main/java/com/game_machine/core/ClientMessageEncoder.java +19 -0
- data/java/project/src/main/java/com/game_machine/core/CloudClient.java +298 -0
- data/java/{src → project/src}/main/java/com/game_machine/core/CommandProxy.java +0 -0
- data/java/project/src/main/java/com/game_machine/core/Commands.java +20 -0
- data/java/project/src/main/java/com/game_machine/core/DatastoreCommands.java +43 -0
- data/java/project/src/main/java/com/game_machine/core/DbConnectionPool.java +72 -0
- data/java/project/src/main/java/com/game_machine/core/DefaultMovementVerifier.java +56 -0
- data/java/{src → project/src}/main/java/com/game_machine/core/EntitySerializer.java +0 -0
- data/java/project/src/main/java/com/game_machine/core/EntityTracking.java +119 -0
- data/java/{src → project/src}/main/java/com/game_machine/core/EventStreamHandler.java +1 -1
- data/java/project/src/main/java/com/game_machine/core/GameActor.java +73 -0
- data/java/project/src/main/java/com/game_machine/core/GameMachineLoader.java +43 -0
- data/java/project/src/main/java/com/game_machine/core/GameMessageActor.java +44 -0
- data/java/project/src/main/java/com/game_machine/core/Grid.java +255 -0
- data/java/{src → project/src}/main/java/com/game_machine/core/GridValue.java +0 -0
- data/java/project/src/main/java/com/game_machine/core/Hashring.java +66 -0
- data/java/{src → project/src}/main/java/com/game_machine/core/IActorFactory.java +0 -0
- data/java/project/src/main/java/com/game_machine/core/LocalLinkedBuffer.java +20 -0
- data/java/project/src/main/java/com/game_machine/core/MessageGateway.java +120 -0
- data/java/project/src/main/java/com/game_machine/core/MessagePersister.java +26 -0
- data/java/project/src/main/java/com/game_machine/core/MonoProxy.java +39 -0
- data/java/project/src/main/java/com/game_machine/core/MovementVerifier.java +7 -0
- data/java/{src → project/src}/main/java/com/game_machine/core/NetMessage.java +10 -6
- data/java/project/src/main/java/com/game_machine/core/PersistentMessage.java +9 -0
- data/java/project/src/main/java/com/game_machine/core/PlayerCommands.java +31 -0
- data/java/project/src/main/java/com/game_machine/core/TcpServer.java +100 -0
- data/java/project/src/main/java/com/game_machine/core/TcpServerHandler.java +54 -0
- data/java/project/src/main/java/com/game_machine/core/TcpServerInitializer.java +32 -0
- data/java/project/src/main/java/com/game_machine/core/UdpClient.java +86 -0
- data/java/{src → project/src}/main/java/com/game_machine/core/UdpServer.java +18 -27
- data/java/{src → project/src}/main/java/com/game_machine/core/UdpServerHandler.java +23 -26
- data/java/project/src/main/java/com/game_machine/core/Vector3.java +159 -0
- data/java/project/src/main/java/com/game_machine/orm/models/PlayerItem.java +118 -0
- data/java/project/src/main/java/com/game_machine/orm/models/TestObject.java +110 -0
- data/java/project/src/main/java/com/game_machine/tutorial/LootGenerator.java +26 -0
- data/java/{src → project/src}/main/resources/game_machine.java.stg +3 -1
- data/java/project/src/main/resources/logback.properties +13 -0
- data/java/project/src/main/resources/logback.xml +76 -0
- data/java/{src → project/src}/main/resources/protostuff.properties +0 -0
- data/java/src/main/java/game/MyGameActor.java +26 -0
- data/lib/game_machine.rb +17 -16
- data/lib/game_machine/actor.rb +1 -1
- data/lib/game_machine/actor/base.rb +8 -31
- data/lib/game_machine/actor/builder.rb +5 -6
- data/lib/game_machine/actor/game_actor.rb +55 -0
- data/lib/game_machine/actor/reloadable.rb +6 -1
- data/lib/game_machine/akka.rb +26 -32
- data/lib/game_machine/app_config.rb +39 -26
- data/lib/game_machine/application.rb +56 -62
- data/lib/game_machine/client_manager.rb +14 -8
- data/lib/game_machine/cloud_updater.rb +51 -0
- data/lib/game_machine/cluster_monitor.rb +3 -3
- data/lib/game_machine/commands.rb +1 -1
- data/lib/game_machine/commands/misc_commands.rb +4 -8
- data/lib/game_machine/commands/player_commands.rb +8 -0
- data/lib/game_machine/console.rb +1 -0
- data/lib/game_machine/console/build.rb +57 -24
- data/lib/game_machine/console/bundle.rb +95 -0
- data/lib/game_machine/console/deploy.rb +30 -0
- data/lib/game_machine/console/install.rb +70 -36
- data/lib/game_machine/console/server.rb +2 -69
- data/lib/game_machine/data_store.rb +111 -15
- data/lib/game_machine/data_stores/couchbase.rb +8 -3
- data/lib/game_machine/data_stores/gamecloud.rb +93 -0
- data/lib/game_machine/data_stores/jdbc.rb +98 -0
- data/lib/game_machine/default_handlers.rb +2 -0
- data/lib/game_machine/default_handlers/team_handler.rb +51 -0
- data/lib/game_machine/default_handlers/zone_manager.rb +30 -0
- data/lib/game_machine/endpoints.rb +0 -4
- data/lib/game_machine/endpoints/udp_incoming.rb +13 -5
- data/lib/game_machine/endpoints/udp_outgoing.rb +15 -9
- data/lib/game_machine/game_systems.rb +0 -2
- data/lib/game_machine/game_systems/agents/controller.rb +2 -2
- data/lib/game_machine/game_systems/entity_tracking.rb +0 -3
- data/lib/game_machine/game_systems/region_manager.rb +3 -2
- data/lib/game_machine/game_systems/region_service.rb +2 -2
- data/lib/game_machine/game_systems/remote_echo.rb +10 -0
- data/lib/game_machine/game_systems/team_manager.rb +2 -11
- data/lib/game_machine/grid.rb +5 -18
- data/lib/game_machine/handlers/authentication.rb +1 -9
- data/lib/game_machine/handlers/game.rb +27 -2
- data/lib/game_machine/handlers/player_authentication.rb +87 -0
- data/lib/game_machine/handlers/request.rb +9 -11
- data/lib/game_machine/hocon_config.rb +81 -0
- data/lib/game_machine/java_lib.rb +14 -1
- data/lib/game_machine/logger.rb +10 -23
- data/lib/game_machine/models.rb +1 -0
- data/lib/game_machine/mono_server.rb +6 -1
- data/lib/game_machine/object_db.rb +12 -6
- data/lib/game_machine/protobuf.rb +1 -1
- data/lib/game_machine/protobuf/game_messages.rb +13 -3
- data/lib/game_machine/protobuf/generate.rb +107 -5
- data/lib/game_machine/restart_watcher.rb +1 -1
- data/lib/game_machine/routes.rb +23 -0
- data/lib/game_machine/scheduler.rb +1 -1
- data/lib/game_machine/securerandom.rb +2 -0
- data/lib/game_machine/system_stats.rb +28 -7
- data/lib/game_machine/version.rb +1 -1
- data/lib/game_machine/wavefront_ext.rb +47 -0
- data/lib/game_machine/write_behind_cache.rb +24 -9
- data/mono/server/Makefile +1 -1
- data/mono/server/Newtonsoft.Json.dll +0 -0
- data/mono/server/build.bat +1 -1
- data/mono/server/callable.cs +9 -0
- data/mono/server/echo.cs +17 -0
- data/mono/server/message_router.cs +16 -23
- data/mono/server/messages.cs +1792 -417
- data/mono/server/protobuf-net.dll +0 -0
- data/mono/server/server.cs +120 -0
- data/mono/server/server.exe +0 -0
- data/pathfinding/astar.cpp +149 -0
- data/pathfinding/build.sh +6 -0
- data/pathfinding/build.txt +16 -0
- data/pathfinding/crowd.cpp +194 -0
- data/pathfinding/include/astar.h +49 -0
- data/pathfinding/include/common.h +5 -0
- data/pathfinding/include/crowd.h +43 -0
- data/pathfinding/include/micropather.h +511 -0
- data/pathfinding/include/navmesh.h +114 -0
- data/pathfinding/include/pathfinder.h +24 -0
- data/pathfinding/main.cpp +108 -17
- data/pathfinding/micropather.cpp +1062 -0
- data/pathfinding/navmesh.cpp +408 -0
- data/pathfinding/overrides/DetourCrowd.cpp +1446 -0
- data/pathfinding/overrides/DetourNavMeshQuery.cpp +3551 -0
- data/pathfinding/overrides/DetourNavMeshQuery.h +538 -0
- data/pathfinding/pathfinder.cpp +117 -0
- data/pathfinding/{bin → premake}/premake4 +0 -0
- data/pathfinding/premake/premake4.exe +0 -0
- data/pathfinding/premake4.lua +12 -3
- data/spec/actor/actor_spec.rb +0 -7
- data/spec/client_manager_spec.rb +1 -1
- data/spec/couchproxy_spec.rb +38 -0
- data/spec/entity_persistence_spec.rb +129 -0
- data/spec/game_systems/team_manager_spec.rb +2 -2
- data/spec/hashring_spec.rb +17 -39
- data/spec/java_grid_spec.rb +0 -2
- data/spec/misc_spec.rb +111 -0
- data/spec/mono_spec.rb +50 -3
- data/spec/reliable_message_spec.rb +38 -0
- data/spec/spec_helper.rb +4 -4
- data/spec/spec_helper_minimal.rb +10 -0
- data/web/app.rb +108 -86
- data/web/config/trinidad.yml +1 -0
- data/web/views/add_player.erb +25 -0
- data/web/views/index.erb +0 -0
- data/web/views/layout.erb +48 -0
- data/web/views/login.erb +25 -0
- data/web/views/players.erb +24 -0
- metadata +209 -94
- data/config/config.example.yml +0 -100
- data/config/regions.example.yml +0 -9
- data/games/example/lib/authentication_handler.rb +0 -69
- data/games/models.rb +0 -3
- data/games/models/clan_member.rb +0 -8
- data/games/models/clan_profile.rb +0 -9
- data/games/models/player.rb +0 -7
- data/games/plugins.rb +0 -1
- data/games/plugins/team_handler.rb +0 -49
- data/games/preload.rb +0 -13
- data/java/.gitignore +0 -1
- data/java/build.gradle +0 -95
- data/java/component.erb +0 -396
- data/java/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/java/src/main/java/com/game_machine/core/GameMachineLoader.java +0 -25
- data/java/src/main/java/com/game_machine/core/Grid.java +0 -195
- data/java/src/main/resources/logback.xml +0 -14
- data/java/src/main/resources/logging.properties +0 -3
- data/lib/game_machine/actor/mono_actor.rb +0 -89
- data/lib/game_machine/auth_handlers/base.rb +0 -21
- data/lib/game_machine/auth_handlers/public.rb +0 -34
- data/lib/game_machine/endpoints/mono_gateway.rb +0 -87
- data/lib/game_machine/endpoints/tcp.rb +0 -51
- data/lib/game_machine/endpoints/tcp_handler.rb +0 -75
- data/lib/game_machine/endpoints/udp.rb +0 -88
- data/lib/game_machine/game_loader.rb +0 -46
- data/lib/game_machine/game_systems/region_settings.rb +0 -13
- data/lib/game_machine/hashring.rb +0 -48
- data/lib/game_machine/settings.rb +0 -11
- data/mono/server/actor.cs +0 -37
- data/mono/server/iactor.cs +0 -11
- data/mono/server/message_util.cs +0 -29
- data/mono/server/proxy_client.cs +0 -73
- data/mono/server/proxy_server.cs +0 -30
- data/mono/server/test_actor.cs +0 -33
- data/pathfinding/include/pathfind.h +0 -167
- data/pathfinding/pathfind.cpp +0 -174
- data/pathfinding/pathfinder.cs +0 -66
- data/script/server.sh +0 -109
- data/script/watch.sh +0 -11
- data/spec/commands/navigation_commands_spec.rb +0 -51
- data/spec/game_systems/entity_tracking_spec.rb +0 -64
- data/spec/navigation/detour_navmesh_spec.rb +0 -34
- data/spec/navigation/detour_path_spec.rb +0 -25
- data/spec/udp_server_spec.rb +0 -10
- data/web/controllers/auth_controller.rb +0 -19
- data/web/controllers/base_controller.rb +0 -16
- data/web/controllers/index_controller.rb +0 -7
- data/web/controllers/log_controller.rb +0 -47
- data/web/controllers/messages_controller.rb +0 -59
- data/web/controllers/player_register_controller.rb +0 -15
- data/web/views/game_messages.haml +0 -45
- data/web/views/index.haml +0 -6
- data/web/views/layout.haml +0 -41
- data/web/views/logs.haml +0 -32
- data/web/views/player_register.haml +0 -22
- data/web/views/player_registered.haml +0 -2
- data/web/views/register_layout.haml +0 -22
- data/web/views/restart.haml +0 -35
data/config/test.conf
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
|
|
2
|
+
gamemachine {
|
|
3
|
+
|
|
4
|
+
environment = test
|
|
5
|
+
use_regions = true
|
|
6
|
+
orm = false
|
|
7
|
+
mono_enabled = false
|
|
8
|
+
|
|
9
|
+
client {
|
|
10
|
+
|
|
11
|
+
# Sets the protocol and host/port used by the client if set to TCP or UDP. ANY lets the client use it's own values
|
|
12
|
+
protocol = ANY
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
handlers {
|
|
16
|
+
|
|
17
|
+
# Team handler
|
|
18
|
+
team = "GameMachine::DefaultHandlers::TeamHandler"
|
|
19
|
+
|
|
20
|
+
# Authentication handlers.
|
|
21
|
+
|
|
22
|
+
#PublicAuthenticator allows any user/password combination to work
|
|
23
|
+
auth = "com.game_machine.authentication.PublicAuthenticator"
|
|
24
|
+
|
|
25
|
+
# The default. Uses salted password hash (bcrypt)
|
|
26
|
+
#auth = "com.game_machine.authentication.DefaultAuthenticator"
|
|
27
|
+
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
routers {
|
|
31
|
+
# Size of the router for incoming message from all clients
|
|
32
|
+
game_handler = 5
|
|
33
|
+
|
|
34
|
+
# Also in the pipeline for all incoming requests, should be set the same as
|
|
35
|
+
# game_handler_routers
|
|
36
|
+
request_handler = 5
|
|
37
|
+
|
|
38
|
+
# router size for the udp actor that handles all incoming upd messages
|
|
39
|
+
udp = 5
|
|
40
|
+
|
|
41
|
+
objectdb = 5
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
datastore {
|
|
45
|
+
# What data store the object database will use (one of memory, mapdb, or couchbase)
|
|
46
|
+
store = gamecloud
|
|
47
|
+
|
|
48
|
+
serialization = json
|
|
49
|
+
|
|
50
|
+
# minimum time in milliseconds between writes to the backing store of the same key. When a message
|
|
51
|
+
# exceeds the limit it is either enqueued, or if already enqueued, it's value is updated, it's
|
|
52
|
+
# value is updated. -1 disables caching. Default 1000
|
|
53
|
+
cache_write_interval = -1
|
|
54
|
+
|
|
55
|
+
# Total writes per second to the backing store that an actor will allow, across all keys. Note this is on a per actor
|
|
56
|
+
# basis. If you want to limit total writes per second to your database, this value should be a multiple of the number
|
|
57
|
+
# of write behind cache actors that are started. -1 disables caching. Default 100
|
|
58
|
+
cache_writes_per_second = -1
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
gamecloud {
|
|
63
|
+
#host = "localhost:9000"
|
|
64
|
+
#user = test
|
|
65
|
+
#api_key = 294122207690d6e93867c56fae265c24
|
|
66
|
+
#api_key = 20934a81ba104ad1936b8a3e9e7fdaef
|
|
67
|
+
|
|
68
|
+
user = chris
|
|
69
|
+
host = "cloud-dev.gamemachine.io:80"
|
|
70
|
+
api_key = 1a77d75e32767f89b0710311be1fd8a5
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
grids {
|
|
74
|
+
default = "4000, 50, 1"
|
|
75
|
+
aoe = "4000, 5, 1"
|
|
76
|
+
local_chat = "4000, 10, 10"
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
couchbase {
|
|
80
|
+
bucket = gamemachine
|
|
81
|
+
password = pass
|
|
82
|
+
servers = ["http://192.168.1.8:8091/pools"]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
jdbc {
|
|
86
|
+
|
|
87
|
+
// Postgres
|
|
88
|
+
hostname = 127.0.0.1
|
|
89
|
+
port = 5432
|
|
90
|
+
database = gamemachine
|
|
91
|
+
url = "jdbc:postgresql://127.0.0.1:5432/gamemachine"
|
|
92
|
+
ds = "org.postgresql.ds.PGSimpleDataSource"
|
|
93
|
+
driver = "org.postgresql.Driver"
|
|
94
|
+
username = gamemachine
|
|
95
|
+
password = gamemachine
|
|
96
|
+
|
|
97
|
+
// Mysql
|
|
98
|
+
#hostname = 127.0.0.1
|
|
99
|
+
#port = 3306
|
|
100
|
+
#database = gamemachine
|
|
101
|
+
#url = "mysql://127.0.0.1:3306/game_machine"
|
|
102
|
+
#ds = "com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
|
|
103
|
+
#driver = "com.mysql.jdbc.Driver"
|
|
104
|
+
#username = gamemachine
|
|
105
|
+
#password = gamemachine
|
|
106
|
+
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
http {
|
|
110
|
+
enabled = true
|
|
111
|
+
host = 0.0.0.0
|
|
112
|
+
port = 3000
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
udp {
|
|
116
|
+
enabled = true
|
|
117
|
+
host = 0.0.0.0
|
|
118
|
+
port = 24130
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
tcp {
|
|
122
|
+
enabled = true
|
|
123
|
+
host = 0.0.0.0
|
|
124
|
+
port = 8910
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
akka {
|
|
128
|
+
host = 127.0.0.1
|
|
129
|
+
port = 2551
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
# Seeds are akka nodes that should already be in the cluster. We use them as first points of contact to join against
|
|
133
|
+
# If there are no seeds, we start the cluster by joining to ourself
|
|
134
|
+
#seeds = ["127.0.0.1:9991","127.0.0.1:9992"]
|
|
135
|
+
seeds = []
|
|
136
|
+
|
|
137
|
+
admin {
|
|
138
|
+
user = admin
|
|
139
|
+
pass = pass
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
regions = [
|
|
143
|
+
["zone1","GameMachine::DefaultHandlers::ZoneManager"],
|
|
144
|
+
["zone2", "GameMachine::DefaultHandlers::ZoneManager"]
|
|
145
|
+
]
|
|
146
|
+
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
|
data/game_machine.gemspec
CHANGED
|
@@ -18,17 +18,22 @@ Gem::Specification.new do |gem|
|
|
|
18
18
|
gem.require_paths = ["lib"]
|
|
19
19
|
|
|
20
20
|
gem.add_dependency 'i18n'
|
|
21
|
-
gem.add_dependency 'rjack-logback'
|
|
22
|
-
gem.add_dependency 'settingslogic'
|
|
23
|
-
gem.add_dependency 'consistent-hashing'
|
|
24
21
|
gem.add_dependency 'json'
|
|
25
22
|
gem.add_dependency 'ffi'
|
|
26
23
|
gem.add_dependency 'sinatra'
|
|
27
24
|
gem.add_dependency 'sinatra-contrib'
|
|
28
|
-
gem.add_dependency '
|
|
29
|
-
gem.add_dependency '
|
|
25
|
+
gem.add_dependency 'rack-flash3'
|
|
26
|
+
gem.add_dependency 'activesupport'
|
|
27
|
+
gem.add_dependency 'wavefront'
|
|
28
|
+
gem.add_dependency 'puma'
|
|
29
|
+
gem.add_dependency 'faraday'
|
|
30
|
+
gem.add_dependency 'bcrypt'
|
|
31
|
+
gem.add_dependency 'bundler'
|
|
32
|
+
|
|
30
33
|
|
|
31
34
|
gem.add_development_dependency 'rake'
|
|
35
|
+
gem.add_development_dependency 'nanoc'
|
|
36
|
+
gem.add_development_dependency 'kramdown'
|
|
32
37
|
gem.add_development_dependency 'rspec'
|
|
33
38
|
gem.add_development_dependency 'rspec-mocks'
|
|
34
39
|
gem.add_development_dependency 'rspec-expectations'
|
data/games/boot.rb
ADDED
data/games/example/lib/game.rb
CHANGED
|
@@ -4,9 +4,7 @@ require_relative 'models/attack'
|
|
|
4
4
|
require_relative 'models/user'
|
|
5
5
|
require_relative 'models/combat_update'
|
|
6
6
|
require_relative 'models/player_command'
|
|
7
|
-
require_relative 'authentication_handler'
|
|
8
7
|
require_relative 'tracking_handler'
|
|
9
|
-
require_relative 'player_register'
|
|
10
8
|
require_relative 'example_controller'
|
|
11
9
|
require_relative 'chatbot'
|
|
12
10
|
require_relative 'combat_controller'
|
|
@@ -16,6 +14,7 @@ require_relative 'aggressive_npc'
|
|
|
16
14
|
require_relative 'npc_group'
|
|
17
15
|
require_relative 'player_manager'
|
|
18
16
|
require_relative 'zone_manager'
|
|
17
|
+
require_relative 'player_register'
|
|
19
18
|
|
|
20
19
|
module Example
|
|
21
20
|
class Game
|
data/games/routes.rb
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
GameMachine::Routes.game_messages do
|
|
3
|
+
|
|
4
|
+
# The route id and the to: parameter are both required. Everything else is optional
|
|
5
|
+
# route id's can be any positive integer. For ruby actors, to: should be the class. For java actors
|
|
6
|
+
# to: should be the string name of the actor (as defined in the java class)
|
|
7
|
+
route 1, to: 'Tutorial::ItemManager', distributed: true, name: 'item_manager'
|
|
8
|
+
route 2, to: 'loot_generator', name: 'loot_generator'
|
|
9
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
require_relative 'item_manager'
|
|
3
|
+
|
|
4
|
+
# For the inventory handler we use a distributed router. The routing system for game messages uses
|
|
5
|
+
# the player id to hash against which guarantees that player ids are mapped to specific actors.
|
|
6
|
+
# This lets us cache player specific data in the actor that the player is hashed to.
|
|
7
|
+
if GameMachine::Application.config.orm
|
|
8
|
+
require_relative 'seed'
|
|
9
|
+
GameMachine::Actor::Builder.new(Tutorial::ItemManager).distributed(3).start
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
require_relative 'object_store'
|
|
2
|
+
require_relative 'sql_store'
|
|
3
|
+
|
|
4
|
+
module Tutorial
|
|
5
|
+
|
|
6
|
+
# Provides item persistence and management. Choice of using object store or sql on a per item basis.
|
|
7
|
+
# Items that have a limited quantity or a cost involve updating multiple records. These items will benefit from
|
|
8
|
+
# using sql as the item manager wraps those updates in a transaction to ensure the updates are atomic. But that comes
|
|
9
|
+
# at a cost. Do not use sql for items just because you prefer sql.
|
|
10
|
+
|
|
11
|
+
# Items that are not limited quantity or have a cost, only require updating the item itself. These items are ideal for
|
|
12
|
+
# the object store. Because we use a distributed router for the item manager, even object store items are saved atomically.
|
|
13
|
+
# The limitation of the object store is that we cannot save multiple items atomically, but are limited to just one.
|
|
14
|
+
|
|
15
|
+
# This demo is designed to show the full persistence api and reliable messaging in a common use case. It should work
|
|
16
|
+
# fine as a starting point for your own item management.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Design notes:
|
|
20
|
+
# - Item definitions are just items assigned to the 'global' user. Player items are created by cloning one of the global items.
|
|
21
|
+
#
|
|
22
|
+
# - Extending the system for more types of items should be done compositionally by adding new messages to PlayerItem. Think of it
|
|
23
|
+
# as an entity component system where PlayerItem is the entity, and all the messages it contains are the components.
|
|
24
|
+
#
|
|
25
|
+
# - We prefer to use nested messages instead of adding concrete fields to PlayerItem. It's a good way to keep encapsulation.
|
|
26
|
+
|
|
27
|
+
class ItemManager < GameMachine::Actor::GameActor
|
|
28
|
+
include GameMachine
|
|
29
|
+
attr_reader :player_item_cache, :catalog_list, :catalog_map, :object_store, :sql_store, :catalog_user
|
|
30
|
+
|
|
31
|
+
def awake(args)
|
|
32
|
+
@catalog_user = 'global'
|
|
33
|
+
@sql_store = SqlStore.new
|
|
34
|
+
@object_store = ObjectStore.new
|
|
35
|
+
|
|
36
|
+
@player_item_cache = {}
|
|
37
|
+
|
|
38
|
+
@catalog_list = MessageLib::PlayerItem.db_find_all(catalog_user)
|
|
39
|
+
@catalog_map = catalog_list.each_with_object({}) {|v,res| res[v.id] = v}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def on_game_message(game_message)
|
|
43
|
+
player_items_message = MessageLib::PlayerItems.new
|
|
44
|
+
|
|
45
|
+
# exactly_once returns true of the message is a reliable message, and it is the first time we have seen
|
|
46
|
+
# the message. Use set_reply instead of tell_player for reliable messages.
|
|
47
|
+
if exactly_once(game_message)
|
|
48
|
+
reply = new_game_message.set_player_items(player_items_message)
|
|
49
|
+
|
|
50
|
+
if game_message.has_add_player_item
|
|
51
|
+
add_player_item(game_message.add_player_item.player_item).each do |player_item|
|
|
52
|
+
reply.player_items.add_player_item(player_item)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
if game_message.has_remove_player_item
|
|
57
|
+
if player_item = remove_player_item(game_message.remove_player_item.id,
|
|
58
|
+
game_message.remove_player_item.quantity
|
|
59
|
+
)
|
|
60
|
+
reply.player_items.add_player_item(player_item)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
set_reply(reply)
|
|
65
|
+
|
|
66
|
+
elsif game_message.has_request_player_items
|
|
67
|
+
|
|
68
|
+
if game_message.request_player_items.catalog
|
|
69
|
+
player_items_message.set_player_item_list(catalog_list)
|
|
70
|
+
player_items_message.catalog = true
|
|
71
|
+
else
|
|
72
|
+
player_items.values.each {|pi| player_items_message.add_player_item(pi)}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
player_message = new_game_message
|
|
76
|
+
player_message.set_player_items(player_items_message)
|
|
77
|
+
tell_player(player_message)
|
|
78
|
+
else
|
|
79
|
+
unhandled(game_message)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def on_player_disconnect(player_id)
|
|
84
|
+
player_item_cache.delete(player_id)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def player_items
|
|
90
|
+
unless player_item_cache.fetch(player_id,nil)
|
|
91
|
+
player_item_cache[player_id] = {}
|
|
92
|
+
sql_store.all_for_player(player_id).each do |player_item|
|
|
93
|
+
player_item_cache[player_id][player_item.id] = player_item
|
|
94
|
+
end
|
|
95
|
+
object_store.all_for_player(player_id).each do |player_item|
|
|
96
|
+
player_item_cache[player_id][player_item.id] = player_item
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
player_item_cache[player_id]
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def add_player_item(player_item)
|
|
103
|
+
catalog_item = catalog_map.fetch(player_item.id,nil)
|
|
104
|
+
return nil if catalog_item.nil?
|
|
105
|
+
|
|
106
|
+
if object_store_item?(player_item)
|
|
107
|
+
return add_object_store_item(player_item,catalog_item)
|
|
108
|
+
else
|
|
109
|
+
return add_sql_item(player_item,catalog_item)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def remove_player_item(id,quantity)
|
|
114
|
+
if player_item = player_items.fetch(id,nil)
|
|
115
|
+
player_item.quantity -= quantity
|
|
116
|
+
if player_item.quantity >= 1
|
|
117
|
+
store_save_player_item(player_item,player_id)
|
|
118
|
+
else
|
|
119
|
+
store_delete_player_item(player_item,player_id)
|
|
120
|
+
player_items.delete(id)
|
|
121
|
+
end
|
|
122
|
+
player_item
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Retrieves current player item, or creates new one from catalog item
|
|
127
|
+
# new items are set to 0 quantity and stripped of components that we don't need
|
|
128
|
+
# to store on the player copy, such as the cost.
|
|
129
|
+
def player_item(id,catalog_item)
|
|
130
|
+
if current_player_item = player_items.fetch(id,nil)
|
|
131
|
+
current_player_item
|
|
132
|
+
else
|
|
133
|
+
current_player_item = catalog_item.clone
|
|
134
|
+
current_player_item.quantity = 0
|
|
135
|
+
current_player_item.set_cost(nil)
|
|
136
|
+
current_player_item
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def deduct_item_cost(player_item,catalog_item)
|
|
141
|
+
currency = catalog_item.cost.currency
|
|
142
|
+
return nil unless player_items.has_key?(currency)
|
|
143
|
+
|
|
144
|
+
player_currency = player_items[currency].clone
|
|
145
|
+
|
|
146
|
+
currency_required = player_item.quantity * catalog_item.cost.amount
|
|
147
|
+
if player_currency.quantity >= currency_required
|
|
148
|
+
player_currency.quantity -= currency_required
|
|
149
|
+
store_save_player_item(player_currency,player_id,true)
|
|
150
|
+
return player_currency
|
|
151
|
+
else
|
|
152
|
+
nil
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def add_object_store_item(player_item,catalog_item)
|
|
157
|
+
current_player_item = player_item(player_item.id,catalog_item)
|
|
158
|
+
current_player_item.quantity += player_item.quantity
|
|
159
|
+
player_items[current_player_item.id] = current_player_item
|
|
160
|
+
|
|
161
|
+
store_save_player_item(current_player_item,player_id)
|
|
162
|
+
return [current_player_item]
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def add_sql_item(player_item,catalog_item)
|
|
166
|
+
state = OpenStruct.new
|
|
167
|
+
changed_items = []
|
|
168
|
+
state.player_item = player_item(player_item.id,catalog_item).clone
|
|
169
|
+
|
|
170
|
+
begin
|
|
171
|
+
ModelLib::PlayerItem.open_transaction
|
|
172
|
+
|
|
173
|
+
limited_item = catalog_item.quantity == -1 ? false : true
|
|
174
|
+
|
|
175
|
+
if limited_item
|
|
176
|
+
state.catalog_item = sql_store.find_by_id(catalog_item.id,catalog_user,true)
|
|
177
|
+
if state.catalog_item.quantity >= player_item.quantity
|
|
178
|
+
state.catalog_item.quantity -= player_item.quantity
|
|
179
|
+
store_save_player_item(state.catalog_item,catalog_user,true)
|
|
180
|
+
else
|
|
181
|
+
ModelLib::PlayerItem.rollback_transaction
|
|
182
|
+
GameMachine.logger.info "Insufficient quantity (#{current_catalog_item.quantity}) for #{player_item.id}"
|
|
183
|
+
return changed_items
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
if catalog_item.has_cost
|
|
188
|
+
state.player_currency = deduct_item_cost(player_item,catalog_item)
|
|
189
|
+
if state.player_currency.nil?
|
|
190
|
+
ModelLib::PlayerItem.rollback_transaction
|
|
191
|
+
GameMachine.logger.info "cost deduction failed #{player_item.id}"
|
|
192
|
+
return changed_items
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
state.player_item.quantity += player_item.quantity
|
|
197
|
+
store_save_player_item(state.player_item,player_id,true)
|
|
198
|
+
|
|
199
|
+
ModelLib::PlayerItem.commit_transaction
|
|
200
|
+
|
|
201
|
+
player_items[state.player_item.id] = state.player_item
|
|
202
|
+
changed_items << state.player_item
|
|
203
|
+
|
|
204
|
+
if state.catalog_item
|
|
205
|
+
catalog_item = state.catalog_item
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
if state.player_currency
|
|
209
|
+
player_items[state.player_currency.id] = state.player_currency
|
|
210
|
+
changed_items << state.player_currency
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
return changed_items
|
|
214
|
+
rescue Exception => e
|
|
215
|
+
GameMachine.logger.error "Error adding sql item #{player_item.id} #{e.to_s} \n #{e.backtrace.join("\n")}"
|
|
216
|
+
ModelLib::PlayerItem.rollback_transaction
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Use object store when:
|
|
221
|
+
# - item is not currency
|
|
222
|
+
# - item is not limited quantity
|
|
223
|
+
# - item does not have a cost
|
|
224
|
+
|
|
225
|
+
# Note that cost handling is not implemented for object store items.
|
|
226
|
+
def object_store_item?(player_item)
|
|
227
|
+
catalog_item = catalog_map.fetch(player_item.id)
|
|
228
|
+
if catalog_item.has_cost
|
|
229
|
+
false
|
|
230
|
+
elsif ['gold','silver'].include?(catalog_item.id)
|
|
231
|
+
false
|
|
232
|
+
elsif catalog_item.quantity = -1
|
|
233
|
+
true
|
|
234
|
+
else
|
|
235
|
+
false
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def store_save_player_item(player_item,player_id,in_transaction=false)
|
|
240
|
+
if object_store_item?(player_item)
|
|
241
|
+
object_store.save_player_item(player_item,player_id)
|
|
242
|
+
else
|
|
243
|
+
sql_store.save_player_item(player_item,player_id,in_transaction)
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
def store_delete_player_item(player_item,player_id)
|
|
248
|
+
if object_store_item?(player_item)
|
|
249
|
+
object_store.delete_player_item(player_item.id,player_id)
|
|
250
|
+
else
|
|
251
|
+
sql_store.delete_player_item(player_item.id,player_id)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
end
|
|
256
|
+
end
|