-
Notifications
You must be signed in to change notification settings - Fork 6
/
game.rb
144 lines (130 loc) · 4.54 KB
/
game.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
class Game < ActiveRecord::Base
enum base_game: {imperial: 0, imperial2030: 1, imperialAsia: 2, imperialEurope2030: 3}
enum variant: {standard: 0, auction: 1, withoutInvestorCard: 2}
enum time_commitment: {infinite: 0, slow: 1, async: 2, live: 3}
has_many :actions, dependent: :destroy
has_many :players, dependent: :destroy
has_many :users, through: :players
has_many :cloned_games, class_name: "Game", foreign_key: "cloned_from_game_id", dependent: :nullify
has_many :snapshots
belongs_to :winner, class_name: "User", optional: true
belongs_to :host, class_name: "User"
belongs_to :current_player, class_name: "User", optional: true
belongs_to :cloned_from_game, class_name: "Game", optional: true
scope :current, -> {
includes(:host, :users)
.where(force_ended_at: nil, cancelled_at: nil)
.order(created_at: :desc)
}
def self.import(log, host_id)
initialize_payload = log[0]["payload"]
raise ArgumentError unless log[0]["type"] == "initialize"
imported_games_count = Game.where(is_imported: true).count
host = User.find(host_id)
game = Game.new(base_game: initialize_payload["baseGame"], variant: initialize_payload["variant"], host: host)
initialize_payload["players"].each do |player|
user = User.create!(name: player["id"] + "-import(#{rand(100000)})")
game.players << Player.new(user: user)
end
log.each do |action|
if action["type"] == "initialize"
action["payload"]["soloMode"] = true
end
game.actions << Action.new(data: action.to_json)
end
game.is_imported = true
game.name = "Imported game: #{imported_games_count + 1}"
game.save!
game
end
def to_json
observers = JSON.parse(REDIS.get("users_observing_games"))[id] || []
latest_state = snapshots.order(:created_at).last&.state
parsed_latest_state = latest_state ? JSON.parse(latest_state)["state"] : nil
{
name: name,
id: id,
base_game: base_game,
host: host.name,
players: users.map(&:to_json_in_game),
force_ended_at: force_ended_at,
cancelled_at: cancelled_at,
created_at: created_at,
current_player_name: current_player&.name,
started_at: started_at,
winner_name: winner&.name,
observers: observers,
variant: variant,
last_move_at: last_move_at,
cloned_from_game: cloned_from_game&.id,
is_public: is_public,
time_commitment: time_commitment,
latest_state: parsed_latest_state
}
end
def to_json_with_observers(observers)
latest_state = snapshots.order(:created_at).last&.state
parsed_latest_state = latest_state ? JSON.parse(latest_state)["state"] : nil
{
name: name,
id: id,
base_game: base_game,
host: host.name,
players: users.map(&:to_json_in_game),
force_ended_at: force_ended_at,
cancelled_at: cancelled_at,
created_at: created_at,
current_player_name: current_player&.name,
started_at: started_at,
winner_name: winner&.name,
observers: observers,
variant: variant,
last_move_at: last_move_at,
cloned_from_game: cloned_from_game&.id,
is_public: is_public,
time_commitment: time_commitment,
latest_state: parsed_latest_state
}
end
def log
actions.order(:created_at).map do |action|
JSON.parse(action.data)
end
end
def abandoned?
if actions.length > 0 && !force_ended_at
return actions.order(:created_at).last.created_at < 7.days.ago
elsif actions.any? { |a| JSON.parse(a.data)["type"] == "rondel" } && !force_ended_at
return actions.order(:created_at).last.created_at < 30.days.ago
elsif !force_ended_at
return created_at < 7.days.ago
end
false
end
def last_move
actions.order(:created_at).last
end
def last_move_at
last_move&.created_at
end
def clone(host, log)
cloned_game = dup
cloned_game.cloned_from_game = self
cloned_game.host = host
cloned_game.users << host
puts "Cloning game #{cloned_game.name}"
puts "Full game has #{actions.length} actions; cloning #{log.length} actions"
actions.order(created_at: :asc).first(log.length).each do |action|
cloned_game.actions << action.dup.tap do |cloned_action|
parsed_data = JSON.parse(action.data)
if parsed_data.dig("payload", "soloMode") == false
parsed_data["payload"]["soloMode"] = true
cloned_action.data = parsed_data.to_json
end
cloned_action.originally_created_at = action.created_at
end
end
cloned_game.save
cloned_game
end
end