Skip to content
This repository has been archived by the owner on Oct 10, 2024. It is now read-only.

Commit

Permalink
Merge pull request #115 from antirotor/antirotor/unreal-engine-support
Browse files Browse the repository at this point in the history
Antirotor/unreal engine support
  • Loading branch information
mkolar authored Apr 3, 2020
2 parents fc6074d + c32aac6 commit dc40fb8
Show file tree
Hide file tree
Showing 4 changed files with 932 additions and 0 deletions.
40 changes: 40 additions & 0 deletions avalon/unreal/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Public API
Anything that isn't defined here is INTERNAL and unreliable for external use.
"""

from .pipeline import (
install,
uninstall,
Creator,
Loader,
ls,
publish,
containerise,
show_creator,
show_loader,
show_publisher,
show_manager,
show_project_manager,
instantiate,
)

from .lib import maintained_selection

__all__ = [
"install",
"uninstall",
"Creator",
"Loader",
"ls",
"publish",
"containerise",
"show_creator",
"show_loader",
"show_publisher",
"show_manager",
"show_project_manager",
"maintained_selection",
"instantiate",
]
200 changes: 200 additions & 0 deletions avalon/unreal/lib.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# -*- coding: utf-8 -*-

import contextlib
import unreal


@contextlib.contextmanager
def maintained_selection():
# WARNING: ❗ this is not implemented at all as I couldn't find way to
# control selection in Unreal.
previous_selection = unreal.EditorUtilityLibrary.get_selected_assets()
try:
yield
finally:
if previous_selection:
# there is no way to make selection of asset with python?
pass
else:
# And there doesn't seem to be even clear selection command?
# One in GlobalEditorUtilityBase (select_nothing) doesn't work
# for me
pass


def create_folder(root, name):
"""Create new folder
If folder exists, append number at the end and try again, incrementing
if needed.
Args:
root (str): path root
name (str): folder name
Returns:
str: folder name
Example:
>>> create_folder("/Game/Foo")
/Game/Foo
>>> create_folder("/Game/Foo")
/Game/Foo1
"""
eal = unreal.EditorAssetLibrary
index = 1
while True:
if eal.does_directory_exist("{}/{}".format(root, name)):
name = "{}{}".format(name, index)
index += 1
else:
eal.make_directory("{}/{}".format(root, name))
break

return name


def move_assets_to_path(root, name, assets):
"""
Moving (renaming) list of asset paths to new destination.
Args:
root (str): root of the path (eg. `/Game`)
name (str): name of destination directory (eg. `Foo` )
assets (list of str): list of asset paths
Returns:
str: folder name
Example:
This will get paths of all assets under `/Game/Test` and move them
to `/Game/NewTest`. If `/Game/NewTest` already exists, then resulting
path will be `/Game/NewTest1`
>>> assets = unreal.EditorAssetLibrary.list_assets("/Game/Test")
>>> move_assets_to_path("/Game", "NewTest", assets)
NewTest
"""
eal = unreal.EditorAssetLibrary
name = create_folder(root, name)

unreal.log(assets)
for asset in assets:
loaded = eal.load_asset(asset)
eal.rename_asset(
asset, "{}/{}/{}".format(root, name, loaded.get_name())
)

return name


def create_avalon_container(container, path):
"""
Helper function to create Avalon Asset Container class on given path.
This Avalon Asset Class helps to mark given path as Avalon Container
and enable asset version control on it.
Args:
name (str): Asset Container name
path (str): Path where to create Asset Container. This path should
point into container folder
Returns:
:class:`unreal.Object`: instance of created asset
Example:
AvalonHelpers().create_avalon_container(
"/Game/modelingFooCharacter_CON",
"modelingFooCharacter_CON"
)
"""
factory = unreal.AssetContainerFactory()
tools = unreal.AssetToolsHelpers().get_asset_tools()

asset = tools.create_asset(container, path, None, factory)
return asset


def create_publish_instance(instance, path):
"""
Helper function to create Avalon Publish Instance on given path.
This behaves similary as :func:`create_avalon_container`.
Args:
path (str): Path where to create Avalon Publish Instance.
This path should point into container folder
name (str): Avalon Publish Instance name
Returns:
:class:`unreal.Object`: instance of created asset
Example:
AvalonHelpers().create_publish_instance(
"/Game/modelingFooCharacter_INST",
"modelingFooCharacter_INST"
)
"""
factory = unreal.AvalonPublishInstanceFactory()
tools = unreal.AssetToolsHelpers().get_asset_tools()
asset = tools.create_asset(instance, path, None, factory)
return asset


def cast_map_to_str_dict(map):
"""
Helper function to cast Unreal Map object to plain old python
dict. This will also cast values and keys to str. Useful for
metadata dicts.
"""
return {str(key): str(value) for (key, value) in map.items()}


class AvalonUnrealException(Exception):
pass


@unreal.uclass()
class AvalonHelpers(unreal.AvalonLib):
"""
Class wrapping some useful functions for Avalon.
This class is extending native BP class in `Avalon Integration Plugin`_
.. _Avalon Integration Plugin:
https://github.com/pypeclub/avalon-unreal-integration
"""

@unreal.ufunction(params=[str, unreal.LinearColor, bool])
def set_folder_color(self, path, color, force=False):
"""
This method sets color on folder in Content Browser. Unfortunately
there is no way to refresh Content Browser so new color isn't applied
immediately. They are saved to config file and appears correctly
only after Editor is restarted.
Args:
path (str): Path to folder
color (:class:`unreal.LinearColor`): Color of the folder
Example:
AvalonHelpers().set_folder_color(
"/Game/Path", unreal.LinearColor(a=1.0, r=1.0, g=0.5, b=0)
)
Note:
This will take effect only after Editor is restarted. I couldn't
find a way to refresh it. Also this saves the color definition
into the project config, binding this path with color. So if you
delete this path and later re-create, it will set this color
again.
"""
self.c_set_folder_color(path, color, False)
Loading

0 comments on commit dc40fb8

Please sign in to comment.