]> git.localhorst.tv Git - alttp.git/blob - app/Models/Channel.php
8af6a7d43e201e191651a4ab9b28fc7c11642ec5
[alttp.git] / app / Models / Channel.php
1 <?php
2
3 namespace App\Models;
4
5 use Illuminate\Broadcasting\Channel as PublicChannel;
6 use Illuminate\Broadcasting\PrivateChannel;
7 use Illuminate\Database\Eloquent\BroadcastsEvents;
8 use Illuminate\Database\Eloquent\Factories\HasFactory;
9 use Illuminate\Database\Eloquent\Model;
10 use Illuminate\Support\Arr;
11
12 class Channel extends Model {
13
14         use BroadcastsEvents;
15         use HasFactory;
16
17         public function broadcastOn($event) {
18                 $channels = [
19                         new PrivateChannel('Channel.'.$this->id),
20                 ];
21                 if (!empty($this->access_key)) {
22                         $channels[] = new PublicChannel('ChannelKey.'.$this->access_key);
23                 }
24                 return $channels;
25         }
26
27         public function getCurrentEpisode() {
28                 return $this->episodes()
29                         ->where('start', '<', now()->subMinutes(10))
30                         ->orderBy('start', 'DESC')
31                         ->first();
32         }
33
34         public function randomOfClass($class) {
35                 return $this->queryChatlog()
36                         ->where('classification', '=', $class)
37                         ->first();
38         }
39
40         public function queryChatlog() {
41                 return ChatLog::where('type', '=', 'chat')
42                         ->where('banned', '=', false)
43                         ->where('created_at', '<', now()->sub(1, 'day'))
44                         ->where(function ($query) {
45                                 $query->whereNull('detected_language');
46                                 $query->orWhereIn('detected_language', $this->getPreferredLanguages());
47                         })
48                         ->inRandomOrder();
49         }
50
51         public function getPreferredLanguages() {
52                 $setting = $this->getChatSetting('language');
53                 if ($setting) {
54                         return [$setting];
55                 }
56                 if (!empty($this->languages)) {
57                         return $this->languages;
58                 }
59                 return ['de'];
60         }
61
62         public function getChatSetting($name, $default = null) {
63                 if (array_key_exists($name, $this->chat_settings)) {
64                         return $this->chat_settings[$name];
65                 }
66                 return $default;
67         }
68
69         public function getGuessingLeaderboard() {
70                 $query = $this->winners()
71                         ->selectRaw('(select t2.uname from guessing_winners t2 where t2.uid = guessing_winners.uid order by created_at desc limit 1) as name, sum(score) as score')
72                         ->where('score', '!=', 0)
73                         ->groupBy('uid')
74                         ->orderBy('score', 'desc')
75                         ->limit(10);
76                 $type = $this->getGuessingSetting('leaderboard_type', 'all');
77                 if ($type == 'month') {
78                         $query->where('created_at', '>=', now()->startOfMonth());
79                 } else if ($type == 'year') {
80                         $query->where('created_at', '>=', now()->startOfYear());
81                 } else if (is_numeric($type)) {
82                         $query->where('created_at', '>=', now()->sub($type, 'days'));
83                 }
84                 return $query->get();
85         }
86
87         public function hasActiveGuessing() {
88                 return !is_null($this->guessing_start);
89         }
90
91         public function isAcceptingGuesses() {
92                 return !is_null($this->guessing_start) && is_null($this->guessing_end);
93         }
94
95         public function startGuessing($type) {
96                 $this->guessing_type = $type;
97                 $this->guessing_start = now();
98                 $this->save();
99         }
100
101         public function stopGuessing() {
102                 $this->guessing_end = now();
103                 $this->save();
104         }
105
106         public function getGuessingSetting($name, $default = null) {
107                 if (empty($this->guessing_settings) ||
108                         empty($this->guessing_type) ||
109                         !array_key_exists($this->guessing_type, $this->guessing_settings) ||
110                         !array_key_exists($name, $this->guessing_settings[$this->guessing_type])
111                 ) {
112                         return $default;
113                 }
114                 return $this->guessing_settings[$this->guessing_type][$name];
115         }
116
117         public function solveGuessing($solution) {
118                 $start = $this->guessing_start;
119                 $end = is_null($this->guessing_end) ? now() : $this->guessing_end;
120                 $guesses = $this->guesses()->whereBetween('created_at', [$start, $end])->orderBy('created_at', 'ASC')->get();
121                 $unique_guesses = [];
122                 foreach ($guesses as $guess) {
123                         $unique_guesses[$guess->uid] = $guess;
124                 }
125                 $candidates = [];
126                 foreach ($unique_guesses as $guess) {
127                         if ($guess->guess == $solution) {
128                                 $candidates[] = $guess;
129                         }
130                 }
131                 if (empty($candidates) && is_numeric($solution)) {
132                         $min_distance = null;
133                         foreach ($unique_guesses as $guess) {
134                                 $distance = abs(intval($guess->guess) - intval($solution));
135                                 if (is_null($min_distance) || $distance == $min_distance) {
136                                         $candidates[] = $guess;
137                                         if (is_null($min_distance)) {
138                                                 $min_distance = $distance;
139                                         }
140                                 } else if ($distance < $min_distance) {
141                                         $candidates = [$guess];
142                                         $min_distance = $distance;
143                                 }
144                         }
145                 }
146                 $winners = [];
147                 $first = true;
148                 foreach ($candidates as $candidate) {
149                         $score = $this->scoreGuessing($solution, $candidate->guess, $first);
150                         $winner = new GuessingWinner();
151                         $winner->channel()->associate($this);
152                         $winner->pod = $start;
153                         $winner->uid = $candidate->uid;
154                         $winner->uname = $candidate->uname;
155                         $winner->guess = $candidate->guess;
156                         $winner->solution = $solution;
157                         $winner->score = $score;
158                         $winner->save();
159                         $winners[] = $winner;
160                         $first = false;
161                 }
162                 return $winners;
163         }
164
165         public function clearGuessing() {
166                 $this->guessing_start = null;
167                 $this->guessing_end = null;
168                 $this->save();
169         }
170
171         public function transformGuess($original) {
172                 $transformed = trim($original);
173                 if ($this->guessing_type == 'gtbk') {
174                         $transformed = str_replace(['roodyo1Gtbigkey'], ['2'], $transformed);
175                         $transformed = str_ireplace(['vier 4Head'], ['4'], $transformed);
176                 }
177                 return $transformed;
178         }
179
180         public function registerGuess($uid, $uname, $guess) {
181                 $model = new GuessingGuess();
182                 $model->channel()->associate($this);
183                 $model->uid = $uid;
184                 $model->uname = $uname;
185                 $model->guess = $this->transformGuess($guess);
186                 $model->save();
187         }
188
189         public function scoreGuessing($solution, $guess, $first) {
190                 $transformed = $this->transformGuess($guess);
191                 if ($transformed == $solution) {
192                         if ($first) {
193                                 return $this->getGuessingSetting('points_exact_first', 1);
194                         }
195                         return $this->getGuessingSetting('points_exact_other', 1);
196                 }
197                 $distance = abs(intval($transformed) - intval($solution));
198                 if ($distance <= $this->getGuessingSetting('points_close_max', 3)) {
199                         if ($first) {
200                                 return $this->getGuessingSetting('points_close_first', 1);
201                         }
202                         return $this->getGuessingSetting('points_close_other', 1);
203                 }
204                 return 0;
205         }
206
207         public function isValidGuess($solution) {
208                 $transformed = $this->transformGuess($solution);
209                 if ($this->guessing_type == 'gtbk') {
210                         $int_solution = intval($transformed);
211                         return is_numeric($transformed) && $int_solution > 0 && $int_solution < 23;
212                 }
213                 return false;
214         }
215
216         public function listGuessingWinners($winners) {
217                 $names = [];
218                 $distance = 0;
219                 foreach ($winners as $winner) {
220                         if ($winner->score > 0) {
221                                 $names[] = $winner->uname;
222                                 $distance = abs(intval($winner->guess) - intval($winner->solution));
223                         }
224                 }
225                 $msg = '';
226                 if (empty($names)) {
227                         $msg = $this->getGuessingSetting('no_winners_message');
228                 } else {
229                         $msg = $this->getGuessingSetting($distance ? 'close_winners_message' : 'winners_message', $this->getGuessingSetting('winners_message'));
230                         $msg = str_replace(['{distance}', '{names}'], [$distance, $this->listAnd($names)], $msg);
231                 }
232                 return $msg;
233         }
234
235         public function listAnd($entries) {
236                 $lang = empty($this->languages) ? 'en' : $this->languages[0];
237                 if ($lang == 'de') {
238                         return Arr::join($entries, ', ', ' und ');
239                 }
240                 return Arr::join($entries, ', ', ' and ');
241         }
242
243         public function chat_bot_logs() {
244                 return $this->hasMany(ChatBotLog::class);
245         }
246
247         public function crews() {
248                 return $this->hasMany(ChannelCrew::class);
249         }
250
251         public function episodes() {
252                 return $this->belongsToMany(Episode::class)
253                         ->using(Restream::class)
254                         ->withPivot('accept_comms', 'accept_tracker');
255         }
256
257         public function guesses() {
258                 return $this->hasMany(GuessingGuess::class);
259         }
260
261         public function organization() {
262                 return $this->belongsTo(Organization::class);
263         }
264
265         public function winners() {
266                 return $this->hasMany(GuessingWinner::class);
267         }
268
269         protected $casts = [
270                 'chat' => 'boolean',
271                 'chat_commands' => 'array',
272                 'chat_settings' => 'array',
273                 'guessing_end' => 'datetime',
274                 'guessing_settings' => 'array',
275                 'guessing_start' => 'datetime',
276                 'languages' => 'array',
277                 'join' => 'boolean',
278         ];
279
280         protected $hidden = [
281                 'access_key',
282                 'chat',
283                 'chat_commands',
284                 'chat_settings',
285                 'created_at',
286                 'ext_id',
287                 'guessing_settings',
288                 'join',
289                 'twitch_chat',
290                 'updated_at',
291         ];
292
293 }