class TacScribe::Cache

The in-memory cache that is updated by events in real-time before the data is synced to the DB

Attributes

reference_latitude[RW]
reference_longitude[RW]

Public Instance Methods

clear() click to toggle source
# File lib/tac_scribe/cache.rb, line 102
def clear
  @@cache.clear
  self.reference_latitude = nil
  self.reference_longitude = nil
end
data() click to toggle source
# File lib/tac_scribe/cache.rb, line 21
def data
  @@cache
end
delete_object(id) click to toggle source
# File lib/tac_scribe/cache.rb, line 98
def delete_object(id)
  @@cache[id][:deleted] = true if @@cache[id]
end
write_object(object) click to toggle source
# File lib/tac_scribe/cache.rb, line 25
def write_object(object)
  if (object.has_key? :skip_localization) 
    object.delete(:skip_localization)
  elsif (reference_latitude != 0 || reference_longitude != 0)
    localize_position(object)
  end

  id = object[:object_id]
  id ||= object[:id].to_s
  object[:id] = id

  cache_object = @@cache[id]

  object[:position] = set_position(object, cache_object)

  %i[object_id latitude longitude color country].each do |key|
    object.delete(key)
  end

  # https://wiki.hoggitworld.com/view/DCS_singleton_coalition
  # Tacview returns a string, CinC returns an integer so we
  # only do the conversion if there is a string.
  if object[:coalition] && object[:coalition].is_a?(String)
    object[:coalition] = case object[:coalition]
                         when 'Enemies' # Enemies is Bluefor
                           2
                         when 'Allies' # Allies is Redfor
                           1
                         else # Neutral
                           0
                         end
  end

  if object[:type] == "Ground+Static+Aerodrome"
    object[:heading] = object[:wind_heading] ? object[:wind_heading] : -1
    object[:speed] = object[:wind_speed] ? object[:wind_speed] : 0
    object.delete(:wind_heading)
    object.delete(:wind_speed)
    object.delete(:category)
    cache_object = object
    # No-op
  elsif cache_object
    object[:heading] = calculate_heading(cache_object, object)
    object[:speed] = calculate_speed(cache_object, object)
    cache_object.merge!(object)
  else
    object[:heading] = -1
    object[:speed] = 0
    cache_object = object
  end

  # Hack to make sure the :name field is present so that it is included
  # in the SQL
  cache_object[:name] = nil unless cache_object.has_key?(:name)

  if !cache_object.key?(:altitude) || !cache_object[:altitude]
    cache_object[:altitude] = 0
  end
  if !cache_object.key?(:coalition) || !cache_object[:coalition]
    cache_object[:coalition] = 2
  end

  cache_object[:pilot] = nil unless cache_object.key?(:pilot)

  cache_object[:group] = nil unless cache_object.key?(:group)

  cache_object[:deleted] = false unless cache_object.key?(:deleted)

  cache_object[:updated_at] = Time.now

  @@cache[id] = cache_object
end

Private Instance Methods

calculate_heading(cache_object, object) click to toggle source
# File lib/tac_scribe/cache.rb, line 138
def calculate_heading(cache_object, object)
  if cache_object[:position] == object[:position]
    return cache_object[:heading]
  end

  begin
    cache_object[:position].bearing_to(object[:position]).to_i
  rescue Math::DomainError => e
    puts 'Could not calculate heading: ' + e.message
    puts 'Old Position: ' + cache_object[:position].inspect
    puts 'New Position: ' + object[:position].inspect
  end
end
calculate_speed(cache_object, object) click to toggle source
# File lib/tac_scribe/cache.rb, line 152
def calculate_speed(cache_object, object)
  time = object[:game_time] - cache_object[:game_time]

  start_point = cache_object[:position]
  end_point = object[:position]

  # Because of the above issues with Point and Lat/Lon
  # the values are reverse here :(
  distance = Haversine.distance(start_point.y, start_point.x,
                                end_point.y, end_point.x).to_meters

  speed =  distance / time

  speed.to_i
end
localize_position(object) click to toggle source
# File lib/tac_scribe/cache.rb, line 110
def localize_position(object)
  if reference_latitude && object.key?(:latitude)
    object[:latitude] = reference_latitude + object[:latitude]
  end
  if reference_longitude && object.key?(:longitude)
    object[:longitude] = reference_longitude + object[:longitude]
  end
end
set_position(object, cache_object) click to toggle source
# File lib/tac_scribe/cache.rb, line 119
def set_position(object, cache_object)
  longitude = if object.key?(:longitude)
                object[:longitude]
              else
                cache_object[:position].x
              end

  latitude = if object.key?(:latitude)
               object[:latitude]
             else
               cache_object[:position].y
             end

  # This "Point" class is not lat/long aware which is why we are
  # flipping things up here because when it converts to SQL we need
  # the long to be first since that is what postgresql expects.
  Point.from_x_y(longitude, latitude)
end