Skip to content

Commit

Permalink
♻️ sync with ayon-core
Browse files Browse the repository at this point in the history
  • Loading branch information
antirotor committed Jun 7, 2024
1 parent c44fe92 commit 2490267
Show file tree
Hide file tree
Showing 54 changed files with 8,677 additions and 190 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "client/ayon_unreal/integration"]
path = client/ayon_unreal/integration
url = https://github.com/ynput/ayon-unreal-plugin.git
53 changes: 7 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,11 @@
# Addon template
This is a boilerplate git repository for creating new ayon addons.
## Unreal Engine AYON Integration

This is repository for addon to [AYON](https://ayon.ynput.io/) integration Unreal Engine Editor.

## Folder structure
All addons must have server code which is located in `server` subfolder. Server side addon definition is entrypoint for each addon. Can define settings, frontend, custom endpoints, etc. Root by default contains `create_package.py` which is a helper script that prepares package structure for server. The script may be modified or expanded by needs of addon (e.g. when frontend needs to be build first). File with `version.py` is kept at the root and is copied to server and client code with script -> The reason is to make sure both parts contain same version.
For more information go to [documentation](https://ayon.ynput.io/docs/addon_unreal_artist).

### Server content
Default base of server addon is `__init__.py` file in root of repository which define addon for server. Most of addons have settings that's why `settings.py` is by default in the structure. Settings can be changed to folder/module when more than one file is needed.
### Building

#### Server frontend
Addons may have their frontend. By default, server looks into `~/frontend/dist` for `index.html` and addon have to have specified scopes where the frontend should be showed (check documentation of `frontend_scopes` on server addon implementation for more information).

#### Private server files
Root of addon may contain subfolder `private` where can be added files that are accessible via ayon server. Url schema is `{server url}/addons/{addon name}/{addon_version}/private/*`. By default it is place where client zip file is created (during package creation). The endpoint requires authorized user.

#### Public server files
Public files works the same as private files but does not require authorized user. Subfolder name is `public`. Url schema is `{server url}/addons/{addon name}/{addon_version}/public/*`. Endpoint is helpful for images/icons or other static content.

### Client content
Addons that have code for desktop client application should create subfolder `client` where a client content is located. It is expected the directory has only one file or folder in it which is named the way how should be imported on a client side (e.g. `ayon_core`).


### Example strucutre
```
├─ server
│ ├─ frontend
│ │ └─ dist
│ │ └─ index.html
│ │
│ ├─ public
│ │ └─ my_icon.png
│ │
│ ├─ private
│ │ └─ kittens.png
│ │
│ ├─ __init__.py
│ └─ settings.py
├─ client
│ └─ openpype_core
│ ├─ pipeline
│ ├─ lib
│ └─ ...
├─ create_package.py
├─ README.md
├─ LICENSE
└─ version.py
```
- run `python ./create_package.py`
- upload resulting zip for `package` directory to your AYON server instance.
- add installed version to your bundle
9 changes: 9 additions & 0 deletions client/ayon_unreal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
## Unreal Integration

Supported Unreal Engine version is 4.26+ (mainly because of major Python changes done there).

### Project naming
Unreal doesn't support project names starting with non-alphabetic character. So names like `123_myProject` are
invalid. If Ayon detects such name it automatically prepends letter **P** to make it valid name, so `123_myProject`
will become `P123_myProject`. There is also soft-limit on project name length to be shorter than 20 characters.
Longer names will issue warning in Unreal Editor that there might be possible side effects.
10 changes: 10 additions & 0 deletions client/ayon_unreal/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from .version import __version__
from .addon import UNREAL_ADDON_ROOT, UnrealAddon


__all__ = (
"__version__",

"UNREAL_ADDON_ROOT",
"UnrealAddon",
)
77 changes: 77 additions & 0 deletions client/ayon_unreal/addon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import os
import re
from ayon_core.addon import AYONAddon, IHostAddon

from .version import __version__

UNREAL_ADDON_ROOT = os.path.dirname(os.path.abspath(__file__))


class UnrealAddon(AYONAddon, IHostAddon):
name = "unreal"
version = __version__
host_name = "unreal"

def get_global_environments(self):
return {
"AYON_UNREAL_ROOT": UNREAL_ADDON_ROOT,
}

def add_implementation_envs(self, env, app):
"""Modify environments to contain all required for implementation."""
# Set AYON_UNREAL_PLUGIN required for Unreal implementation
# Imports are in this method for Python 2 compatiblity of an addon
from pathlib import Path

from .lib import get_compatible_integration

from ayon_core.tools.utils import show_message_dialog

pattern = re.compile(r'^\d+-\d+$')

if not pattern.match(app.name):
msg = (
"Unreal application key in the settings must be in format"
"'5-0' or '5-1'"
)
show_message_dialog(
parent=None,
title="Unreal application name format",
message=msg,
level="critical")
raise ValueError(msg)

ue_version = app.name.replace("-", ".")
unreal_plugin_path = os.path.join(
UNREAL_ADDON_ROOT, "integration", "UE_{}".format(ue_version), "Ayon"
)
if not Path(unreal_plugin_path).exists():
compatible_versions = get_compatible_integration(
ue_version, Path(UNREAL_ADDON_ROOT) / "integration"
)
if compatible_versions:
unreal_plugin_path = compatible_versions[-1] / "Ayon"
unreal_plugin_path = unreal_plugin_path.as_posix()

if not env.get("AYON_UNREAL_PLUGIN") or \
env.get("AYON_UNREAL_PLUGIN") != unreal_plugin_path:
env["AYON_UNREAL_PLUGIN"] = unreal_plugin_path

# Set default environments if are not set via settings
defaults = {
"AYON_LOG_NO_COLORS": "1",
"UE_PYTHONPATH": os.environ.get("PYTHONPATH", ""),
}
for key, value in defaults.items():
if not env.get(key):
env[key] = value

def get_launch_hook_paths(self, app):
if app.host_name != self.host_name:
return []
return [
os.path.join(UNREAL_ADDON_ROOT, "hooks")
]

def get_workfile_extensions(self):
return [".uproject"]
51 changes: 51 additions & 0 deletions client/ayon_unreal/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
"""Unreal Editor Ayon host API."""

from .plugin import (
UnrealActorCreator,
UnrealAssetCreator,
Loader
)

from .pipeline import (
install,
uninstall,
ls,
publish,
containerise,
show_creator,
show_loader,
show_publisher,
show_manager,
show_experimental_tools,
show_tools_dialog,
show_tools_popup,
instantiate,
UnrealHost,
set_sequence_hierarchy,
generate_sequence,
maintained_selection
)

__all__ = [
"UnrealActorCreator",
"UnrealAssetCreator",
"Loader",
"install",
"uninstall",
"ls",
"publish",
"containerise",
"show_creator",
"show_loader",
"show_publisher",
"show_manager",
"show_experimental_tools",
"show_tools_dialog",
"show_tools_popup",
"instantiate",
"UnrealHost",
"set_sequence_hierarchy",
"generate_sequence",
"maintained_selection"
]
44 changes: 44 additions & 0 deletions client/ayon_unreal/api/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# -*- coding: utf-8 -*-
import unreal # noqa


class AyonUnrealException(Exception):
pass


@unreal.uclass()
class AyonHelpers(unreal.AyonLib):
"""Class wrapping some useful functions for Ayon.
This class is extending native BP class in Ayon Integration Plugin.
"""

@unreal.ufunction(params=[str, unreal.LinearColor, bool])
def set_folder_color(self, path: str, color: unreal.LinearColor) -> None:
"""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:
AyonHelpers().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 2490267

Please sign in to comment.