Files
wanderer/lib/wanderer_app/eve_data_service.ex
2024-10-05 01:56:16 +04:00

457 lines
13 KiB
Elixir

defmodule WandererApp.EveDataService do
@moduledoc """
Service for loading data from the EVE DB dumps & JSON files
"""
require Logger
alias WandererApp.Utils.JSONUtil
@eve_db_dump_url "https://www.fuzzwork.co.uk/dump/latest"
@dump_file_names [
"invGroups.csv",
"invTypes.csv",
"mapConstellations.csv",
"mapRegions.csv",
"mapLocationWormholeClasses.csv",
"mapSolarSystems.csv",
"mapSolarSystemJumps.csv"
]
def update_eve_data() do
download_files()
Logger.info("Downloading files finished!")
get_db_data()
|> Ash.bulk_create(WandererApp.Api.MapSolarSystem, :create)
Logger.info("MapSolarSystem updated!")
get_ship_types_data()
|> Ash.bulk_create(WandererApp.Api.ShipTypeInfo, :create)
Logger.info("ShipTypeInfo updated!")
get_solar_system_jumps_data()
|> Ash.bulk_create(WandererApp.Api.MapSolarSystemJumps, :create)
Logger.info("MapSolarSystemJumps updated!")
end
def download_files() do
tasks =
@dump_file_names
|> Enum.map(fn file_name ->
Task.async(fn ->
download_file(file_name)
end)
end)
Task.await_many(tasks, :timer.minutes(1))
end
def download_file(file_name) do
url = "#{@eve_db_dump_url}/#{file_name}"
Logger.info("Downloading file from #{url}")
download_path = Path.join([:code.priv_dir(:wanderer_app), "repo", "data", file_name])
Req.get!(url, raw: true, into: File.stream!(download_path, [:write])).body
|> Stream.run()
Logger.info("File downloaded successfully to #{download_path}")
:ok
end
def load_wormhole_types() do
JSONUtil.read_json("#{:code.priv_dir(:wanderer_app)}/repo/data/wormholes.json")
|> JSONUtil.map_json(fn row ->
%{
id: row["typeID"],
name: row["name"],
src: row["src"],
dest: row["dest"],
total_mass: row["total_mass"],
lifetime: row["lifetime"],
max_mass_per_jump: row["max_mass_per_jump"],
static: row["static"],
mass_regen: row["mass_regen"],
sibling_groups: row["sibling_groups"]
}
end)
end
def load_wormhole_classes() do
JSONUtil.read_json("#{:code.priv_dir(:wanderer_app)}/repo/data/wormholeClasses.json")
|> JSONUtil.map_json(fn row ->
%{
id: row["id"],
short_name: row["shortName"],
title: row["title"],
effect_power: row |> Map.get("effectPower", 0),
wormhole_class_id: row["wormholeClassID"]
}
end)
end
def load_wormhole_systems() do
JSONUtil.read_json("#{:code.priv_dir(:wanderer_app)}/repo/data/wormholeSystems.json")
|> JSONUtil.map_json(fn row ->
%{
solar_system_id: row["solarSystemID"],
wanderers: row["wanderers"],
statics: row["statics"],
system_name: row["systemName"],
effect_name: row["effectName"]
}
end)
end
def load_effects() do
JSONUtil.read_json("#{:code.priv_dir(:wanderer_app)}/repo/data/effects.json")
|> JSONUtil.map_json(fn row ->
%{
id: row["name"] |> Slug.slugify(),
name: row["name"],
modifiers:
row["modifiers"]
|> Enum.map(fn m ->
%{
name: m["name"],
positive: m["positive"],
power: m["power"]
}
end)
}
end)
end
def load_triglavian_systems() do
JSONUtil.read_json("#{:code.priv_dir(:wanderer_app)}/repo/data/triglavianSystems.json")
|> JSONUtil.map_json(fn row ->
%{
solar_system_id: row["solarSystemID"],
solar_system_name: row["solarSystemName"],
effect_name: row["effectName"],
effect_power: row["effectPower"],
invasion_status: row["invasionStatus"]
}
end)
end
def load_wormhole_classes_info() do
{:ok, data} =
JSONUtil.read_json("#{:code.priv_dir(:wanderer_app)}/repo/data/wormholeClassesInfo.json")
%{
names: data["names"],
classes: data["classes"]
}
end
def load_shattered_constellations() do
{:ok, data} =
JSONUtil.read_json(
"#{:code.priv_dir(:wanderer_app)}/repo/data/shatteredConstellations.json"
)
data
end
def load_map_constellations() do
WandererApp.Utils.CSVUtil.csv_row_to_table_record(
"#{:code.priv_dir(:wanderer_app)}/repo/data/mapConstellations.csv",
fn row ->
%{
constellation_id: row["constellationID"] |> Integer.parse() |> elem(0),
constellation_name: row["constellationName"]
}
end
)
end
def load_map_regions() do
WandererApp.Utils.CSVUtil.csv_row_to_table_record(
"#{:code.priv_dir(:wanderer_app)}/repo/data/mapRegions.csv",
fn row ->
%{
region_id: row["regionID"] |> Integer.parse() |> elem(0),
region_name: row["regionName"]
}
end
)
end
def load_map_location_wormhole_classes() do
WandererApp.Utils.CSVUtil.csv_row_to_table_record(
"#{:code.priv_dir(:wanderer_app)}/repo/data/mapLocationWormholeClasses.csv",
fn row ->
%{
location_id: row["locationID"],
wormhole_class_id: row["wormholeClassID"]
}
end
)
end
def load_inv_groups() do
WandererApp.Utils.CSVUtil.csv_row_to_table_record(
"#{:code.priv_dir(:wanderer_app)}/repo/data/invGroups.csv",
fn row ->
%{
group_id: row["groupID"] |> Integer.parse() |> elem(0),
group_name: row["groupName"],
category_id: row["categoryID"] |> Integer.parse() |> elem(0)
}
end
)
end
def get_db_data() do
map_constellations = load_map_constellations()
map_regions = load_map_regions()
map_location_wormhole_classes = load_map_location_wormhole_classes()
wormhole_classes = load_wormhole_classes()
wormhole_systems = load_wormhole_systems()
triglavian_systems = load_triglavian_systems()
wormhole_classes_info = load_wormhole_classes_info()
shattered_constellations = load_shattered_constellations()
WandererApp.Utils.CSVUtil.csv_row_to_table_record(
"#{:code.priv_dir(:wanderer_app)}/repo/data/mapSolarSystems.csv",
fn row ->
solar_system_id = row["solarSystemID"] |> Integer.parse() |> elem(0)
region_id = row["regionID"] |> Integer.parse() |> elem(0)
constellation_id = row["constellationID"] |> Integer.parse() |> elem(0)
{:ok, wormhole_class_id} =
get_wormhole_class_id(
map_location_wormhole_classes,
region_id,
constellation_id,
solar_system_id
)
{:ok, constellation_name} =
get_constellation_name(map_constellations, constellation_id)
{:ok, region_name} = get_region_name(map_regions, region_id)
{:ok, wormhole_class} = get_wormhole_class(wormhole_classes, wormhole_class_id)
{:ok, security} = get_security(row["security"])
{:ok, class_title} =
get_class_title(
wormhole_classes_info,
wormhole_class_id,
security,
wormhole_class
)
is_shattered =
case Map.get(shattered_constellations, constellation_id |> Integer.to_string()) do
nil -> false
_ -> true
end
%{
effect_power: 0,
effect_name: "",
statics: [],
wandering: [],
triglavian_invasion_status: "Normal",
constellation_id: constellation_id,
region_id: region_id,
solar_system_id: solar_system_id,
solar_system_name: row["solarSystemName"],
solar_system_name_lc: row["solarSystemName"] |> String.downcase(),
sun_type_id: get_sun_type_id(row["sunTypeID"]),
constellation_name: constellation_name,
region_name: region_name,
security: security,
system_class: wormhole_class_id,
class_title: class_title,
type_description: wormhole_class.title,
is_shattered: is_shattered
}
|> get_wormhole_data(wormhole_systems, solar_system_id, wormhole_class)
|> get_triglavian_data(triglavian_systems, solar_system_id)
end
)
end
def get_ship_types_data() do
inv_groups = load_inv_groups()
ship_type_groups =
inv_groups
|> Enum.filter(fn g -> g.category_id == 6 end)
|> Enum.map(fn g -> g.group_id end)
WandererApp.Utils.CSVUtil.csv_row_to_table_record(
"#{:code.priv_dir(:wanderer_app)}/repo/data/invTypes.csv",
fn row ->
group_id = row["groupID"] |> Integer.parse() |> elem(0)
inv_group =
case Enum.find(inv_groups, fn group ->
group.group_id == group_id
end) do
nil -> %{}
group -> group
end
%{
type_id: row["typeID"] |> Integer.parse() |> elem(0),
group_id: group_id,
name: row["typeName"],
mass: row["mass"],
volume: row["volume"],
capacity: row["capacity"],
group_name: inv_group.group_name
}
end
)
|> Enum.filter(fn t -> t.group_id in ship_type_groups end)
end
def get_solar_system_jumps_data() do
WandererApp.Utils.CSVUtil.csv_row_to_table_record(
"#{:code.priv_dir(:wanderer_app)}/repo/data/mapSolarSystemJumps.csv",
fn row ->
%{
from_solar_system_id: row["fromSolarSystemID"] |> Integer.parse() |> elem(0),
to_solar_system_id: row["toSolarSystemID"] |> Integer.parse() |> elem(0)
}
end
)
end
defp get_sun_type_id(sun_type_id) do
case sun_type_id do
"None" -> 0
_ -> sun_type_id |> Integer.parse() |> elem(0)
end
end
defp get_wormhole_data(default_data, wormhole_systems, solar_system_id, wormhole_class) do
case Enum.find(wormhole_systems, fn system -> system.solar_system_id == solar_system_id end) do
nil ->
default_data
wormhole_data ->
%{
default_data
| effect_power: wormhole_class.effect_power,
effect_name: wormhole_data.effect_name,
statics: wormhole_data.statics,
wandering: wormhole_data.wanderers
}
end
end
defp get_triglavian_data(default_data, triglavian_systems, solar_system_id) do
case Enum.find(triglavian_systems, fn system -> system.solar_system_id == solar_system_id end) do
nil ->
default_data
triglavian_data ->
%{
default_data
| triglavian_invasion_status: triglavian_data.invasion_status,
effect_name: triglavian_data.effect_name,
effect_power: triglavian_data.effect_power
}
end
end
defp get_security(security) do
case security do
nil -> {:ok, ""}
_ -> {:ok, String.to_float(security) |> get_true_security() |> Float.to_string(decimals: 1)}
end
end
defp get_true_security(security) when is_float(security) and security > 0.0 and security < 0.05, do: security |> Float.ceil(1)
defp get_true_security(security) when is_float(security), do: security |> Float.floor(1)
defp get_class_title(wormhole_classes_info, wormhole_class_id, security, wormhole_class) do
case wormhole_class_id in [
wormhole_classes_info.names["hs"],
wormhole_classes_info.names["ls"],
wormhole_classes_info.names["ns"]
] do
true ->
{:ok, security}
_ ->
{:ok, wormhole_class.short_name}
end
end
defp get_constellation_name(constellations, constellation_id) do
case Enum.find(constellations, fn constellation ->
constellation.constellation_id == constellation_id
end) do
nil -> {:ok, ""}
constellation -> {:ok, constellation.constellation_name}
end
end
defp get_region_name(regions, region_id) do
case Enum.find(regions, fn region -> region.region_id == region_id end) do
nil -> {:ok, ""}
region -> {:ok, region.region_name}
end
end
defp get_wormhole_class(wormhole_classes, wormhole_class_id) do
{:ok,
Enum.find(wormhole_classes, fn wormhole_class ->
wormhole_class.wormhole_class_id == wormhole_class_id
end)}
end
defp get_wormhole_class_id(_systems, _region_id, _constellation_id, 30_100_000),
do: {:ok, 10_100}
defp get_wormhole_class_id(systems, region_id, constellation_id, solar_system_id) do
with region <-
Enum.find(systems, fn system ->
system.location_id |> Integer.parse() |> elem(0) == region_id
end),
constellation <-
Enum.find(systems, fn system ->
system.location_id |> Integer.parse() |> elem(0) == constellation_id
end),
solar_system <-
Enum.find(systems, fn system ->
system.location_id |> Integer.parse() |> elem(0) == solar_system_id
end),
wormhole_class_id <- get_wormhole_class_id(region, constellation, solar_system) do
{:ok, wormhole_class_id}
else
_ -> {:ok, -1}
end
end
defp get_wormhole_class_id(_region, _constellation, solar_system)
when not is_nil(solar_system),
do: solar_system.wormhole_class_id |> Integer.parse() |> elem(0)
defp get_wormhole_class_id(_region, constellation, _solar_system)
when not is_nil(constellation),
do: constellation.wormhole_class_id |> Integer.parse() |> elem(0)
defp get_wormhole_class_id(region, _constellation, _solar_system) when not is_nil(region),
do: region.wormhole_class_id |> Integer.parse() |> elem(0)
defp get_wormhole_class_id(_region, _constellation, _solar_system), do: -1
end