Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

플러그인 가져오기

참고

이 튜토리얼에서는 여러분이 일반 플러그인을 만드는 방법을 이미 알고 있다고 가정합니다. 의심스러운 경우 플러그인 만들기 페이지를 참조하세요. 이는 또한 당신이 Godot의 가져오기 시스템에 대해 잘 알고 있다고 가정합니다.

소개

가져오기 플러그인은 사용자 정의 리소스를 Godot로 가져오고 일류 리소스로 처리할 수 있도록 하는 특별한 유형의 편집기 도구입니다. 편집기 자체에는 PNG 이미지, Collada 및 glTF 모델, Ogg Vorbis 사운드 등과 같은 일반적인 리소스를 처리하기 위한 많은 가져오기 플러그인이 번들로 제공됩니다.

이 튜토리얼에서는 사용자 정의 텍스트 파일을 재료 리소스로 로드하기 위해 가져오기 플러그인을 생성하는 방법을 보여줍니다. 이 텍스트 파일에는 색상의 세 채널을 나타내는 쉼표로 구분된 세 개의 숫자 값이 포함되며 결과 색상은 가져온 재질의 알베도(기본 색상)로 사용됩니다. 이 예에서는 순수한 파란색(빨간색 0, 녹색 0, 전체 파란색)이 포함되어 있습니다.

0,0,255

구성

먼저 가져오기 플러그인의 초기화 및 삭제를 처리할 일반 플러그인이 필요합니다. 먼저 plugin.cfg 파일을 추가해 보겠습니다.

[plugin]

name="Silly Material Importer"
description="Imports a 3D Material from an external text file."
author="Yours Truly"
version="1.0"
script="material_import.gd"

그런 다음 필요할 때 가져오기 플러그인을 추가하고 제거하려면 material_import.gd 파일이 필요합니다.

# material_import.gd
@tool
extends EditorPlugin


var import_plugin


func _enter_tree():
    import_plugin = preload("import_plugin.gd").new()
    add_import_plugin(import_plugin)


func _exit_tree():
    remove_import_plugin(import_plugin)
    import_plugin = null

이 플러그인이 활성화되면 가져오기 플러그인(곧 만들 예정)의 새 인스턴스가 생성되고 add_import_plugin() 메서드를 사용하여 편집기에 추가됩니다. 나중에 제거할 때 참조할 수 있도록 클래스 멤버 ``import_plugin``에 이에 대한 참조를 저장합니다. remove_import_plugin() 메서드는 메모리를 정리하고 편집기에 가져오기 플러그인을 더 이상 사용할 수 없음을 알리기 위해 플러그인이 비활성화될 때 호출됩니다.

가져오기 플러그인은 참조 유형이므로 free() 함수를 사용하여 메모리에서 명시적으로 해제할 필요가 없습니다. 범위를 벗어나면 엔진에 의해 자동으로 해제됩니다.

EditorImportPlugin 클래스

쇼의 주인공은 :ref:`EditorImportPlugin 클래스 <class_EditorImportPlugin>`입니다. 파일을 다루는 방법을 알아야 할 때 Godot가 호출하는 메소드를 구현하는 일을 담당합니다.

한 번에 한 가지 방법으로 플러그인 코딩을 시작해 보겠습니다.

# import_plugin.gd
@tool
extends EditorImportPlugin


func _get_importer_name():
    return "demos.sillymaterial"

첫 번째 방법은 :ref:`_get_importer_name()<class_EditorImportPlugin_private_method__get_importer_name>`입니다. 이것은 특정 파일에서 어떤 가져오기가 사용되었는지 알기 위해 Godot가 사용하는 플러그인의 고유한 이름입니다. 파일을 다시 가져와야 하는 경우 편집기는 어떤 플러그인을 호출해야 하는지 알 수 있습니다.

func _get_visible_name():
    return "Silly Material"

_get_visible_name() 메소드는 가져오는 유형의 이름을 반환하는 역할을 하며 가져오기 도크에서 사용자에게 표시됩니다.

"다음으로 가져오기"에 이어 이 이름을 선택해야 합니다. "바보 재질로 가져오기". 원하는 대로 이름을 지정할 수 있지만 플러그인을 설명하는 이름을 사용하는 것이 좋습니다.

func _get_recognized_extensions():
    return ["mtxt"]

Godot의 가져오기 시스템은 확장자로 파일 유형을 감지합니다. _get_recognized_extensions() 메소드에서는 이 플러그인이 이해할 수 있는 각 확장을 나타내는 문자열 배열을 반환합니다. 확장자가 두 개 이상의 플러그인에서 인식되는 경우 사용자는 파일을 가져올 때 사용할 플러그인을 선택할 수 있습니다.

.json``.txt``와 같은 일반적인 확장은 많은 플러그인에서 사용될 수 있습니다. 또한 프로젝트에는 단지 게임용 데이터이므로 가져오면 안되는 파일이 있을 수 있습니다. 데이터의 유효성을 검사하려면 가져올 때 주의해야 합니다. 파일의 형식이 올바르다고 기대하지 마십시오.

func _get_save_extension():
    return "material"

가져온 파일은 프로젝트 루트의 .import 폴더에 저장됩니다. 해당 확장은 가져오는 리소스 유형과 일치해야 하지만 Godot는 무엇을 사용할지 알 수 없기 때문에(동일한 리소스에 대해 유효한 확장이 여러 개 있을 수 있으므로) 가져오기에 사용할 항목을 선언해야 합니다.

머티리얼을 가져오는 중이므로 이러한 리소스 유형에 대한 특수 확장을 사용하겠습니다. 씬을 가져오는 경우 scn``를 사용할 있습니다. 일반 리소스는 ``res 확장을 사용할 수 있습니다. 그러나 이는 엔진에 의해 어떤 방식으로든 강제되지 않습니다.

func _get_resource_type():
    return "StandardMaterial3D"

가져온 리소스에는 특정 유형이 있으므로 편집자는 해당 리소스가 속한 속성 슬롯을 알 수 있습니다. 이를 통해 FileSystem 도크에서 인스펙터의 속성으로 끌어서 놓을 수 있습니다.

우리의 경우에는 3D 개체에 적용할 수 있는 :ref:`class_StandardMaterial3D`입니다.

참고

동일한 확장에서 다른 유형을 가져와야 하는 경우 여러 가져오기 플러그인을 만들어야 합니다. 이와 관련하여 중복을 피하기 위해 다른 파일에서 가져오기 코드를 추상화할 수 있습니다.

옵션 및 사전 설정

플러그인은 사용자가 리소스를 가져오는 방법을 제어할 수 있도록 다양한 옵션을 제공할 수 있습니다. 선택한 옵션 세트가 공통적인 경우 사용자가 더 쉽게 사용할 수 있도록 다양한 사전 설정을 만들 수도 있습니다. 다음 이미지는 편집기에 옵션이 표시되는 방식을 보여줍니다.

../../../_images/import_plugin_options.png

사전 설정이 많을 수 있고 번호로 식별되므로 이름을 사용하여 참조할 수 있도록 열거형을 사용하는 것이 좋습니다.

@tool
extends EditorImportPlugin


enum Presets { DEFAULT }


...

이제 열거형이 정의되었으므로 가져오기 플러그인의 메서드를 계속 살펴보겠습니다.

func _get_preset_count():
    return Presets.size()

_get_preset_count() 메서드는 이 플러그인이 정의하는 사전 설정의 양을 반환합니다. 현재는 하나의 사전 설정만 있지만 Presets 열거형의 크기를 반환하여 이 방법을 미래에도 사용할 수 있도록 만들 수 있습니다.

func _get_preset_name(preset_index):
    match preset_index:
        Presets.DEFAULT:
            return "Default"
        _:
            return "Unknown"

여기에는 사용자에게 표시될 사전 설정에 이름을 제공하는 _get_preset_name() 메서드가 있으므로 짧고 명확한 이름을 사용해야 합니다.

여기서 match 문을 사용하여 코드를 더욱 구조화할 수 있습니다. 이렇게 하면 나중에 새로운 사전 설정을 쉽게 추가할 수 있습니다. 우리는 무언가를 반환하기 위해 catch all 패턴을 사용합니다. Godot는 정의한 사전 설정 수를 초과하는 사전 설정을 요구하지 않지만 항상 안전한 편에 있는 것이 좋습니다.

사전 설정이 하나만 있는 경우 해당 이름을 직접 반환하면 되지만, 이렇게 하면 사전 설정을 더 추가할 때 주의해야 합니다.

func _get_import_options(path, preset_index):
    match preset_index:
        Presets.DEFAULT:
            return [{
                       "name": "use_red_anyway",
                       "default_value": false
                    }]
        _:
            return []

이는 사용 가능한 옵션을 정의하는 방법입니다. :ref:`_get_import_options() <class_EditorImportPlugin_private_method__get_import_options>`는 사전 배열을 반환하며 각 사전에는 사용자에게 표시되는 옵션을 사용자 정의하기 위해 확인되는 몇 가지 키가 포함되어 있습니다. 다음 표에는 가능한 키가 나와 있습니다.

유형

설명

name

String

옵션의 이름입니다. 표시되면 밑줄은 공백이 되고 첫 글자는 대문자로 표시됩니다.

default_value

모두

이 사전 설정에 대한 옵션의 기본값입니다.

property_hint

열거형 값

힌트로 사용할 PropertyHint 값 중 하나입니다.

hint_string

String

속성의 힌트 텍스트입니다. GDScript의 export 문에 추가하는 것과 동일합니다.

usage

열거형 값

사용법을 정의하는 PropertyUsageFlags 값 중 하나입니다.

namedefault_value 키는 **필수**이고 나머지는 선택사항입니다.

_get_import_options 방법은 사전 설정 번호를 수신하므로 각 사전 설정(특히 기본값)에 대한 옵션을 구성할 수 있습니다. 이 예에서는 match 문을 사용하지만 옵션이 많고 사전 설정이 값만 변경하는 경우 먼저 옵션 배열을 만든 다음 사전 설정에 따라 변경할 수 있습니다.

경고

사전 설정을 정의하지 않은 경우에도(_get_preset_count``가 0을 반환하도록 하여) ``_get_import_options 메서드가 호출됩니다. 비어 있는 배열이라도 반환해야 합니다. 그렇지 않으면 오류가 발생할 수 있습니다.

func _get_option_visibility(path, option_name, options):
    return true

_get_option_visibility() 메소드의 경우 모든 옵션(즉, 정의한 단일 옵션)이 항상 표시되므로 간단히 ``true``를 반환합니다.

다른 옵션이 특정 값으로 설정된 경우에만 특정 옵션을 표시해야 하는 경우 이 메서드에 논리를 추가할 수 있습니다.

import 방법

파일을 리소스로 변환하는 프로세스의 중요한 부분은 _import() 메서드에서 다룹니다. 샘플 코드가 약간 길기 때문에 몇 부분으로 나누어 보겠습니다.

func _import(source_file, save_path, options, r_platform_variants, r_gen_files):
    var file = FileAccess.open(source_file, FileAccess.READ)
    if file == null:
        return FileAccess.get_open_error()

    var line = file.get_line()

가져오기 방법의 첫 번째 부분은 소스 파일을 열고 읽습니다. 이를 수행하기 위해 FileAccess 클래스를 사용하고 편집기에서 제공하는 source_file 매개변수를 전달합니다.

파일을 열 때 오류가 발생하면 해당 파일을 반환하여 가져오기가 성공하지 못했다는 사실을 편집자에게 알립니다.

var channels = line.split(",")
if channels.size() != 3:
    return ERR_PARSE_ERROR

var color
if options.use_red_anyway:
    color = Color.from_rgba8(255, 0, 0)
else:
    color = Color.from_rgba8(int(channels[0]), int(channels[1]), int(channels[2]))

이 코드는 이전에 읽은 파일의 줄을 가져와서 쉼표로 구분된 조각으로 나눕니다. 세 값보다 많거나 적으면 파일이 유효하지 않은 것으로 간주하고 오류를 보고합니다.

그런 다음 새 Color 변수를 생성하고 입력 파일에 따라 해당 값을 설정합니다. use_red_anyway 옵션이 활성화되면 색상이 대신 순수한 빨간색으로 설정됩니다.

var material = StandardMaterial3D.new()
material.albedo_color = color

이 부분은 가져온 리소스인 새로운 :ref:`StandardMaterial3D <class_StandardMaterial3D>`을 만듭니다. 새로운 인스턴스를 생성한 다음 알베도 색상을 이전에 얻은 값으로 설정합니다.

return ResourceSaver.save(material, "%s.%s" % [save_path, _get_save_extension()])

이것은 마지막 부분이자 매우 중요한 부분입니다. 여기서는 만들어진 리소스를 디스크에 저장하기 때문입니다. 저장된 파일의 경로는 save_path 매개변수를 통해 편집기에서 생성되고 알려집니다. 이는 확장명 없이 **제공되므로 문자열 형식 <doc_gdscript_printf>`을 사용하여 추가합니다. 이를 위해 이전에 정의한 ``_get_save_extension` 메서드를 호출하므로 동기화가 중단되지 않도록 할 수 있습니다.

또한 ResourceSaver.save() 메서드의 결과를 반환하므로 이 단계에서 오류가 있으면 편집자가 이를 알 수 있습니다.

플랫폼 변형 및 생성된 파일

우리 플러그인이 import 메소드의 두 인수를 무시했다는 것을 눈치채셨을 것입니다. 이는 *반환 인수*입니다(따라서 이름 시작 부분에 ``r``가 있음). 이는 편집기가 가져오기 메소드를 호출한 후 해당 인수에서 읽을 것임을 의미합니다. 둘 다 정보로 채울 수 있는 배열입니다.

대상 플랫폼에 따라 리소스를 다르게 가져와야 하는 경우 r_platform_variants 인수가 사용됩니다. 플랫폼 변형이라고 부르지만 :ref:`feature 태그 <doc_feature_tags>`의 존재를 기반으로 하므로 동일한 플랫폼이라도 설정에 따라 여러 변형이 있을 수 있습니다.

플랫폼 변형을 가져오려면 확장 앞에 기능 태그를 사용하여 저장한 다음 해당 태그를 r_platform_variants 배열에 푸시하여 편집자가 이를 알 수 있도록 해야 합니다.

예를 들어, 모바일 플랫폼을 위해 다른 자료를 저장한다고 가정해 보겠습니다. 우리는 다음과 같은 작업을 수행해야 합니다.

r_platform_variants.push_back("mobile")
return ResourceSaver.save(mobile_material, "%s.%s.%s" % [save_path, "mobile", _get_save_extension()])

r_gen_files 인수는 가져오기 프로세스 중에 생성되어 보관해야 하는 추가 파일을 위한 것입니다. 편집자는 이를 확인하여 종속성을 이해하고 추가 파일이 실수로 삭제되지 않았는지 확인합니다.

이 역시 배열이므로 저장하는 파일의 전체 경로로 채워져야 합니다. 예를 들어, 다음 패스를 위한 또 다른 재질을 만들고 이를 다른 파일에 저장해 보겠습니다.

var next_pass = StandardMaterial3D.new()
next_pass.albedo_color = color.inverted()
var next_pass_path = "%s.next_pass.%s" % [save_path, _get_save_extension()]

err = ResourceSaver.save(next_pass, next_pass_path)
if err != OK:
    return err
r_gen_files.push_back(next_pass_path)

플러그인 사용해 보기

이는 이론적이었지만 이제 가져오기 플러그인이 완료되었으므로 테스트해 보겠습니다. 소개 섹션에 설명된 내용으로 샘플 파일을 생성했는지 확인하고 ``test.mtxt``로 저장합니다. 그런 다음 프로젝트 설정에서 플러그인을 활성화하십시오.

모든 것이 순조롭게 진행되면 가져오기 플러그인이 편집기에 추가되고 파일 시스템이 스캔되어 사용자 정의 리소스가 FileSystem 도크에 표시됩니다. 이를 선택하고 Import Dock에 초점을 맞추면 거기서 선택할 수 있는 유일한 옵션을 볼 수 있습니다.

만들기는 씬의 MeshInstance3D 노드이고 해당 Mesh 속성에 대해 새 SphereMesh를 설정합니다. 인스펙터에서 Material 섹션을 펼친 다음 FileSystem 도크에서 재질 속성으로 파일을 드래그합니다. 객체는 가져온 재질의 파란색으로 뷰포트에서 업데이트됩니다.

../../../_images/import_plugin_trying.png

가져오기 도크로 이동하여 "어쨌든 Red 사용" 옵션을 활성화하고 "다시 가져오기"를 클릭하세요. 이렇게 하면 가져온 재질이 업데이트되고 대신 빨간색을 표시하는 뷰가 자동으로 업데이트됩니다.

그리고 그게 다야! 첫 번째 가져오기 플러그인이 완료되었습니다! 이제 창의력을 발휘하여 자신이 좋아하는 형식에 맞는 플러그인을 만들어보세요. 이는 사용자 정의 형식으로 데이터를 작성한 다음 마치 원시 리소스인 것처럼 Godot에서 사용하는 데 매우 유용할 수 있습니다. 이는 가져오기 시스템이 얼마나 강력하고 확장 가능한지 보여줍니다.