]> git.localhorst.tv Git - alttp.git/blobdiff - app/Models/Channel.php
protocol chat bot messages
[alttp.git] / app / Models / Channel.php
index 8b5ff9007e2359c93bc105cdcd9b7e13fb1f73ce..46155cda710d1c5d0de970a692d84a8fce889924 100644 (file)
 
 namespace App\Models;
 
+use Illuminate\Broadcasting\Channel as PublicChannel;
+use Illuminate\Broadcasting\PrivateChannel;
+use Illuminate\Database\Eloquent\BroadcastsEvents;
 use Illuminate\Database\Eloquent\Factories\HasFactory;
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Support\Arr;
 
-class Channel extends Model
-{
+class Channel extends Model {
+
+       use BroadcastsEvents;
        use HasFactory;
 
+       public function broadcastOn($event) {
+               $channels = [
+                       new PrivateChannel('Channel.'.$this->id),
+               ];
+               if (!empty($this->access_key)) {
+                       $channels[] = new PublicChannel('ChannelKey.'.$this->access_key);
+               }
+               return $channels;
+       }
+
+       public function getCurrentEpisode() {
+               return $this->episodes()
+                       ->where('start', '<', now()->subMinutes(10))
+                       ->orderBy('start', 'DESC')
+                       ->first();
+       }
+
+       public function randomOfClass($class) {
+               return $this->queryChatlog()
+                       ->where('classification', '=', $class)
+                       ->first();
+       }
+
+       public function queryChatlog() {
+               return ChatLog::where('type', '=', 'chat')
+                       ->where('banned', '=', false)
+                       ->where('created_at', '<', now()->sub(1, 'day'))
+                       ->where(function ($query) {
+                               $query->whereNull('detected_language');
+                               $query->orWhereIn('detected_language', $this->getPreferredLanguages());
+                       })
+                       ->inRandomOrder();
+       }
+
+       public function getPreferredLanguages() {
+               $setting = $this->getChatSetting('language');
+               if ($setting) {
+                       return [$setting];
+               }
+               if (!empty($this->languages)) {
+                       return $this->languages;
+               }
+               return ['de'];
+       }
+
+       public function getChatSetting($name, $default = null) {
+               if (array_key_exists($name, $this->chat_settings)) {
+                       return $this->chat_settings[$name];
+               }
+               return $default;
+       }
+
+       public function getGuessingLeaderboard() {
+               $query = $this->winners()
+                       ->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')
+                       ->where('score', '!=', 0)
+                       ->groupBy('uid')
+                       ->orderBy('score', 'desc')
+                       ->limit(10);
+               $type = $this->getGuessingSetting('leaderboard_type', 'all');
+               if ($type == 'month') {
+                       $query->where('created_at', '>=', now()->startOfMonth());
+               } else if ($type == 'year') {
+                       $query->where('created_at', '>=', now()->startOfYear());
+               } else if (is_numeric($type)) {
+                       $query->where('created_at', '>=', now()->sub($type, 'days'));
+               }
+               return $query->get();
+       }
+
+       public function hasActiveGuessing() {
+               return !is_null($this->guessing_start);
+       }
+
+       public function isAcceptingGuesses() {
+               return !is_null($this->guessing_start) && is_null($this->guessing_end);
+       }
+
+       public function startGuessing($type) {
+               $this->guessing_type = $type;
+               $this->guessing_start = now();
+               $this->save();
+       }
+
+       public function stopGuessing() {
+               $this->guessing_end = now();
+               $this->save();
+       }
+
+       public function getGuessingSetting($name, $default = null) {
+               if (empty($this->guessing_settings) ||
+                       empty($this->guessing_type) ||
+                       !array_key_exists($this->guessing_type, $this->guessing_settings) ||
+                       !array_key_exists($name, $this->guessing_settings[$this->guessing_type])
+               ) {
+                       return $default;
+               }
+               return $this->guessing_settings[$this->guessing_type][$name];
+       }
+
+       public function solveGuessing($solution) {
+               $start = $this->guessing_start;
+               $end = is_null($this->guessing_end) ? now() : $this->guessing_end;
+               $guesses = $this->guesses()->whereBetween('created_at', [$start, $end])->orderBy('created_at', 'ASC')->get();
+               $unique_guesses = [];
+               foreach ($guesses as $guess) {
+                       $unique_guesses[$guess->uid] = $guess;
+               }
+               $candidates = [];
+               foreach ($unique_guesses as $guess) {
+                       if ($guess->guess == $solution) {
+                               $candidates[] = $guess;
+                       }
+               }
+               if (empty($candidates) && is_numeric($solution)) {
+                       $min_distance = null;
+                       foreach ($unique_guesses as $guess) {
+                               $distance = abs(intval($guess->guess) - intval($solution));
+                               if (is_null($min_distance) || $distance == $min_distance) {
+                                       $candidates[] = $guess;
+                                       if (is_null($min_distance)) {
+                                               $min_distance = $distance;
+                                       }
+                               } else if ($distance < $min_distance) {
+                                       $candidates = [$guess];
+                                       $min_distance = $distance;
+                               }
+                       }
+               }
+               $winners = [];
+               $first = true;
+               foreach ($candidates as $candidate) {
+                       $score = $this->scoreGuessing($solution, $candidate->guess, $first);
+                       $winner = new GuessingWinner();
+                       $winner->channel()->associate($this);
+                       $winner->pod = $start;
+                       $winner->uid = $candidate->uid;
+                       $winner->uname = $candidate->uname;
+                       $winner->guess = $candidate->guess;
+                       $winner->solution = $solution;
+                       $winner->score = $score;
+                       $winner->save();
+                       $winners[] = $winner;
+                       $first = false;
+               }
+               return $winners;
+       }
+
+       public function clearGuessing() {
+               $this->guessing_start = null;
+               $this->guessing_end = null;
+               $this->save();
+       }
+
+       public function transformGuess($original) {
+               $transformed = trim($original);
+               if ($this->guessing_type == 'gtbk') {
+                       $transformed = str_replace(['roodyo1Gtbigkey'], ['2'], $transformed);
+                       $transformed = str_ireplace(['vier 4Head'], ['4'], $transformed);
+               }
+               return $transformed;
+       }
+
+       public function registerGuess($uid, $uname, $guess) {
+               $model = new GuessingGuess();
+               $model->channel()->associate($this);
+               $model->uid = $uid;
+               $model->uname = $uname;
+               $model->guess = $this->transformGuess($guess);
+               $model->save();
+       }
+
+       public function scoreGuessing($solution, $guess, $first) {
+               $transformed = $this->transformGuess($guess);
+               if ($transformed == $solution) {
+                       if ($first) {
+                               return $this->getGuessingSetting('points_exact_first', 1);
+                       }
+                       return $this->getGuessingSetting('points_exact_other', 1);
+               }
+               $distance = abs(intval($transformed) - intval($solution));
+               if ($distance <= $this->getGuessingSetting('points_close_max', 3)) {
+                       if ($first) {
+                               return $this->getGuessingSetting('points_close_first', 1);
+                       }
+                       return $this->getGuessingSetting('points_close_other', 1);
+               }
+               return 0;
+       }
+
+       public function isValidGuess($solution) {
+               $transformed = $this->transformGuess($solution);
+               if ($this->guessing_type == 'gtbk') {
+                       $int_solution = intval($transformed);
+                       return is_numeric($transformed) && $int_solution > 0 && $int_solution < 23;
+               }
+               return false;
+       }
+
+       public function listGuessingWinners($winners) {
+               $names = [];
+               $distance = 0;
+               foreach ($winners as $winner) {
+                       if ($winner->score > 0) {
+                               $names[] = $winner->uname;
+                               $distance = abs(intval($winner->guess) - intval($winner->solution));
+                       }
+               }
+               $msg = '';
+               if (empty($names)) {
+                       $msg = $this->getGuessingSetting('no_winners_message');
+               } else {
+                       $msg = $this->getGuessingSetting($distance ? 'close_winners_message' : 'winners_message', $this->getGuessingSetting('winners_message'));
+                       $msg = str_replace(['{distance}', '{names}'], [$distance, $this->listAnd($names)], $msg);
+               }
+               return $msg;
+       }
+
+       public function listAnd($entries) {
+               $lang = empty($this->languages) ? 'en' : $this->languages[0];
+               if ($lang == 'de') {
+                       return Arr::join($entries, ', ', ' und ');
+               }
+               return Arr::join($entries, ', ', ' and ');
+       }
+
+       public function crews() {
+               return $this->hasMany(ChannelCrew::class);
+       }
+
        public function episodes() {
                return $this->belongsToMany(Episode::class)
                        ->using(Restream::class)
                        ->withPivot('accept_comms', 'accept_tracker');
        }
 
+       public function guesses() {
+               return $this->hasMany(GuessingGuess::class);
+       }
+
        public function organization() {
                return $this->belongsTo(Organization::class);
        }
 
+       public function winners() {
+               return $this->hasMany(GuessingWinner::class);
+       }
+
        protected $casts = [
+               'chat' => 'boolean',
+               'chat_commands' => 'array',
+               'chat_settings' => 'array',
+               'guessing_end' => 'datetime',
+               'guessing_settings' => 'array',
+               'guessing_start' => 'datetime',
                'languages' => 'array',
+               'join' => 'boolean',
        ];
 
        protected $hidden = [
+               'access_key',
+               'chat',
+               'chat_commands',
+               'chat_settings',
                'created_at',
                'ext_id',
+               'guessing_settings',
+               'join',
+               'twitch_chat',
                'updated_at',
        ];