Skip to content

Commit

Permalink
add language support to global events
Browse files Browse the repository at this point in the history
fix #1
  • Loading branch information
dealloc committed Mar 4, 2024
1 parent 366a7ed commit 4ba82b0
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 26 deletions.
14 changes: 13 additions & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,19 @@ import Config
config :helldivers_2,
generators: [timestamp_type: :utc_datetime],
war_season: "801",
war_seasons: ["801", "805"]
war_seasons: ["801", "805"],
# default language
language: :en,
# all available languages
languages: [
en: "en-US",
de: "de-DE",
es: "es-ES",
ru: "ru-RU",
fr: "fr-FR",
it: "it-IT",
pl: "pl-PL"
]

# Configures the endpoint
config :helldivers_2, Helldivers2Web.Endpoint,
Expand Down
7 changes: 6 additions & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import Config

# We don't start up any Helldiver seasons during tests to avoid hitting the API
config :helldivers_2,
war_seasons: []
war_seasons: [],
# Limit languages available in testing
languages: [
en: "en-US",
de: "de-DE"
]

# We don't run a server during test. If one is required,
# you can enable the server option below.
Expand Down
51 changes: 40 additions & 11 deletions lib/helldivers_2/models/war_status.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule Helldivers2.Models.WarStatus do
community targets, joint operations, planet events,
and global events.
"""
require Logger
alias Helldivers2.WarSeason
alias Helldivers2.Models.WarInfo.Planet
alias Helldivers2.Models.WarStatus.PlanetEvent
Expand Down Expand Up @@ -46,27 +47,36 @@ defmodule Helldivers2.Models.WarStatus do

@spec download(String.t()) :: {:ok, t()} | {:error, term()}
def download(war_id) do
with {:ok, response} <-
Req.get("https://api.live.prod.thehelldiversgame.com/api/WarSeason/#{war_id}/Status"),
%Req.Response{status: 200, body: payload} <- response do
{:ok, parse(payload)}
else
%Req.Response{status: status} ->
{:error, "API error #{status}"}
end
default_language = Application.get_env(:helldivers_2, :language)

translations = :helldivers_2
|> Application.get_env(:languages)
|> Task.async_stream(fn {key, lang} -> {key, download_language!(war_id, lang)} end, timeout: :infinity, zip_input_on_exit: true)
|> Enum.reduce(%{}, fn ({:ok, {key, payload}}, acc) ->
Map.put(acc, key, payload)
end)

# Take the default language as 'base' response object.
base = Map.get(translations, default_language)

{:ok, parse(base, translations)}
end

@doc """
Attempts to parse as much information as possible from the given `map` into a struct.
"""
@spec parse(map()) :: t()
def parse(map) when is_map(map) do
@spec parse(map(), %{atom() => map()}) :: t()
def parse(map, translations \\ %{}) when is_map(map) do
war_id = Map.get(map, "warId")
campaigns = Enum.map(Map.get(map, "campaigns"), &Campaign.parse(war_id, &1))

joint_operations =
Enum.map(Map.get(map, "jointOperations"), &JointOperation.parse(war_id, &1))

# We currently only translate global events
global_event_translations = translations
|> Map.new(fn {key, payload} -> {key, Map.get(payload, "globalEvents")} end)

%__MODULE__{
war_id: war_id,
snapshot_at: DateTime.from_unix!(Map.get(map, "time")),
Expand All @@ -91,8 +101,27 @@ defmodule Helldivers2.Models.WarStatus do
active_election_policy_effects: [],
global_events: map
|> Map.get("globalEvents")
|> Enum.map(&GlobalEvent.parse(war_id, &1))
|> Enum.map(&GlobalEvent.parse(war_id, &1, global_event_translations))
|> Enum.sort(fn (event1, event2) -> event1.id > event2.id end)
}
end

@spec download_language!(String.t(), String.t()) :: map() | no_return()
defp download_language!(war_id, language) do
Logger.debug("Fetching #{language} for #{war_id}")

response =
[url: "https://api.live.prod.thehelldiversgame.com/api/WarSeason/#{war_id}/Status", retry: :transient]
|> Req.new()
|> Req.Request.put_header("accept-language", language)
|> Req.request!()

case response do
%Req.Response{status: 200} ->
response.body

%Req.Response{status: status} ->
raise "API returned an error #{status}"
end
end
end
24 changes: 20 additions & 4 deletions lib/helldivers_2/models/war_status/global_event.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ defmodule Helldivers2.Models.WarStatus.GlobalEvent do
portrait_id_32: non_neg_integer(),
title: String.t(),
title_32: non_neg_integer(),
message: String.t(),
message: %{String.t() => String.t()},
message_id_32: non_neg_integer(),
race: Faction.t(),
flag: non_neg_integer(),
Expand All @@ -36,16 +36,32 @@ defmodule Helldivers2.Models.WarStatus.GlobalEvent do

@doc """
Attempts to parse as much information as possible from the given `map` into a struct.
Takes an optional map of translations, where each key is the language
and each value is the full list of all global events available.
"""
@spec parse(String.t(), map()) :: t()
def parse(war_id, map) when is_map(map) do
def parse(war_id, map, translations \\ %{}) when is_map(map) do
# Get the ID of the base entity so we can fetch all matching entities from translations.
id = Map.get(map, "eventId")

# Filter out our translations map to only include the currently being processed message.
translations = translations
|> Map.new(fn {lang, events} ->
event = events
|> Enum.find(%{}, fn event -> Map.get(event, "eventId") == id end)
|> Map.get("message")

{lang, event}
end)

%__MODULE__{
id: Map.get(map, "eventId"),
id: id,
id_32: Map.get(map, "id32"),
portrait_id_32: Map.get(map, "portraitId32"),
title: Map.get(map, "title"),
title_32: Map.get(map, "titleId32"),
message: Map.get(map, "message"),
message: translations,
message_id_32: Map.get(map, "messageId32"),
race: Faction.parse(Map.get(map, "race")),
flag: Map.get(map, "flag"),
Expand Down
16 changes: 13 additions & 3 deletions lib/helldivers_2_web/schemas/global_event_schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule Helldivers2Web.Schemas.GlobalEventSchema do
alias OpenApiSpex.Schema
require OpenApiSpex

@languages Application.compile_env(:helldivers_2, :languages)

@doc "Generates a schema for a single homeworld schema response"
def response(),
do:
Expand All @@ -29,16 +31,24 @@ defmodule Helldivers2Web.Schemas.GlobalEventSchema do
},
title: %Schema{
type: :string,
description: "The title text, for some reason this may not always be English"
description: "The title of the global event, appears to be more a status than an actual title",
enum: ["BRIEFING", "SUCCESS", "FAILED"]
},
title_32: %Schema{
type: :integer,
description:
"Internal identifier of the title, this always remains the same regardless of language"
},
message: %Schema{
type: :string,
description: "The message from Super Earth about the global event"
type: :object,
properties:
Map.new(@languages, fn {key, lang} ->
{key,
%Schema{
type: :string,
description: "The message from Super Earth about the global event in #{lang}"
}}
end)
},
message_id_32: %Schema{
type: :integer,
Expand Down
20 changes: 14 additions & 6 deletions test/support/fixtures/war_season_fixtures.ex
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ defmodule Helldivers2.WarSeasonFixtures do
health: 1_000_000,
regen_per_second: 138.88889,
players: 1728,
liberation: 100,
liberation: 100
},
%PlanetStatus{
planet: planet_klen_dath_fixture(),
owner: "Humans",
health: 1_000_000,
regen_per_second: 138.88889,
players: 0,
liberation: 100,
liberation: 100
}
],
planet_attacks: [
Expand Down Expand Up @@ -144,8 +144,12 @@ defmodule Helldivers2.WarSeasonFixtures do
portrait_id_32: 0,
title: "SUCCESS",
title_32: 2_998_873_950,
message:
"The path to the Barrier Planets is clear. \n\nUpon each Barrier Planet, SEAF Engineers have begun construction of the Terminid Control System (TCS): a network of massive towers that will cover each planet in the well-tested neurotoxin known as Termicide.\n\nSoon, our citizens will be able to rest easy, knowing their children are safe from the threat of being eaten alive.",
message: %{
"en" =>
"Well done, Helldivers. SEAF Containment Teams will take over cleanup and inoculation operations from here. Colonists have been advised that there is absolutely zero threat of further Terminid violence, and to settle their families with total peace of mind.\n\nAdditionally, the pilots allocated to spore clearance on Veld have now been redirected to Helldiver support operations. \n<i=1>Extraction will be faster on all operations.</i> ",
"de" =>
"Gut gemacht, Helldivers. S.E.A.F.-Sicherungsteams übernehmen ab hier die Säuberungs- und Impfaufgaben. Die Kolonisten wurden darüber informiert, dass absolut keine Gefahr weiterer Bedrohungen durch Terminiden besteht und dass sie sich in aller Ruhe mit ihren Familien niederlassen können.\n\nDarüber hinaus wurden die Piloten, die die Sporen auf Veld beseitigen sollten, nun angewiesen, die Helldivers bei ihren Bemühungen zu unterstützen.\n<i=1>Die Evakuierung geht bei allen Operationen schneller vonstatten.</i>"
},
message_id_32: 2_450_763_514,
race: "Humans",
flag: 2,
Expand All @@ -159,8 +163,12 @@ defmodule Helldivers2.WarSeasonFixtures do
portrait_id_32: 0,
title: "BRIEFING",
title_32: 2_908_633_975,
message:
"The Automatons have launched cowardly surprise attacks on multiple highly-populated Super Earth planets. The Super Earth Armed Forces in the region have been overrun. Millions of citizens are in grave danger of death, or disenfranchisement.\n\nThis grievous attack on Freedom will not go unanswered. The homes of our citizens must be defended.",
message: %{
"en" =>
"Despite the valorous efforts of the Helldivers, Automaton marauders have invaded Super Earth territory. Patriotic citizens mourn as their sufficiently-sized homes burn to the ground.\n\nSuper Earth citizens demand justice, and they will receive it.",
"de" =>
"Trotz der mutigen Anstrengungen der Helldivers konnten Roboter-Marodeure in Über-Erde-Gebiete eindringen. Patriotische Bürger verfallen in tiefe Trauer, während ihre ausreichend großen Behausungen niederbrennen.\n\nDie Bürger von Über-Erde verlangen Gerechtigkeit und sie werden sie bekommen."
},
message_id_32: 2_667_498_758,
race: "Humans",
flag: 1,
Expand Down

0 comments on commit 4ba82b0

Please sign in to comment.