mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
wip on integrating avalon functionality
This commit is contained in:
parent
9294a21635
commit
aa9df7edd5
29 changed files with 1282 additions and 14 deletions
|
|
@ -3,11 +3,12 @@ import os
|
|||
|
||||
def add_implementation_envs(env, _app):
|
||||
"""Modify environments to contain all required for implementation."""
|
||||
# Set AVALON_UNREAL_PLUGIN required for Unreal implementation
|
||||
# Set OPENPYPE_UNREAL_PLUGIN required for Unreal implementation
|
||||
unreal_plugin_path = os.path.join(
|
||||
os.environ["OPENPYPE_REPOS_ROOT"], "repos", "avalon-unreal-integration"
|
||||
os.environ["OPENPYPE_ROOT"], "openpype", "hosts",
|
||||
"unreal", "integration"
|
||||
)
|
||||
env["AVALON_UNREAL_PLUGIN"] = unreal_plugin_path
|
||||
env["OPENPYPE_UNREAL_PLUGIN"] = unreal_plugin_path
|
||||
|
||||
# Set default environments if are not set via settings
|
||||
defaults = {
|
||||
|
|
|
|||
44
openpype/hosts/unreal/api/helpers.py
Normal file
44
openpype/hosts/unreal/api/helpers.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import unreal # noqa
|
||||
|
||||
|
||||
class OpenPypeUnrealException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@unreal.uclass()
|
||||
class OpenPypeHelpers(unreal.OpenPypeLib):
|
||||
"""Class wrapping some useful functions for OpenPype.
|
||||
|
||||
This class is extending native BP class in OpenPype Integration Plugin.
|
||||
|
||||
"""
|
||||
|
||||
@unreal.ufunction(params=[str, unreal.LinearColor, bool])
|
||||
def set_folder_color(self, path: str, color: unreal.LinearColor) -> Bool:
|
||||
"""Set color on folder in Content Browser.
|
||||
|
||||
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)
|
||||
|
|
@ -169,11 +169,11 @@ def create_unreal_project(project_name: str,
|
|||
env: dict = None) -> None:
|
||||
"""This will create `.uproject` file at specified location.
|
||||
|
||||
As there is no way I know to create project via command line, this is
|
||||
easiest option. Unreal project file is basically JSON file. If we find
|
||||
`AVALON_UNREAL_PLUGIN` environment variable we assume this is location
|
||||
of Avalon Integration Plugin and we copy its content to project folder
|
||||
and enable this plugin.
|
||||
As there is no way I know to create a project via command line, this is
|
||||
easiest option. Unreal project file is basically a JSON file. If we find
|
||||
the `OPENPYPE_UNREAL_PLUGIN` environment variable we assume this is the
|
||||
location of the Integration Plugin and we copy its content to the project
|
||||
folder and enable this plugin.
|
||||
|
||||
Args:
|
||||
project_name (str): Name of the project.
|
||||
|
|
@ -254,14 +254,14 @@ def create_unreal_project(project_name: str,
|
|||
{"Name": "PythonScriptPlugin", "Enabled": True},
|
||||
{"Name": "EditorScriptingUtilities", "Enabled": True},
|
||||
{"Name": "SequencerScripting", "Enabled": True},
|
||||
{"Name": "Avalon", "Enabled": True}
|
||||
{"Name": "OpenPype", "Enabled": True}
|
||||
]
|
||||
}
|
||||
|
||||
if dev_mode or preset["dev_mode"]:
|
||||
# this will add project module and necessary source file to make it
|
||||
# C++ project and to (hopefully) make Unreal Editor to compile all
|
||||
# sources at start
|
||||
# this will add the project module and necessary source file to
|
||||
# make it a C++ project and to (hopefully) make Unreal Editor to
|
||||
# compile all # sources at start
|
||||
|
||||
data["Modules"] = [{
|
||||
"Name": project_name,
|
||||
|
|
|
|||
388
openpype/hosts/unreal/api/pipeline.py
Normal file
388
openpype/hosts/unreal/api/pipeline.py
Normal file
|
|
@ -0,0 +1,388 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import pyblish.api
|
||||
from avalon.pipeline import AVALON_CONTAINER_ID
|
||||
|
||||
import unreal # noqa
|
||||
from typing import List
|
||||
|
||||
from openpype.tools.utils import host_tools
|
||||
|
||||
from avalon import api
|
||||
|
||||
|
||||
AVALON_CONTAINERS = "OpenPypeContainers"
|
||||
|
||||
|
||||
def install():
|
||||
|
||||
pyblish.api.register_host("unreal")
|
||||
_register_callbacks()
|
||||
_register_events()
|
||||
|
||||
|
||||
def _register_callbacks():
|
||||
"""
|
||||
TODO: Implement callbacks if supported by UE4
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def _register_events():
|
||||
"""
|
||||
TODO: Implement callbacks if supported by UE4
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def uninstall():
|
||||
pyblish.api.deregister_host("unreal")
|
||||
|
||||
|
||||
class Creator(api.Creator):
|
||||
hosts = ["unreal"]
|
||||
asset_types = []
|
||||
|
||||
def process(self):
|
||||
nodes = list()
|
||||
|
||||
with unreal.ScopedEditorTransaction("Avalon Creating Instance"):
|
||||
if (self.options or {}).get("useSelection"):
|
||||
self.log.info("setting ...")
|
||||
print("settings ...")
|
||||
nodes = unreal.EditorUtilityLibrary.get_selected_assets()
|
||||
|
||||
asset_paths = [a.get_path_name() for a in nodes]
|
||||
self.name = move_assets_to_path(
|
||||
"/Game", self.name, asset_paths
|
||||
)
|
||||
|
||||
instance = create_publish_instance("/Game", self.name)
|
||||
imprint(instance, self.data)
|
||||
|
||||
return instance
|
||||
|
||||
|
||||
class Loader(api.Loader):
|
||||
hosts = ["unreal"]
|
||||
|
||||
|
||||
def ls():
|
||||
"""
|
||||
List all containers found in *Content Manager* of Unreal and return
|
||||
metadata from them. Adding `objectName` to set.
|
||||
"""
|
||||
ar = unreal.AssetRegistryHelpers.get_asset_registry()
|
||||
avalon_containers = ar.get_assets_by_class("AssetContainer", True)
|
||||
|
||||
# get_asset_by_class returns AssetData. To get all metadata we need to
|
||||
# load asset. get_tag_values() work only on metadata registered in
|
||||
# Asset Registy Project settings (and there is no way to set it with
|
||||
# python short of editing ini configuration file).
|
||||
for asset_data in avalon_containers:
|
||||
asset = asset_data.get_asset()
|
||||
data = unreal.EditorAssetLibrary.get_metadata_tag_values(asset)
|
||||
data["objectName"] = asset_data.asset_name
|
||||
data = cast_map_to_str_dict(data)
|
||||
|
||||
yield data
|
||||
|
||||
|
||||
def parse_container(container):
|
||||
"""
|
||||
To get data from container, AssetContainer must be loaded.
|
||||
|
||||
Args:
|
||||
container(str): path to container
|
||||
|
||||
Returns:
|
||||
dict: metadata stored on container
|
||||
"""
|
||||
asset = unreal.EditorAssetLibrary.load_asset(container)
|
||||
data = unreal.EditorAssetLibrary.get_metadata_tag_values(asset)
|
||||
data["objectName"] = asset.get_name()
|
||||
data = cast_map_to_str_dict(data)
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def publish():
|
||||
"""Shorthand to publish from within host"""
|
||||
import pyblish.util
|
||||
|
||||
return pyblish.util.publish()
|
||||
|
||||
|
||||
def containerise(name, namespace, nodes, context, loader=None, suffix="_CON"):
|
||||
|
||||
"""Bundles *nodes* (assets) into a *container* and add metadata to it.
|
||||
|
||||
Unreal doesn't support *groups* of assets that you can add metadata to.
|
||||
But it does support folders that helps to organize asset. Unfortunately
|
||||
those folders are just that - you cannot add any additional information
|
||||
to them. `Avalon Integration Plugin`_ is providing way out - Implementing
|
||||
`AssetContainer` Blueprint class. This class when added to folder can
|
||||
handle metadata on it using standard
|
||||
:func:`unreal.EditorAssetLibrary.set_metadata_tag()` and
|
||||
:func:`unreal.EditorAssetLibrary.get_metadata_tag_values()`. It also
|
||||
stores and monitor all changes in assets in path where it resides. List of
|
||||
those assets is available as `assets` property.
|
||||
|
||||
This is list of strings starting with asset type and ending with its path:
|
||||
`Material /Game/Avalon/Test/TestMaterial.TestMaterial`
|
||||
|
||||
.. _Avalon Integration Plugin:
|
||||
https://github.com/pypeclub/avalon-unreal-integration
|
||||
|
||||
"""
|
||||
# 1 - create directory for container
|
||||
root = "/Game"
|
||||
container_name = "{}{}".format(name, suffix)
|
||||
new_name = move_assets_to_path(root, container_name, nodes)
|
||||
|
||||
# 2 - create Asset Container there
|
||||
path = "{}/{}".format(root, new_name)
|
||||
create_container(container=container_name, path=path)
|
||||
|
||||
namespace = path
|
||||
|
||||
data = {
|
||||
"schema": "openpype:container-2.0",
|
||||
"id": AVALON_CONTAINER_ID,
|
||||
"name": new_name,
|
||||
"namespace": namespace,
|
||||
"loader": str(loader),
|
||||
"representation": context["representation"]["_id"],
|
||||
}
|
||||
# 3 - imprint data
|
||||
imprint("{}/{}".format(path, container_name), data)
|
||||
return path
|
||||
|
||||
|
||||
def instantiate(root, name, data, assets=None, suffix="_INS"):
|
||||
"""
|
||||
Bundles *nodes* into *container* marking it with metadata as publishable
|
||||
instance. If assets are provided, they are moved to new path where
|
||||
`AvalonPublishInstance` class asset is created and imprinted with metadata.
|
||||
|
||||
This can then be collected for publishing by Pyblish for example.
|
||||
|
||||
Args:
|
||||
root (str): root path where to create instance container
|
||||
name (str): name of the container
|
||||
data (dict): data to imprint on container
|
||||
assets (list of str): list of asset paths to include in publish
|
||||
instance
|
||||
suffix (str): suffix string to append to instance name
|
||||
"""
|
||||
container_name = "{}{}".format(name, suffix)
|
||||
|
||||
# if we specify assets, create new folder and move them there. If not,
|
||||
# just create empty folder
|
||||
if assets:
|
||||
new_name = move_assets_to_path(root, container_name, assets)
|
||||
else:
|
||||
new_name = create_folder(root, name)
|
||||
|
||||
path = "{}/{}".format(root, new_name)
|
||||
create_publish_instance(instance=container_name, path=path)
|
||||
|
||||
imprint("{}/{}".format(path, container_name), data)
|
||||
|
||||
|
||||
def imprint(node, data):
|
||||
loaded_asset = unreal.EditorAssetLibrary.load_asset(node)
|
||||
for key, value in data.items():
|
||||
# Support values evaluated at imprint
|
||||
if callable(value):
|
||||
value = value()
|
||||
# Unreal doesn't support NoneType in metadata values
|
||||
if value is None:
|
||||
value = ""
|
||||
unreal.EditorAssetLibrary.set_metadata_tag(
|
||||
loaded_asset, key, str(value)
|
||||
)
|
||||
|
||||
with unreal.ScopedEditorTransaction("Avalon containerising"):
|
||||
unreal.EditorAssetLibrary.save_asset(node)
|
||||
|
||||
|
||||
def show_tools_popup():
|
||||
"""Show popup with tools.
|
||||
|
||||
Popup will disappear on click or loosing focus.
|
||||
"""
|
||||
from openpype.hosts.unreal.api import tools_ui
|
||||
|
||||
tools_ui.show_tools_popup()
|
||||
|
||||
|
||||
def show_tools_dialog():
|
||||
"""Show dialog with tools.
|
||||
|
||||
Dialog will stay visible.
|
||||
"""
|
||||
from openpype.hosts.unreal.api import tools_ui
|
||||
|
||||
tools_ui.show_tools_dialog()
|
||||
|
||||
|
||||
def show_creator():
|
||||
host_tools.show_creator()
|
||||
|
||||
|
||||
def show_loader():
|
||||
host_tools.show_loader(use_context=True)
|
||||
|
||||
|
||||
def show_publisher():
|
||||
host_tools.show_publish()
|
||||
|
||||
|
||||
def show_manager():
|
||||
host_tools.show_scene_inventory()
|
||||
|
||||
|
||||
def show_experimental_tools():
|
||||
host_tools.show_experimental_tools_dialog()
|
||||
|
||||
|
||||
def create_folder(root: str, name: str) -> str:
|
||||
"""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: str, name: str, assets: List[str]) -> str:
|
||||
"""
|
||||
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_container(container: str, path: str) -> unreal.Object:
|
||||
"""
|
||||
Helper function to create Asset Container class on given path.
|
||||
This Asset Class helps to mark given path as Container
|
||||
and enable asset version control on it.
|
||||
|
||||
Args:
|
||||
container (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:
|
||||
|
||||
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: str, path: str) -> unreal.Object:
|
||||
"""
|
||||
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 Publish Instance.
|
||||
This path should point into container folder
|
||||
instance (str): Publish Instance name
|
||||
|
||||
Returns:
|
||||
:class:`unreal.Object`: instance of created asset
|
||||
|
||||
Example:
|
||||
|
||||
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) -> dict:
|
||||
"""Cast Unreal Map to dict.
|
||||
|
||||
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.
|
||||
|
||||
Args:
|
||||
map: Unreal Map object
|
||||
|
||||
Returns:
|
||||
dict
|
||||
|
||||
"""
|
||||
return {str(key): str(value) for (key, value) in map.items()}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
from avalon import api
|
||||
# -*- coding: utf-8 -*-
|
||||
from abc import ABC
|
||||
|
||||
import openpype.api
|
||||
import avalon.api
|
||||
|
||||
|
||||
class Creator(openpype.api.Creator):
|
||||
|
|
@ -7,6 +10,6 @@ class Creator(openpype.api.Creator):
|
|||
defaults = ['Main']
|
||||
|
||||
|
||||
class Loader(api.Loader):
|
||||
class Loader(avalon.api.Loader, ABC):
|
||||
"""This serves as skeleton for future OpenPype specific functionality"""
|
||||
pass
|
||||
|
|
|
|||
35
openpype/hosts/unreal/integration/.gitignore
vendored
Normal file
35
openpype/hosts/unreal/integration/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
*.smod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
/Binaries
|
||||
/Intermediate
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import unreal
|
||||
|
||||
avalon_detected = True
|
||||
try:
|
||||
from avalon import api
|
||||
from avalon import unreal as avalon_unreal
|
||||
except ImportError as exc:
|
||||
avalon_detected = False
|
||||
unreal.log_error("Avalon: cannot load avalon [ {} ]".format(exc))
|
||||
|
||||
if avalon_detected:
|
||||
api.install(avalon_unreal)
|
||||
|
||||
|
||||
@unreal.uclass()
|
||||
class AvalonIntegration(unreal.AvalonPythonBridge):
|
||||
@unreal.ufunction(override=True)
|
||||
def RunInPython_Popup(self):
|
||||
unreal.log_warning("Avalon: showing tools popup")
|
||||
if avalon_detected:
|
||||
avalon_unreal.show_tools_popup()
|
||||
|
||||
@unreal.ufunction(override=True)
|
||||
def RunInPython_Dialog(self):
|
||||
unreal.log_warning("Avalon: showing tools dialog")
|
||||
if avalon_detected:
|
||||
avalon_unreal.show_tools_dialog()
|
||||
24
openpype/hosts/unreal/integration/OpenPype.uplugin
Normal file
24
openpype/hosts/unreal/integration/OpenPype.uplugin
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"FileVersion": 3,
|
||||
"Version": 1,
|
||||
"VersionName": "1.0",
|
||||
"FriendlyName": "OpenPype",
|
||||
"Description": "OpenPype Integration",
|
||||
"Category": "OpenPype.Integration",
|
||||
"CreatedBy": "Ondrej Samohel",
|
||||
"CreatedByURL": "https://openpype.io",
|
||||
"DocsURL": "https://openpype.io/docs/artist_hosts_unreal",
|
||||
"MarketplaceURL": "",
|
||||
"SupportURL": "https://pype.club/",
|
||||
"CanContainContent": true,
|
||||
"IsBetaVersion": true,
|
||||
"IsExperimentalVersion": false,
|
||||
"Installed": false,
|
||||
"Modules": [
|
||||
{
|
||||
"Name": "OpenPype",
|
||||
"Type": "Editor",
|
||||
"LoadingPhase": "Default"
|
||||
}
|
||||
]
|
||||
}
|
||||
11
openpype/hosts/unreal/integration/README.md
Normal file
11
openpype/hosts/unreal/integration/README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# OpenPype Unreal Integration plugin
|
||||
|
||||
This is plugin for Unreal Editor, creating menu for [OpenPype](https://github.com/getavalon) tools to run.
|
||||
|
||||
## How does this work
|
||||
|
||||
Plugin is creating basic menu items in **Window/OpenPype** section of Unreal Editor main menu and a button
|
||||
on the main toolbar with associated menu. Clicking on those menu items is calling callbacks that are
|
||||
declared in c++ but needs to be implemented during Unreal Editor
|
||||
startup in `Plugins/OpenPype/Content/Python/init_unreal.py` - this should be executed by Unreal Editor
|
||||
automatically.
|
||||
BIN
openpype/hosts/unreal/integration/Resources/openpype128.png
Normal file
BIN
openpype/hosts/unreal/integration/Resources/openpype128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
openpype/hosts/unreal/integration/Resources/openpype40.png
Normal file
BIN
openpype/hosts/unreal/integration/Resources/openpype40.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.8 KiB |
BIN
openpype/hosts/unreal/integration/Resources/openpype512.png
Normal file
BIN
openpype/hosts/unreal/integration/Resources/openpype512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 84 KiB |
|
|
@ -0,0 +1,57 @@
|
|||
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class Avalon : ModuleRules
|
||||
{
|
||||
public Avalon(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add public include paths required here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PrivateIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add other private include paths required here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
// ... add other public dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Projects",
|
||||
"InputCore",
|
||||
"UnrealEd",
|
||||
"LevelEditor",
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Slate",
|
||||
"SlateCore",
|
||||
// ... add private dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
DynamicallyLoadedModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
// ... add any modules that your module loads dynamically here ...
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#include "AssetContainer.h"
|
||||
#include "AssetRegistryModule.h"
|
||||
#include "Misc/PackageName.h"
|
||||
#include "Engine.h"
|
||||
#include "Containers/UnrealString.h"
|
||||
|
||||
UAssetContainer::UAssetContainer(const FObjectInitializer& ObjectInitializer)
|
||||
: UAssetUserData(ObjectInitializer)
|
||||
{
|
||||
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
|
||||
FString path = UAssetContainer::GetPathName();
|
||||
UE_LOG(LogTemp, Warning, TEXT("UAssetContainer %s"), *path);
|
||||
FARFilter Filter;
|
||||
Filter.PackagePaths.Add(FName(*path));
|
||||
|
||||
AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UAssetContainer::OnAssetAdded);
|
||||
AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UAssetContainer::OnAssetRemoved);
|
||||
AssetRegistryModule.Get().OnAssetRenamed().AddUObject(this, &UAssetContainer::OnAssetRenamed);
|
||||
}
|
||||
|
||||
void UAssetContainer::OnAssetAdded(const FAssetData& AssetData)
|
||||
{
|
||||
TArray<FString> split;
|
||||
|
||||
// get directory of current container
|
||||
FString selfFullPath = UAssetContainer::GetPathName();
|
||||
FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath);
|
||||
|
||||
// get asset path and class
|
||||
FString assetPath = AssetData.GetFullName();
|
||||
FString assetFName = AssetData.AssetClass.ToString();
|
||||
|
||||
// split path
|
||||
assetPath.ParseIntoArray(split, TEXT(" "), true);
|
||||
|
||||
FString assetDir = FPackageName::GetLongPackagePath(*split[1]);
|
||||
|
||||
// take interest only in paths starting with path of current container
|
||||
if (assetDir.StartsWith(*selfDir))
|
||||
{
|
||||
// exclude self
|
||||
if (assetFName != "AssetContainer")
|
||||
{
|
||||
assets.Add(assetPath);
|
||||
assetsData.Add(AssetData);
|
||||
UE_LOG(LogTemp, Log, TEXT("%s: asset added to %s"), *selfFullPath, *selfDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UAssetContainer::OnAssetRemoved(const FAssetData& AssetData)
|
||||
{
|
||||
TArray<FString> split;
|
||||
|
||||
// get directory of current container
|
||||
FString selfFullPath = UAssetContainer::GetPathName();
|
||||
FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath);
|
||||
|
||||
// get asset path and class
|
||||
FString assetPath = AssetData.GetFullName();
|
||||
FString assetFName = AssetData.AssetClass.ToString();
|
||||
|
||||
// split path
|
||||
assetPath.ParseIntoArray(split, TEXT(" "), true);
|
||||
|
||||
FString assetDir = FPackageName::GetLongPackagePath(*split[1]);
|
||||
|
||||
// take interest only in paths starting with path of current container
|
||||
FString path = UAssetContainer::GetPathName();
|
||||
FString lpp = FPackageName::GetLongPackagePath(*path);
|
||||
|
||||
if (assetDir.StartsWith(*selfDir))
|
||||
{
|
||||
// exclude self
|
||||
if (assetFName != "AssetContainer")
|
||||
{
|
||||
// UE_LOG(LogTemp, Warning, TEXT("%s: asset removed"), *lpp);
|
||||
assets.Remove(assetPath);
|
||||
assetsData.Remove(AssetData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UAssetContainer::OnAssetRenamed(const FAssetData& AssetData, const FString& str)
|
||||
{
|
||||
TArray<FString> split;
|
||||
|
||||
// get directory of current container
|
||||
FString selfFullPath = UAssetContainer::GetPathName();
|
||||
FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath);
|
||||
|
||||
// get asset path and class
|
||||
FString assetPath = AssetData.GetFullName();
|
||||
FString assetFName = AssetData.AssetClass.ToString();
|
||||
|
||||
// split path
|
||||
assetPath.ParseIntoArray(split, TEXT(" "), true);
|
||||
|
||||
FString assetDir = FPackageName::GetLongPackagePath(*split[1]);
|
||||
if (assetDir.StartsWith(*selfDir))
|
||||
{
|
||||
// exclude self
|
||||
if (assetFName != "AssetContainer")
|
||||
{
|
||||
|
||||
assets.Remove(str);
|
||||
assets.Add(assetPath);
|
||||
assetsData.Remove(AssetData);
|
||||
// UE_LOG(LogTemp, Warning, TEXT("%s: asset renamed %s"), *lpp, *str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#include "AssetContainerFactory.h"
|
||||
#include "AssetContainer.h"
|
||||
|
||||
UAssetContainerFactory::UAssetContainerFactory(const FObjectInitializer& ObjectInitializer)
|
||||
: UFactory(ObjectInitializer)
|
||||
{
|
||||
SupportedClass = UAssetContainer::StaticClass();
|
||||
bCreateNew = false;
|
||||
bEditorImport = true;
|
||||
}
|
||||
|
||||
UObject* UAssetContainerFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
|
||||
{
|
||||
UAssetContainer* AssetContainer = NewObject<UAssetContainer>(InParent, Class, Name, Flags);
|
||||
return AssetContainer;
|
||||
}
|
||||
|
||||
bool UAssetContainerFactory::ShouldShowInNewMenu() const {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
#include "Avalon.h"
|
||||
#include "LevelEditor.h"
|
||||
#include "AvalonPythonBridge.h"
|
||||
#include "AvalonStyle.h"
|
||||
|
||||
|
||||
static const FName AvalonTabName("Avalon");
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FAvalonModule"
|
||||
|
||||
// This function is triggered when the plugin is staring up
|
||||
void FAvalonModule::StartupModule()
|
||||
{
|
||||
|
||||
FAvalonStyle::Initialize();
|
||||
FAvalonStyle::SetIcon("Logo", "openpype40");
|
||||
|
||||
// Create the Extender that will add content to the menu
|
||||
FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
|
||||
|
||||
TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
|
||||
TSharedPtr<FExtender> ToolbarExtender = MakeShareable(new FExtender());
|
||||
|
||||
MenuExtender->AddMenuExtension(
|
||||
"LevelEditor",
|
||||
EExtensionHook::After,
|
||||
NULL,
|
||||
FMenuExtensionDelegate::CreateRaw(this, &FAvalonModule::AddMenuEntry)
|
||||
);
|
||||
ToolbarExtender->AddToolBarExtension(
|
||||
"Settings",
|
||||
EExtensionHook::After,
|
||||
NULL,
|
||||
FToolBarExtensionDelegate::CreateRaw(this, &FAvalonModule::AddToobarEntry));
|
||||
|
||||
|
||||
LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
|
||||
LevelEditorModule.GetToolBarExtensibilityManager()->AddExtender(ToolbarExtender);
|
||||
|
||||
}
|
||||
|
||||
void FAvalonModule::ShutdownModule()
|
||||
{
|
||||
FAvalonStyle::Shutdown();
|
||||
}
|
||||
|
||||
|
||||
void FAvalonModule::AddMenuEntry(FMenuBuilder& MenuBuilder)
|
||||
{
|
||||
// Create Section
|
||||
MenuBuilder.BeginSection("OpenPype", TAttribute<FText>(FText::FromString("OpenPype")));
|
||||
{
|
||||
// Create a Submenu inside of the Section
|
||||
MenuBuilder.AddMenuEntry(
|
||||
FText::FromString("Tools..."),
|
||||
FText::FromString("Pipeline tools"),
|
||||
FSlateIcon(FAvalonStyle::GetStyleSetName(), "OpenPype.Logo"),
|
||||
FUIAction(FExecuteAction::CreateRaw(this, &FAvalonModule::MenuPopup))
|
||||
);
|
||||
|
||||
MenuBuilder.AddMenuEntry(
|
||||
FText::FromString("Tools dialog..."),
|
||||
FText::FromString("Pipeline tools dialog"),
|
||||
FSlateIcon(FAvalonStyle::GetStyleSetName(), "OpenPype.Logo"),
|
||||
FUIAction(FExecuteAction::CreateRaw(this, &FAvalonModule::MenuDialog))
|
||||
);
|
||||
|
||||
}
|
||||
MenuBuilder.EndSection();
|
||||
}
|
||||
|
||||
void FAvalonModule::AddToobarEntry(FToolBarBuilder& ToolbarBuilder)
|
||||
{
|
||||
ToolbarBuilder.BeginSection(TEXT("OpenPype"));
|
||||
{
|
||||
ToolbarBuilder.AddToolBarButton(
|
||||
FUIAction(
|
||||
FExecuteAction::CreateRaw(this, &FAvalonModule::MenuPopup),
|
||||
NULL,
|
||||
FIsActionChecked()
|
||||
|
||||
),
|
||||
NAME_None,
|
||||
LOCTEXT("OpenPype_label", "OpenPype"),
|
||||
LOCTEXT("OpenPype_tooltip", "OpenPype Tools"),
|
||||
FSlateIcon(FAvalonStyle::GetStyleSetName(), "OpenPype.Logo")
|
||||
);
|
||||
}
|
||||
ToolbarBuilder.EndSection();
|
||||
}
|
||||
|
||||
|
||||
void FAvalonModule::MenuPopup() {
|
||||
UAvalonPythonBridge* bridge = UAvalonPythonBridge::Get();
|
||||
bridge->RunInPython_Popup();
|
||||
}
|
||||
|
||||
void FAvalonModule::MenuDialog() {
|
||||
UAvalonPythonBridge* bridge = UAvalonPythonBridge::Get();
|
||||
bridge->RunInPython_Dialog();
|
||||
}
|
||||
|
||||
IMPLEMENT_MODULE(FAvalonModule, Avalon)
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#include "AvalonLib.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "Misc/ConfigCacheIni.h"
|
||||
#include "UObject/UnrealType.h"
|
||||
|
||||
/**
|
||||
* Sets color on folder icon on given path
|
||||
* @param InPath - path to folder
|
||||
* @param InFolderColor - color of the folder
|
||||
* @warning This color will appear only after Editor restart. Is there a better way?
|
||||
*/
|
||||
|
||||
void UAvalonLib::CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd)
|
||||
{
|
||||
auto SaveColorInternal = [](FString InPath, FLinearColor InFolderColor)
|
||||
{
|
||||
// Saves the color of the folder to the config
|
||||
if (FPaths::FileExists(GEditorPerProjectIni))
|
||||
{
|
||||
GConfig->SetString(TEXT("PathColor"), *InPath, *InFolderColor.ToString(), GEditorPerProjectIni);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SaveColorInternal(FolderPath, FolderColor);
|
||||
|
||||
}
|
||||
/**
|
||||
* Returns all poperties on given object
|
||||
* @param cls - class
|
||||
* @return TArray of properties
|
||||
*/
|
||||
TArray<FString> UAvalonLib::GetAllProperties(UClass* cls)
|
||||
{
|
||||
TArray<FString> Ret;
|
||||
if (cls != nullptr)
|
||||
{
|
||||
for (TFieldIterator<FProperty> It(cls); It; ++It)
|
||||
{
|
||||
FProperty* Property = *It;
|
||||
if (Property->HasAnyPropertyFlags(EPropertyFlags::CPF_Edit))
|
||||
{
|
||||
Ret.Add(Property->GetName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ret;
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#pragma once
|
||||
|
||||
#include "AvalonPublishInstance.h"
|
||||
#include "AssetRegistryModule.h"
|
||||
|
||||
|
||||
UAvalonPublishInstance::UAvalonPublishInstance(const FObjectInitializer& ObjectInitializer)
|
||||
: UObject(ObjectInitializer)
|
||||
{
|
||||
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked<FAssetRegistryModule>("AssetRegistry");
|
||||
FString path = UAvalonPublishInstance::GetPathName();
|
||||
FARFilter Filter;
|
||||
Filter.PackagePaths.Add(FName(*path));
|
||||
|
||||
AssetRegistryModule.Get().OnAssetAdded().AddUObject(this, &UAvalonPublishInstance::OnAssetAdded);
|
||||
AssetRegistryModule.Get().OnAssetRemoved().AddUObject(this, &UAvalonPublishInstance::OnAssetRemoved);
|
||||
AssetRegistryModule.Get().OnAssetRenamed().AddUObject(this, &UAvalonPublishInstance::OnAssetRenamed);
|
||||
}
|
||||
|
||||
void UAvalonPublishInstance::OnAssetAdded(const FAssetData& AssetData)
|
||||
{
|
||||
TArray<FString> split;
|
||||
|
||||
// get directory of current container
|
||||
FString selfFullPath = UAvalonPublishInstance::GetPathName();
|
||||
FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath);
|
||||
|
||||
// get asset path and class
|
||||
FString assetPath = AssetData.GetFullName();
|
||||
FString assetFName = AssetData.AssetClass.ToString();
|
||||
|
||||
// split path
|
||||
assetPath.ParseIntoArray(split, TEXT(" "), true);
|
||||
|
||||
FString assetDir = FPackageName::GetLongPackagePath(*split[1]);
|
||||
|
||||
// take interest only in paths starting with path of current container
|
||||
if (assetDir.StartsWith(*selfDir))
|
||||
{
|
||||
// exclude self
|
||||
if (assetFName != "AvalonPublishInstance")
|
||||
{
|
||||
assets.Add(assetPath);
|
||||
UE_LOG(LogTemp, Log, TEXT("%s: asset added to %s"), *selfFullPath, *selfDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UAvalonPublishInstance::OnAssetRemoved(const FAssetData& AssetData)
|
||||
{
|
||||
TArray<FString> split;
|
||||
|
||||
// get directory of current container
|
||||
FString selfFullPath = UAvalonPublishInstance::GetPathName();
|
||||
FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath);
|
||||
|
||||
// get asset path and class
|
||||
FString assetPath = AssetData.GetFullName();
|
||||
FString assetFName = AssetData.AssetClass.ToString();
|
||||
|
||||
// split path
|
||||
assetPath.ParseIntoArray(split, TEXT(" "), true);
|
||||
|
||||
FString assetDir = FPackageName::GetLongPackagePath(*split[1]);
|
||||
|
||||
// take interest only in paths starting with path of current container
|
||||
FString path = UAvalonPublishInstance::GetPathName();
|
||||
FString lpp = FPackageName::GetLongPackagePath(*path);
|
||||
|
||||
if (assetDir.StartsWith(*selfDir))
|
||||
{
|
||||
// exclude self
|
||||
if (assetFName != "AvalonPublishInstance")
|
||||
{
|
||||
// UE_LOG(LogTemp, Warning, TEXT("%s: asset removed"), *lpp);
|
||||
assets.Remove(assetPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UAvalonPublishInstance::OnAssetRenamed(const FAssetData& AssetData, const FString& str)
|
||||
{
|
||||
TArray<FString> split;
|
||||
|
||||
// get directory of current container
|
||||
FString selfFullPath = UAvalonPublishInstance::GetPathName();
|
||||
FString selfDir = FPackageName::GetLongPackagePath(*selfFullPath);
|
||||
|
||||
// get asset path and class
|
||||
FString assetPath = AssetData.GetFullName();
|
||||
FString assetFName = AssetData.AssetClass.ToString();
|
||||
|
||||
// split path
|
||||
assetPath.ParseIntoArray(split, TEXT(" "), true);
|
||||
|
||||
FString assetDir = FPackageName::GetLongPackagePath(*split[1]);
|
||||
if (assetDir.StartsWith(*selfDir))
|
||||
{
|
||||
// exclude self
|
||||
if (assetFName != "AssetContainer")
|
||||
{
|
||||
|
||||
assets.Remove(str);
|
||||
assets.Add(assetPath);
|
||||
// UE_LOG(LogTemp, Warning, TEXT("%s: asset renamed %s"), *lpp, *str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#include "AvalonPublishInstanceFactory.h"
|
||||
#include "AvalonPublishInstance.h"
|
||||
|
||||
UAvalonPublishInstanceFactory::UAvalonPublishInstanceFactory(const FObjectInitializer& ObjectInitializer)
|
||||
: UFactory(ObjectInitializer)
|
||||
{
|
||||
SupportedClass = UAvalonPublishInstance::StaticClass();
|
||||
bCreateNew = false;
|
||||
bEditorImport = true;
|
||||
}
|
||||
|
||||
UObject* UAvalonPublishInstanceFactory::FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn)
|
||||
{
|
||||
UAvalonPublishInstance* AvalonPublishInstance = NewObject<UAvalonPublishInstance>(InParent, Class, Name, Flags);
|
||||
return AvalonPublishInstance;
|
||||
}
|
||||
|
||||
bool UAvalonPublishInstanceFactory::ShouldShowInNewMenu() const {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#include "AvalonPythonBridge.h"
|
||||
|
||||
UAvalonPythonBridge* UAvalonPythonBridge::Get()
|
||||
{
|
||||
TArray<UClass*> AvalonPythonBridgeClasses;
|
||||
GetDerivedClasses(UAvalonPythonBridge::StaticClass(), AvalonPythonBridgeClasses);
|
||||
int32 NumClasses = AvalonPythonBridgeClasses.Num();
|
||||
if (NumClasses > 0)
|
||||
{
|
||||
return Cast<UAvalonPythonBridge>(AvalonPythonBridgeClasses[NumClasses - 1]->GetDefaultObject());
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#include "AvalonStyle.h"
|
||||
#include "Framework/Application/SlateApplication.h"
|
||||
#include "Styling/SlateStyle.h"
|
||||
#include "Styling/SlateStyleRegistry.h"
|
||||
|
||||
|
||||
TUniquePtr< FSlateStyleSet > FAvalonStyle::AvalonStyleInstance = nullptr;
|
||||
|
||||
void FAvalonStyle::Initialize()
|
||||
{
|
||||
if (!AvalonStyleInstance.IsValid())
|
||||
{
|
||||
AvalonStyleInstance = Create();
|
||||
FSlateStyleRegistry::RegisterSlateStyle(*AvalonStyleInstance);
|
||||
}
|
||||
}
|
||||
|
||||
void FAvalonStyle::Shutdown()
|
||||
{
|
||||
if (AvalonStyleInstance.IsValid())
|
||||
{
|
||||
FSlateStyleRegistry::UnRegisterSlateStyle(*AvalonStyleInstance);
|
||||
AvalonStyleInstance.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
FName FAvalonStyle::GetStyleSetName()
|
||||
{
|
||||
static FName StyleSetName(TEXT("AvalonStyle"));
|
||||
return StyleSetName;
|
||||
}
|
||||
|
||||
FName FAvalonStyle::GetContextName()
|
||||
{
|
||||
static FName ContextName(TEXT("OpenPype"));
|
||||
return ContextName;
|
||||
}
|
||||
|
||||
#define IMAGE_BRUSH(RelativePath, ...) FSlateImageBrush( Style->RootToContentDir( RelativePath, TEXT(".png") ), __VA_ARGS__ )
|
||||
|
||||
const FVector2D Icon40x40(40.0f, 40.0f);
|
||||
|
||||
TUniquePtr< FSlateStyleSet > FAvalonStyle::Create()
|
||||
{
|
||||
TUniquePtr< FSlateStyleSet > Style = MakeUnique<FSlateStyleSet>(GetStyleSetName());
|
||||
Style->SetContentRoot(FPaths::ProjectPluginsDir() / TEXT("Avalon/Resources"));
|
||||
|
||||
return Style;
|
||||
}
|
||||
|
||||
void FAvalonStyle::SetIcon(const FString& StyleName, const FString& ResourcePath)
|
||||
{
|
||||
FSlateStyleSet* Style = AvalonStyleInstance.Get();
|
||||
|
||||
FString Name(GetContextName().ToString());
|
||||
Name = Name + "." + StyleName;
|
||||
Style->Set(*Name, new FSlateImageBrush(Style->RootToContentDir(ResourcePath, TEXT(".png")), Icon40x40));
|
||||
|
||||
|
||||
FSlateApplication::Get().GetRenderer()->ReloadTextureResources();
|
||||
}
|
||||
|
||||
#undef IMAGE_BRUSH
|
||||
|
||||
const ISlateStyle& FAvalonStyle::Get()
|
||||
{
|
||||
check(AvalonStyleInstance);
|
||||
return *AvalonStyleInstance;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "UObject/NoExportTypes.h"
|
||||
#include "Engine/AssetUserData.h"
|
||||
#include "AssetData.h"
|
||||
#include "AssetContainer.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS(Blueprintable)
|
||||
class AVALON_API UAssetContainer : public UAssetUserData
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UAssetContainer(const FObjectInitializer& ObjectInitalizer);
|
||||
// ~UAssetContainer();
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||||
TArray<FString> assets;
|
||||
|
||||
// There seems to be no reflection option to expose array of FAssetData
|
||||
/*
|
||||
UPROPERTY(Transient, BlueprintReadOnly, Category = "Python", meta=(DisplayName="Assets Data"))
|
||||
TArray<FAssetData> assetsData;
|
||||
*/
|
||||
private:
|
||||
TArray<FAssetData> assetsData;
|
||||
void OnAssetAdded(const FAssetData& AssetData);
|
||||
void OnAssetRemoved(const FAssetData& AssetData);
|
||||
void OnAssetRenamed(const FAssetData& AssetData, const FString& str);
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Fill out your copyright notice in the Description page of Project Settings.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Factories/Factory.h"
|
||||
#include "AssetContainerFactory.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class AVALON_API UAssetContainerFactory : public UFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UAssetContainerFactory(const FObjectInitializer& ObjectInitializer);
|
||||
virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
|
||||
virtual bool ShouldShowInNewMenu() const override;
|
||||
};
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine.h"
|
||||
|
||||
|
||||
class FAvalonModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
|
||||
private:
|
||||
|
||||
void AddMenuEntry(FMenuBuilder& MenuBuilder);
|
||||
void AddToobarEntry(FToolBarBuilder& ToolbarBuilder);
|
||||
void MenuPopup();
|
||||
void MenuDialog();
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "Engine.h"
|
||||
#include "AvalonLib.generated.h"
|
||||
|
||||
|
||||
UCLASS(Blueprintable)
|
||||
class AVALON_API UAvalonLib : public UObject
|
||||
{
|
||||
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, Category = Python)
|
||||
static void CSetFolderColor(FString FolderPath, FLinearColor FolderColor, bool bForceAdd);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = Python)
|
||||
static TArray<FString> GetAllProperties(UClass* cls);
|
||||
};
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "Engine.h"
|
||||
#include "AvalonPublishInstance.generated.h"
|
||||
|
||||
|
||||
UCLASS(Blueprintable)
|
||||
class AVALON_API UAvalonPublishInstance : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UAvalonPublishInstance(const FObjectInitializer& ObjectInitalizer);
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly)
|
||||
TArray<FString> assets;
|
||||
private:
|
||||
void OnAssetAdded(const FAssetData& AssetData);
|
||||
void OnAssetRemoved(const FAssetData& AssetData);
|
||||
void OnAssetRenamed(const FAssetData& AssetData, const FString& str);
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Factories/Factory.h"
|
||||
#include "AvalonPublishInstanceFactory.generated.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
UCLASS()
|
||||
class AVALON_API UAvalonPublishInstanceFactory : public UFactory
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UAvalonPublishInstanceFactory(const FObjectInitializer& ObjectInitializer);
|
||||
virtual UObject* FactoryCreateNew(UClass* Class, UObject* InParent, FName Name, EObjectFlags Flags, UObject* Context, FFeedbackContext* Warn) override;
|
||||
virtual bool ShouldShowInNewMenu() const override;
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
#include "Engine.h"
|
||||
#include "AvalonPythonBridge.generated.h"
|
||||
|
||||
UCLASS(Blueprintable)
|
||||
class UAvalonPythonBridge : public UObject
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
UFUNCTION(BlueprintCallable, Category = Python)
|
||||
static UAvalonPythonBridge* Get();
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = Python)
|
||||
void RunInPython_Popup() const;
|
||||
|
||||
UFUNCTION(BlueprintImplementableEvent, Category = Python)
|
||||
void RunInPython_Dialog() const;
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include "CoreMinimal.h"
|
||||
|
||||
class FSlateStyleSet;
|
||||
class ISlateStyle;
|
||||
|
||||
|
||||
class FAvalonStyle
|
||||
{
|
||||
public:
|
||||
static void Initialize();
|
||||
static void Shutdown();
|
||||
static const ISlateStyle& Get();
|
||||
static FName GetStyleSetName();
|
||||
static FName GetContextName();
|
||||
|
||||
static void SetIcon(const FString& StyleName, const FString& ResourcePath);
|
||||
|
||||
private:
|
||||
static TUniquePtr< FSlateStyleSet > Create();
|
||||
static TUniquePtr< FSlateStyleSet > AvalonStyleInstance;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue