PPaste!

Hearthstone stalk

Home - All the pastes - Authored by Thooms

Raw version

  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
#!/usr/bin/env ruby

require 'curses'
require 'io/console'
require 'socket'

# $ gem install libnotify
require 'libnotify'

module ColorPair
  DEFAULT = 0
  TITLE = 1
end

def io_readable?(socket)
  read_array = IO::select [socket], nil, nil, 0.0
  if read_array && read_array[0]
    read_array[0].include? socket
  else
    false
  end
end

def info_from_str(str)
  arr = str.split(',')
  {
    :ukn1 => arr[0].to_i,
    :ukn2 => arr[1].to_i,
    :ukn3 => arr[2].to_i,
    :user_id => arr[3].to_i,
    :user_name => arr[4],
    :battle_id => arr[5].to_i,
    :version => arr[6].to_i,
    :hostname => arr[7],
    :in_battle? => arr[8] == "0",
    :ukn4 => arr[9].to_i,
    :last_active => Time.now
  }
end

def draw_title_color
  Curses::setpos(0, 0)
  Curses::attron(Curses::color_pair(ColorPair::TITLE)) do
    Curses::addstr(" " * Curses::cols)
  end
end

def draw_title(title)
  Curses::setpos(0, 0)
  Curses::attron(Curses::color_pair(ColorPair::TITLE)|Curses::A_BOLD) do
    Curses::addstr(" " + title)
  end
end

def draw_player(player, addr)
  player_str = "- #{player[:last_active].strftime("%Y-%m-%d %H:%M:%S").ljust(19)}    #{addr.ljust(15)} #{player[:in_battle?] ? "In battle" : "Idling   "}    #{player[:hostname]}    #{player[:user_name]}\n"
  Curses::addstr(player_str)
end

players = {}

if __FILE__ == $0
  begin
    Curses::init_screen
    Curses::start_color
    Curses::init_pair(ColorPair::TITLE, Curses::COLOR_WHITE, Curses::COLOR_MAGENTA)
    Curses::use_default_colors
    Curses::clear
    draw_title_color
    Curses::refresh

    prog_start = Time.now

    socket = UDPSocket.new
    socket.bind "0.0.0.0", 1228
    loop do
      while io_readable?(socket)
        data, addr = socket.recvfrom 1024
        addr = addr[3]
        player_info = info_from_str(data)
        if Time.now - prog_start > 40.0 && !players.key?(addr)
          # We notify new players starting from 40s after the program
          # start (so that we detect all players that were already
          # playing before notifying)
          Libnotify.show(body: "#{player_info[:user_name]} started playing", summary: "Hearthstone", timeout: 3.0)
        end
        players[addr] = player_info
      end

      Curses::clear
      draw_title_color
      draw_title "Hearthstone connected players"
      Curses::setpos(1, 0)
      players.each { |addr,p| Libnotify.show(body: "#{p[:user_name]} stopped playing", summary: "Hearthstone", timeout: 3.0) if Time.now - p[:last_active] > 60.0 }
      players.delete_if{ |addr,p| Time.now - p[:last_active] > 60.0 }
      players.sort {|p1,p2| p1[1][:user_name] <=> p2[1][:user_name]}.to_h.each do |addr,player_info|
        draw_player(player_info, addr)
      end
      Curses::refresh
      sleep 1
    end
  rescue Interrupt
  ensure
    Curses::close_screen
  end
end