Skip to content
This repository
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 170 lines (137 sloc) 4.748 kb
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 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
class LocsPlus
  include Purugin::Plugin, Purugin::Colors, Purugin::Tasks
  description 'LocsPlus', 0.5

  WAYPOINT_SHOW_ALL_HEADER = "Saved waypoints ({blue}name {gray}loc{white} distance {green}ns ew up{white}):"
  
  module CoordinateEncoding
    def encode(value)
      (value.to_i + 32000).to_s(36)
    end
  
    def decode(value)
      value.to_i(36) - 32000
    end
  end
  
  include CoordinateEncoding
  
  # Takes distance and applies proper direction label
  def distance_string(distance, positive, negative)
    label = distance == 0.0 ? "" : green(distance < 0 ? negative : positive)
    "%0.1f%s" % [distance.abs, label]
  end

  def loc_string(name, player, x, y, z, pitch, yaw)
    loc = player.location
    dx, dy, dz = loc.x - x, loc.y - y, loc.z - z
    distance = Math.sqrt(dx ** 2 + dy ** 2 + dz ** 2)
    ns = distance_string(dz, 'N', 'S')
    ew = distance_string(dx, 'W', 'E')
    ud = distance_string(dy, 'D', 'U')
    colorize("{blue}%s {gray}[%s]{white} ~%0.1f voxs [%s, %s, %s]" %
             [name, pos_string(x, y, z), distance, ns, ew, ud])
  end

  def pos_string(x, y, z, *)
    "%s, %s, %s" % [encode(x), encode(y), encode(z)]
  end

  DIRS = ['S', 'SE', 'E', 'NE', 'N', 'NW', 'W', 'SW', 'S']

  def direction(location)
    # add 255 to shift W to beginning of int division. 450 yaw per dir.
    index = (location.yaw.abs * 10 + 225).to_i / 450
    puts "DIR: #{index}"
    DIRS[index]
  end

  def locations(player)
    @locs ||= {}
    @locs[player.name] = {} unless @locs[player.name]
    @locs[player.name]
  end

  def location(player, name)
    return player.world.spawn_location if name == 'bind'

    player_locs = locations(player)
    return nil unless player_locs

    loc = player_locs[name]
    return nil unless loc

    org.bukkit.Location.from_a loc
  end

  def locations_path
    @path ||= File.join getDataFolder, 'locations.data'
  end

  def load_locations
    return {} unless File.exist? locations_path
    File.open(locations_path, 'rb') { |io| @locs = Marshal.load io }
  end

  def save_locations
    File.open(locations_path, 'wb') { |io| Marshal.dump @locs, io }
  end

  def setup_tracker_thread
    tracks = @tracks = {} # All tracking locations for all players
    @track_time = config.get_fixnum!('locs_plus.track_time', 4)

    # Tracker thread to display all players locs of interest
    sync_task(0, @track_time) do
      tracks.each do |player, (name, loc)|
        player.msg loc_string(name, player, *loc)
      end
    end
  end

  def waypoint_create(player, name)
    raise ArgumentError.new "Cannot use 'bind' as name" if name == 'bind'
    locations(player)[name] = player.location.to_a
    save_locations
  end

  def waypoint_help(p)
    p.msg "/waypoint - show all waypoints"
    p.msg "/waypoint name|bind - show named waypoint"
    p.msg "/waypoint create name - create waypoint for name"
    p.msg "/waypoint remove name - remove waypoint for name"
    p.msg "/waypoint help - display help for waypoints"
  end

  def waypoint_remove(player, name)
    locations(player).delete(name)
    save_locations
  end

  def waypoint_show(player, name)
    player.msg loc_string(name, player, *location(player, name))
  end

  def waypoint_show_all(me)
    me.msg colorize(WAYPOINT_SHOW_ALL_HEADER)
    locations(me).each do |name, loc|
      me.msg loc_string(name, me, *loc)
    end
    me.msg loc_string("bind", me, *me.world.spawn_location.to_a)
  end

  def track(me, waypoint_name)
    me.msg "You start tracking '#{waypoint_name}'"
    @tracks[me] = [waypoint_name, location(me, waypoint_name)]
  end

  def track_help(me)
    me.msg "/track name", "/track stop"
  end

  def track_stop(me)
    if @tracks.delete(me)
      me.msg "Tracking stopped"
    else
      me.msg "No Track is active"
    end
  end

  def track_status(me)
    if @tracks[me]
      me.msg "You are tracking to waypoint '#{@tracks[me][0]}'"
    else
      me.msg "You are not tracking anything"
    end
  end

  def on_enable
    load_locations
    public_player_command('loc', 'display current location') do |me, *|
      loc = me.location
      biome = me.world.biome(me)
      me.msg colorize("Location: {gray}#{pos_string(*loc.to_a)} {green}#{direction(loc)} ({blue}#{biome.name}{white})")
    end

    command_type('valid_wp') do |me, waypoint_name|
      loc = location(me, waypoint_name)
      error? loc, "No such waypoint: '#{waypoint_name}'"
      waypoint_name
    end

    public_player_command('waypoint', 'manage waypoints',
       '<show_all> | help | create {name} | remove {name:valid_wp} | <show> {name:valid_wp} ')

    setup_tracker_thread
    public_player_command('track', 'track to a waypoint',
         '<status> | help | stop | {waypoint:valid_wp}')
  end
end
Something went wrong with that request. Please try again.