Skip to content

Commit

Permalink
Asset conversion now receives more details on the asset
Browse files Browse the repository at this point in the history
  • Loading branch information
henriquegemignani committed Aug 11, 2021
1 parent 7367e67 commit 7a3e9d0
Show file tree
Hide file tree
Showing 11 changed files with 80 additions and 48 deletions.
11 changes: 6 additions & 5 deletions retro_data_structures/conversion/ancs.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from construct.lib import ListContainer, Container

from retro_data_structures.conversion.asset_converter import AssetConverter
from retro_data_structures.conversion.asset_converter import AssetConverter, AssetDetails, Resource
from retro_data_structures.conversion.errors import UnsupportedTargetGame, UnsupportedSourceGame
from retro_data_structures.formats.meta_animation import MetaAnimationType
from retro_data_structures.game_check import Game
Expand Down Expand Up @@ -80,7 +80,7 @@ def get_animation_ids(animation):
raise ValueError(f"Unknown animation type: {animation['type']}")


def convert_from_prime(data, converter: AssetConverter):
def convert_from_prime(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.ECHOES:
raise UnsupportedTargetGame(Game.PRIME, converter.target_game)

Expand Down Expand Up @@ -116,7 +116,7 @@ def convert_from_prime(data, converter: AssetConverter):
return data


def convert_from_echoes(data, converter: AssetConverter):
def convert_from_echoes(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.PRIME:
raise UnsupportedTargetGame(Game.ECHOES, converter.target_game)

Expand All @@ -133,7 +133,8 @@ def convert_from_echoes(data, converter: AssetConverter):
seen_ids = set()

for animation, event_set in zip(data["animation_set"]["animations"], data["animation_set"]["event_sets"]):
evnt_id = converter.convert_asset(event_set, "EVNT", Game.ECHOES).id
details = AssetDetails(asset_id=None, asset_type="EVNT", original_game=Game.ECHOES)
evnt_id = converter.convert_asset(event_set, details).id
for anim_id in get_animation_ids(animation["meta"]):
if anim_id not in seen_ids and anim_id != Game.ECHOES.invalid_asset_id:
seen_ids.add(anim_id)
Expand All @@ -147,7 +148,7 @@ def convert_from_echoes(data, converter: AssetConverter):
return data


def convert_from_corruption(data, converter: AssetConverter):
def convert_from_corruption(data: Resource, details: AssetDetails, converter: AssetConverter):
raise UnsupportedSourceGame(Game.CORRUPTION)


Expand Down
8 changes: 4 additions & 4 deletions retro_data_structures/conversion/anim.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from retro_data_structures.conversion.asset_converter import AssetConverter
from retro_data_structures.conversion.asset_converter import AssetConverter, Resource, AssetDetails
from retro_data_structures.conversion.errors import UnsupportedTargetGame, UnsupportedSourceGame
from retro_data_structures.game_check import Game

Expand All @@ -8,7 +8,7 @@ def find_missing(lst):
if x not in lst]


def convert_from_prime(data, converter: AssetConverter):
def convert_from_prime(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.ECHOES:
raise UnsupportedTargetGame(Game.PRIME, converter.target_game)

Expand Down Expand Up @@ -60,7 +60,7 @@ def convert_from_prime(data, converter: AssetConverter):
return data


def convert_from_echoes(data, converter: AssetConverter):
def convert_from_echoes(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.PRIME:
raise UnsupportedTargetGame(Game.ECHOES, converter.target_game)

Expand Down Expand Up @@ -103,7 +103,7 @@ def convert_from_echoes(data, converter: AssetConverter):
return data


def convert_from_corruption(data, converter: AssetConverter):
def convert_from_corruption(data: Resource, details: AssetDetails, converter: AssetConverter):
raise UnsupportedSourceGame(Game.CORRUPTION)


Expand Down
36 changes: 25 additions & 11 deletions retro_data_structures/conversion/asset_converter.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import copy
import dataclasses
from typing import Callable, Dict, Tuple, Any, NamedTuple, Optional

from retro_data_structures.asset_provider import AssetProvider, InvalidAssetId, UnknownAssetId
from retro_data_structures.formats import AssetType, AssetId
from retro_data_structures.game_check import Game

IdGenerator = Callable[[AssetType], AssetId]

@dataclasses.dataclass(frozen=True)
class AssetDetails:
asset_id: Optional[AssetId]
asset_type: AssetType
original_game: Game


IdGenerator = Callable[[AssetDetails], AssetId]
Resource = Any
ResourceConverter = Callable[[Resource, "AssetConverter"], Resource]
ResourceConverter = Callable[[Resource, AssetDetails, "AssetConverter"], Resource]


class ConvertedAsset(NamedTuple):
@dataclasses.dataclass(frozen=True)
class ConvertedAsset:
id: AssetId
type: AssetType
resource: Resource
Expand All @@ -24,7 +34,7 @@ class AssetConverter:
converted_assets: Dict[AssetId, ConvertedAsset]

def __init__(self, target_game: Game, asset_providers: Dict[Game, AssetProvider], id_generator: IdGenerator,
converters: Callable[[Game, AssetType], ResourceConverter]):
converters: Callable[[AssetDetails], ResourceConverter]):
self.target_game = target_game
self.asset_providers = asset_providers
self.id_generator = id_generator
Expand Down Expand Up @@ -58,21 +68,25 @@ def convert_asset_by_id(self, asset_id: AssetId, source_game: Game) -> Converted

asset_provider = self.asset_providers[source_game]
source_asset = asset_provider.get_asset(asset_id)
asset_type = asset_provider.get_type_for_asset(asset_id)
details = AssetDetails(
asset_id=asset_id,
asset_type=asset_provider.get_type_for_asset(asset_id),
original_game=source_game,
)

try:
new_asset = self.convert_asset(source_asset, asset_type, source_game)
new_asset = self.convert_asset(source_asset, details)
except Exception as e:
raise InvalidAssetId(asset_id, f"Unable to convert {asset_type}: {e}")
raise InvalidAssetId(asset_id, f"Unable to convert {details}: {e}")
self.converted_ids[(source_game, asset_id)] = new_asset.id
self._being_converted.remove(asset_id)

return new_asset

def convert_asset(self, asset, asset_type: AssetType, source_game: Game) -> ConvertedAsset:
new_asset_id = self.id_generator(asset_type)
converted_resource = self.converters(source_game, asset_type)(copy.deepcopy(asset), self)
converted_asset = ConvertedAsset(new_asset_id, asset_type, converted_resource)
def convert_asset(self, asset, details: AssetDetails) -> ConvertedAsset:
new_asset_id = self.id_generator(details)
converted_resource = self.converters(details)(copy.deepcopy(asset), details, self)
converted_asset = ConvertedAsset(new_asset_id, details.asset_type, converted_resource)

self.converted_assets[new_asset_id] = converted_asset
return converted_asset
Expand Down
8 changes: 4 additions & 4 deletions retro_data_structures/conversion/cinf.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from retro_data_structures.conversion.asset_converter import AssetConverter
from retro_data_structures.conversion.asset_converter import AssetConverter, Resource, AssetDetails
from retro_data_structures.conversion.errors import UnsupportedTargetGame, UnsupportedSourceGame
from retro_data_structures.game_check import Game


def convert_from_prime(data, converter: AssetConverter):
def convert_from_prime(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.ECHOES:
raise UnsupportedTargetGame(Game.PRIME, converter.target_game)

Expand Down Expand Up @@ -32,7 +32,7 @@ def convert_from_prime(data, converter: AssetConverter):
return data


def convert_from_echoes(data, converter: AssetConverter):
def convert_from_echoes(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.PRIME:
raise UnsupportedTargetGame(Game.ECHOES, converter.target_game)

Expand All @@ -58,7 +58,7 @@ def convert_from_echoes(data, converter: AssetConverter):
return data


def convert_from_corruption(data, converter: AssetConverter):
def convert_from_corruption(data: Resource, details: AssetDetails, converter: AssetConverter):
raise UnsupportedSourceGame(Game.CORRUPTION)


Expand Down
8 changes: 4 additions & 4 deletions retro_data_structures/conversion/cmdl.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from construct.lib import ListContainer

from retro_data_structures.conversion.asset_converter import AssetConverter
from retro_data_structures.conversion.asset_converter import AssetConverter, Resource, AssetDetails
from retro_data_structures.conversion.errors import UnsupportedTargetGame, UnsupportedSourceGame
from retro_data_structures.game_check import Game

Expand All @@ -12,7 +12,7 @@ def _convert_textures(material_set, converter: AssetConverter, source_game: Game
])


def convert_from_prime(data, converter: AssetConverter):
def convert_from_prime(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.ECHOES:
raise UnsupportedTargetGame(Game.PRIME, converter.target_game)

Expand All @@ -37,7 +37,7 @@ def convert_from_prime(data, converter: AssetConverter):
return data


def convert_from_echoes(data, converter: AssetConverter):
def convert_from_echoes(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.PRIME:
raise UnsupportedTargetGame(Game.ECHOES, converter.target_game)

Expand All @@ -63,7 +63,7 @@ def convert_from_echoes(data, converter: AssetConverter):
return data


def convert_from_corruption(data, converter: AssetConverter):
def convert_from_corruption(data: Resource, details: AssetDetails, converter: AssetConverter):
raise UnsupportedSourceGame(Game.CORRUPTION)


Expand Down
10 changes: 4 additions & 6 deletions retro_data_structures/conversion/conversions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from retro_data_structures.conversion import anim, ancs, cinf, cmdl, cskr, evnt, part, txtr
from retro_data_structures.conversion.asset_converter import ResourceConverter
from retro_data_structures.formats import AssetType
from retro_data_structures.game_check import Game
from retro_data_structures.conversion.asset_converter import ResourceConverter, AssetDetails

ALL_FORMATS = {
"ANCS": ancs.CONVERTERS,
Expand All @@ -15,10 +13,10 @@
}


def converter_for(source_game: Game, type_name: AssetType) -> ResourceConverter:
def converter_for(details: AssetDetails) -> ResourceConverter:
try:
format_converters = ALL_FORMATS[type_name.upper()]
format_converters = ALL_FORMATS[details.asset_type.upper()]
except KeyError as e:
raise KeyError(f"No conversion available for format {e}")

return format_converters[source_game]
return format_converters[details.original_game]
8 changes: 4 additions & 4 deletions retro_data_structures/conversion/cskr.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from retro_data_structures.conversion.asset_converter import AssetConverter
from retro_data_structures.conversion.asset_converter import AssetConverter, Resource, AssetDetails
from retro_data_structures.conversion.errors import UnsupportedTargetGame, UnsupportedSourceGame
from retro_data_structures.game_check import Game


def convert_from_prime(data, converter: AssetConverter):
def convert_from_prime(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.ECHOES:
raise UnsupportedTargetGame(Game.PRIME, converter.target_game)

Expand All @@ -28,7 +28,7 @@ def convert_from_prime(data, converter: AssetConverter):
return data


def convert_from_echoes(data, converter: AssetConverter):
def convert_from_echoes(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.PRIME:
raise UnsupportedTargetGame(Game.ECHOES, converter.target_game)

Expand All @@ -47,7 +47,7 @@ def convert_from_echoes(data, converter: AssetConverter):
return data


def convert_from_corruption(data, converter: AssetConverter):
def convert_from_corruption(data: Resource, details: AssetDetails, converter: AssetConverter):
raise UnsupportedSourceGame(Game.CORRUPTION)


Expand Down
8 changes: 4 additions & 4 deletions retro_data_structures/conversion/evnt.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from retro_data_structures.conversion.asset_converter import AssetConverter
from retro_data_structures.conversion.asset_converter import AssetConverter, Resource, AssetDetails
from retro_data_structures.conversion.errors import UnsupportedTargetGame, UnsupportedSourceGame
from retro_data_structures.game_check import Game

Expand All @@ -15,7 +15,7 @@ def _convert_particles(data, converter: AssetConverter, source_game: Game):
poi_node["particle"]["id"] = converter.convert_id(poi_node["particle"]["id"], source_game)


def convert_from_prime(data, converter: AssetConverter):
def convert_from_prime(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.ECHOES:
raise UnsupportedTargetGame(Game.PRIME, converter.target_game)

Expand All @@ -36,7 +36,7 @@ def convert_from_prime(data, converter: AssetConverter):
return data


def convert_from_echoes(data, converter: AssetConverter):
def convert_from_echoes(data: Resource, details: AssetDetails, converter: AssetConverter):
if converter.target_game != Game.PRIME:
raise UnsupportedTargetGame(Game.ECHOES, converter.target_game)

Expand All @@ -58,7 +58,7 @@ def convert_from_echoes(data, converter: AssetConverter):
return data


def convert_from_corruption(data, converter: AssetConverter):
def convert_from_corruption(data: Resource, details: AssetDetails, converter: AssetConverter):
raise UnsupportedSourceGame(Game.CORRUPTION)


Expand Down
9 changes: 5 additions & 4 deletions retro_data_structures/conversion/part.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import copy
import functools

from retro_data_structures.conversion.asset_converter import AssetConverter
from retro_data_structures.conversion.asset_converter import AssetConverter, Resource, AssetDetails
from retro_data_structures.game_check import Game


Expand Down Expand Up @@ -457,7 +456,9 @@ def downgrade(data, converter: AssetConverter, source_game: Game):
return data


def convert(data, converter: AssetConverter, source_game: Game):
def convert(data: Resource, details: AssetDetails, converter: AssetConverter):
source_game = details.original_game

if source_game.value < converter.target_game.value:
upgrade(data, converter, source_game)
elif source_game.value > converter.target_game.value:
Expand Down Expand Up @@ -487,7 +488,7 @@ def convert(data, converter: AssetConverter, source_game: Game):
class PARTConverter(dict):
def __missing__(self, key: Game):
if isinstance(key, Game):
return functools.partial(convert, source_game=key)
return convert
else:
raise KeyError(key)

Expand Down
4 changes: 2 additions & 2 deletions retro_data_structures/conversion/txtr.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from retro_data_structures.conversion.asset_converter import AssetConverter
from retro_data_structures.conversion.asset_converter import AssetConverter, Resource, AssetDetails
from retro_data_structures.game_check import Game


def convert_from_gx1(data, converter: AssetConverter):
def convert_from_gx1(data: Resource, details: AssetDetails, converter: AssetConverter):
# This file format only changes in Tropical Freeze
return data

Expand Down
18 changes: 18 additions & 0 deletions test/conversion/test_conversion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import pytest

from retro_data_structures.conversion import conversions
from retro_data_structures.conversion.asset_converter import AssetDetails
from retro_data_structures.game_check import Game


@pytest.mark.parametrize("asset_type", [
"ANCS", "ANIM", "CINF", "CMDL", "CSKR", "EVNT", "PART", "TXTR"
])
@pytest.mark.parametrize("game", Game)
def test_converter_for(asset_type, game: Game):
details = AssetDetails(
asset_id=None,
asset_type=asset_type,
original_game=game,
)
conversions.converter_for(details)

0 comments on commit 7a3e9d0

Please sign in to comment.