Skip to content

Desuq Cafe

문서 메뉴

이 번역은 최신 영어 원문보다 늦을 수 있습니다. 영어 버전 보기

아키텍처 및 개발자 참조

이 페이지는 플러그인을 확장하는 개발자를 위한 “내부 동작 방식” 참조 문서입니다. 모듈 구조, 핸들러 기반 클라이언트, Sequencer 통합, 에디터 디테일 패널 시스템, 주요 타입, 그리고 새 기능을 추가하는 패턴을 다룹니다.

람다 바인딩을 지원하는 네이티브 C++ 델리게이트(Native 접미사 이벤트)의 전체 목록은 Native Delegates를 참조하십시오.

모듈 구조

플러그인은 세 개의 모듈로 구성됩니다.

모듈유형목적
InhyeongOBSWebSocketRuntime핵심 기능, Subsystem, 컴포넌트, Sequencer 통합
InhyeongOBSWebSocketEditorEditor디테일 패널 커스터마이징, Editor Subsystem, Sequencer 트랙 에디터
InhyeongOBSWebSocketTakeRecorderEditorTake Recorder 동기화 (PostEngineInit 시 로드, Takes plugin 활성 시에만)

Take Recorder 동기화 설정

설정은 Config/DefaultInhyeongOBS.ini에 저장됩니다.

[/Script/InhyeongOBSWebSocketTakeRecorder.InhyeongOBSTakeRecorderSync]
bEnabled=True
bShowNotifications=True
bWarnIfOBSNotConnected=True
bAutoStartRecord=True
bAutoStopRecord=True
PostRollSeconds=0.000000
bAutoStartVirtualCam=False
bAutoStopVirtualCam=False
bAutoStartStream=False
bAutoStopStream=False
bSwitchSceneOnStart=False
StartSceneName=
bSwitchSceneOnStop=False
StopSceneName=
bCreateChaptersOnMarkedFrames=True
bAddStartChapterWithMetadata=True
bMatchRecordDirectory=False
bLogFileCorrelation=True

유틸리티 클래스

클래스위치목적
FOBSRequestBatchBuilderUtilities/배치 요청을 위한 플루언트 빌더
FOBSJsonBuilderUtilities/플루언트 JSON 오브젝트 생성

요청 유형 상수

모든 OBS WebSocket 요청 유형과 필드 이름은 Core/Types/InhyeongOBSRequestTypes.h에 집중 관리됩니다.

#include "Core/Types/InhyeongOBSRequestTypes.h"

// Request types
OBSRequests::GetSceneList            // "GetSceneList"
OBSRequests::SetCurrentProgramScene  // "SetCurrentProgramScene"
OBSRequests::StartRecord             // "StartRecord"

// Field names
OBSFields::SceneName                 // "sceneName"
OBSFields::InputName                 // "inputName"
OBSFields::SceneItemId               // "sceneItemId"

이를 통해 오타를 방지하고 프로토콜 업데이트 관리를 쉽게 합니다.

JSON 빌더 유틸리티

FOBSJsonBuilder는 OBS 요청을 위한 플루언트 JSON 생성을 제공합니다.

#include "Utilities/InhyeongOBSJsonBuilder.h"

// Basic usage
TSharedPtr<FJsonObject> Data = FOBSJsonBuilder::Create()
    .Add(TEXT("sceneName"), SceneName)
    .Add(TEXT("sceneItemId"), SceneItemId)
    .Add(TEXT("sceneItemEnabled"), true)
    .Build();

// Conditional additions
TSharedPtr<FJsonObject> Settings = FOBSJsonBuilder::Create()
    .Add(TEXT("sourceName"), SourceName)
    .Add(TEXT("imageFormat"), TEXT("png"))
    .AddIfPositive(TEXT("imageWidth"), Width)      // Only adds if > 0
    .AddIfPositive(TEXT("imageHeight"), Height)
    .AddIfInRange(TEXT("imageCompressionQuality"), Quality, 0, 100)
    .Build();

// Nested objects
TSharedPtr<FJsonObject> Transform = FOBSJsonBuilder::Create()
    .Add(TEXT("positionX"), 100.0f)
    .Add(TEXT("positionY"), 200.0f)
    .Build();

TSharedPtr<FJsonObject> Request = FOBSJsonBuilder::Create()
    .Add(TEXT("sceneName"), SceneName)
    .Add(TEXT("sceneItemId"), ItemId)
    .Add(TEXT("sceneItemTransform"), Transform)
    .Build();

사용 가능한 메서드:

메서드설명
Add(Key, Value)string, int32, int64, float, double, bool, 또는 JSON 오브젝트 추가
AddIfNotEmpty(Key, String)문자열이 비어 있지 않은 경우에만 추가
AddIfPositive(Key, Number)숫자가 0보다 클 때만 추가
AddIfInRange(Key, Value, Min, Max)값이 범위 내에 있을 때만 추가
Build()생성된 TSharedPtr<FJsonObject> 반환
HasFields()추가된 필드가 있는지 확인

핸들러 아키텍처

WebSocket 클라이언트는 체계적인 구성을 위해 모듈식 핸들러를 사용합니다.

UInhyeongOBSWebSocketClient
├── UInhyeongOBSOutputs       (Stream, Record, VirtualCam, ReplayBuffer)
├── UInhyeongOBSScenes        (Scene switching, scene items)
├── UInhyeongOBSAudio         (Audio inputs, volume, mute)
├── UInhyeongOBSInputSettings (Text, browser, image, media source settings)
├── UInhyeongOBSMediaInputs   (Media playback control)
├── UInhyeongOBSStudioMode    (Preview scene, studio transitions)
├── UInhyeongOBSTransitions   (Scene transitions, duration, settings)
├── UInhyeongOBSFilters       (Source filter management)
├── UInhyeongOBSScreenshots   (Screenshot capture and texture conversion)
├── UInhyeongOBSConfig        (Scene collections, profiles, video settings, persistent data)
└── UInhyeongOBSGeneral       (Stats, hotkeys, vendor requests, custom events)

핸들러 접근 방법:

Client->GetOutputs()
Client->GetScenes()
Client->GetAudio()
Client->GetInputSettings()
Client->GetMediaInputs()
Client->GetStudioMode()
Client->GetTransitions()
Client->GetFilters()
Client->GetScreenshots()
Client->GetConfig()
Client->GetGeneral()

Sequencer 아키텍처

Sequencer 통합은 Unreal의 Movie Scene 패턴을 따릅니다.

Runtime Module (InhyeongOBSWebSocket)
├── EventTriggersTrack/                   Discrete action tracks
│   ├── UMovieSceneOBSTrack              Track container with playback settings
│   ├── UMovieSceneOBSSection            Section with action parameters
│   ├── FMovieSceneOBSTemplate           Evaluation template (boundary detection)
│   ├── FOBSExecutionToken               Execution token for firing actions
│   └── PreAnimatedState/                State restoration handlers
│       ├── FOBSOutputPreAnimatedState
│       ├── FOBSScenesPreAnimatedState
│       ├── FOBSAudioPreAnimatedState
│       ├── FOBSTransitionsPreAnimatedState
│       ├── FOBSStudioModePreAnimatedState
│       ├── FOBSFiltersPreAnimatedState
│       └── FOBSSourcesPreAnimatedState
├── KeyframeableTrack/                   Interpolated property tracks
│   ├── Audio/
│   │   ├── UMovieSceneOBSVolumeTrack    Volume track (targets InputName)
│   │   ├── UMovieSceneOBSVolumeSection  Float channel for volume dB
│   │   ├── FMovieSceneOBSVolumeTemplate Continuous evaluation
│   │   ├── FOBSVolumePreAnimatedState   Capture/restore volume
│   │   ├── UMovieSceneOBSBalanceTrack   Balance track (targets InputName)
│   │   ├── UMovieSceneOBSBalanceSection Float channel for L/R balance
│   │   ├── FMovieSceneOBSBalanceTemplate Continuous evaluation
│   │   └── FOBSBalancePreAnimatedState  Capture/restore balance
│   ├── Scene/
│   │   ├── UMovieSceneOBSTransformTrack Transform track (targets Scene+Source)
│   │   ├── UMovieSceneOBSTransformSection Float/Int channels for transform
│   │   ├── FMovieSceneOBSTransformTemplate Continuous evaluation
│   │   └── FOBSTransformPreAnimatedState Capture/restore transform
│   ├── Sources/
│   │   ├── UMovieSceneOBSColorSourceTrack    Color source track (targets InputName)
│   │   ├── UMovieSceneOBSColorSourceSection  4 float channels for RGBA
│   │   ├── FMovieSceneOBSColorSourceTemplate Continuous evaluation, ABGR conversion
│   │   └── FOBSColorSourcePreAnimatedState   Capture/restore with format conversion
│   ├── Media/
│   │   ├── UMovieSceneOBSMediaCursorTrack    Media cursor track (targets InputName)
│   │   ├── UMovieSceneOBSMediaCursorSection  Single float channel for cursor (ms)
│   │   ├── FMovieSceneOBSMediaCursorTemplate Continuous evaluation, float→int64
│   │   └── FOBSMediaCursorPreAnimatedState   Capture/restore cursor position
│   ├── Filters/
│   │   ├── UMovieSceneOBSFilterSettingTrack    Generic filter setting track (targets Source+Filter+Setting)
│   │   ├── UMovieSceneOBSFilterSettingSection  Float channel for any numeric setting
│   │   ├── FMovieSceneOBSFilterSettingTemplate Continuous evaluation with JSON overlay
│   │   ├── FOBSFilterSettingPreAnimatedState   Capture/restore from filter cache
│   │   └── FOBSCommonFilterSettings            UI hints for known filter types
│   └── Transitions/
│       ├── UMovieSceneOBSTransitionDurationTrack    Duration track (current transition)
│       ├── UMovieSceneOBSTransitionDurationSection  Float channel for duration ms
│       ├── FMovieSceneOBSTransitionDurationTemplate Continuous evaluation, handles fixed transitions
│       └── FOBSTransitionDurationPreAnimatedState   Capture/restore duration
├── ContinuousStateTrack/                State-holding tracks (no keyframes)
│   ├── Audio/
│   │   ├── OBSMuteStatePreAnimatedState             Capture/restore mute state
│   │   ├── MovieSceneOBSMuteStateSection            Section with bMuteState property
│   │   ├── MovieSceneOBSMuteStateTrack              Track targeting InputName
│   │   ├── MovieSceneOBSMuteStateTemplate           Setup/Evaluate/TearDown
│   │   ├── OBSMonitorTypeStatePreAnimatedState      Capture/restore monitor type
│   │   ├── MovieSceneOBSMonitorTypeStateSection     Section with MonitorType enum
│   │   ├── MovieSceneOBSMonitorTypeStateTrack       Track targeting InputName
│   │   └── MovieSceneOBSMonitorTypeStateTemplate    Setup/Evaluate/TearDown
│   ├── Scene/
│   │   ├── OBSVisibilityStatePreAnimatedState       Capture/restore visibility
│   │   ├── MovieSceneOBSVisibilityStateSection      Section with bVisible property
│   │   ├── MovieSceneOBSVisibilityStateTrack        Track targeting Scene+ItemId
│   │   ├── MovieSceneOBSVisibilityStateTemplate     Setup/Evaluate/TearDown
│   │   ├── OBSBlendModeStatePreAnimatedState        Capture/restore blend mode
│   │   ├── MovieSceneOBSBlendModeStateSection       Section with BlendMode enum
│   │   ├── MovieSceneOBSBlendModeStateTrack         Track targeting Scene+ItemId
│   │   ├── MovieSceneOBSBlendModeStateTemplate      Setup/Evaluate/TearDown
│   │   ├── OBSLockStatePreAnimatedState             Capture/restore lock state
│   │   ├── MovieSceneOBSLockStateSection            Section with bLocked property
│   │   ├── MovieSceneOBSLockStateTrack              Track targeting Scene+ItemId
│   │   └── MovieSceneOBSLockStateTemplate           Setup/Evaluate/TearDown
│   ├── Filter/
│   │   ├── OBSFilterEnabledStatePreAnimatedState    Capture/restore filter enabled
│   │   ├── MovieSceneOBSFilterEnabledStateSection   Section with bEnabled property
│   │   ├── MovieSceneOBSFilterEnabledStateTrack     Track targeting Source+Filter
│   │   └── MovieSceneOBSFilterEnabledStateTemplate  Setup/Evaluate/TearDown
│   ├── StudioMode/
│   │   ├── OBSStudioModeStatePreAnimatedState       Capture/restore studio mode
│   │   ├── MovieSceneOBSStudioModeStateSection      Section with bEnabled property
│   │   ├── MovieSceneOBSStudioModeStateTrack        Global track (no target)
│   │   └── MovieSceneOBSStudioModeStateTemplate     Setup/Evaluate/TearDown
│   └── Transitions/
│       ├── OBSTransitionStatePreAnimatedState       Capture/restore current transition
│       ├── MovieSceneOBSTransitionStateSection      Section (presence = apply)
│       ├── MovieSceneOBSTransitionStateTrack        Track with TransitionName target
│       └── MovieSceneOBSTransitionStateTemplate     Setup/Evaluate/TearDown
├── MediaSyncTrack/                      Timeline-synchronized media playback
│   ├── OBSMediaSyncPreAnimatedState                 Capture/restore media state+position
│   ├── MovieSceneOBSMediaSyncSection                Section defines sync window
│   ├── MovieSceneOBSMediaSyncTrack                  Track targeting MediaInputName
│   └── MovieSceneOBSMediaSyncTemplate               Play/pause/seek synchronization
Editor Module (InhyeongOBSWebSocketEditor)
├── Sequencer/
│   ├── Shared/
│   │   └── OBSSequencerMenuRegistry         Centralized menu building (prevents duplicates)
│   ├── EventTriggersTrack/
│   │   ├── FMovieSceneOBSTrackEditor        Track editor for event trigger
│   │   └── FMovieSceneOBSSectionInterface   Section display
│   ├── KeyframeableTrack/
│   │   ├── FOBSKeyframeableTrackEditorBase  Shared base for all keyframeable editors
│   │   └── [Category]/FOBSXxxTrackEditor    Per-track editors (Volume, Balance, etc.)
│   ├── ContinuousStateTrack/
│   │   ├── FOBSContinuousStateTrackEditorBase    Shared base for all continuous state editors
│   │   ├── FOBSContinuousStateSectionInterface   Shared section display (colored bar)
│   │   └── [Category]/FOBSXxxStateTrackEditor    Per-track editors (Mute, Visibility, etc.)
│   └── MediaSyncTrack/
│       ├── FOBSMediaSyncTrackEditor         Track editor with media input picker
│       └── FOBSMediaSyncSectionInterface    Section display with offset indicator
└── DetailsCustomization/
    └── Sequencer/
        ├── EventTriggersTrack/               Action params customization
        ├── KeyframeableTrack/               Target pickers (Input, Scene+Item, etc.)
        ├── ContinuousStateTrack/            Target pickers per track type
        └── MediaSyncTrack/                  Track + Section customizations
├── FOBSSequencerActionExecutor          Routes to correct OBS client
├── FOBSSequencerActionQueue             Throttling, deduplication, batching
└── FOBSSequencerActionRegistry          Action metadata registry

주요 클래스:

클래스목적
FOBSSequencerActionRegistry40개 이상의 동작 메타데이터를 포함하는 정적 레지스트리
FOBSSequencerActionQueue33ms 스로틀링(~30fps), 중복 제거, 배치 최적화(최대 48개 동작/배치)를 갖춘 싱글턴 큐
FOBSOutputPreAnimatedState복원을 위해 재생 전 출력 상태를 캡처
FOBSSequencerActionExecutor동작을 올바른 OBS 클라이언트(Editor 또는 Game Subsystem)로 라우팅

새 Sequencer 동작 추가하기

  1. InhyeongOBSSequencerTypes.hEOBSSequencerAction에 열거형 값을 추가합니다.
  2. InhyeongOBSSequencerTypes.cppREGISTER_ACTION 블록을 추가합니다.
  3. OBSSequencerActionExecutor.cpp에 실행 케이스를 추가합니다.
  4. 배치 처리를 사용하는 경우 OBSSequencerActionQueue.cpp에 배치 요청 빌드를 추가합니다.

애니메이션 이전 상태 지원 추가하기

OBS 설정을 수정하는 State 유형 동작의 경우 복원 기능을 구현합니다.

  1. Sequencer/EventTriggersTrack/FOBS[Handler]PreAnimatedState를 생성합니다.
  2. IPersistentEvaluationData를 상속합니다.
  3. 핸들러의 캐시된 값을 사용하여 CaptureFrom()을 구현합니다(비동기 금지).
  4. 150ms 디바운스를 적용하여 RestoreTo()를 구현합니다.
  5. MovieSceneOBSTemplate::SupportsPreAnimatedState()를 업데이트하여 해당 카테고리를 포함합니다.
  6. MovieSceneOBSTemplate.cpp에 Setup/TearDown 블록을 추가합니다.

애니메이션 이전 상태 패턴:

// In Setup() - capture before section modifies OBS
FOBS[Handler]PreAnimatedState& State = PersistentData.GetOrAddSectionData();
if (!State.bHasCapturedState)
{
    State.CaptureFrom(Handler, EntryAction);
}

// In TearDown() - restore when section becomes inactive
FOBS[Handler]PreAnimatedState* State = PersistentData.FindSectionData();
if (State && State->bHasCapturedState)
{
    State->RestoreTo(Handler);
}

새 Continuous State Track 추가하기

각 Continuous State Track은 Sequencer/ContinuousStateTrack/[Handler]/에 4개의 파일이 필요합니다.

파일목적
OBS[State]PreAnimatedState.h/.cpp캡처/복원, 멱등 ApplyState()
MovieSceneOBS[State]Section.h/.cpp단순 프로퍼티(bool/enum), 채널 없음
MovieSceneOBS[State]Track.h/.cpp대상 식별 기능을 갖춘 컨테이너
MovieSceneOBS[State]Template.h/.cppSetup이 캡처, Evaluate가 적용, TearDown이 복원

중요 구현 규칙:

  1. PreAnimatedState는 IPersistentEvaluationData를 상속합니다(USTRUCT 금지).
  2. ApplyState()는 반드시 멱등이어야 합니다(전송 전 bStateIsApplied 확인).
  3. Track::CreateTemplateForSection은 직접 반환을 사용합니다(*new 금지).
  4. Section에는 FMovieSceneFloatChannel이 없으며, 단순 프로퍼티만 있습니다.
  5. Section 생성자는 EvalOptions.CompletionMode = RestoreState로 설정합니다.
  6. Template은 영구 데이터에 GetOrAddTrackData<>() / FindTrackData<>()를 사용합니다.

새 Keyframeable Track 추가하기

각 키프레임 가능한 프로퍼티는 Sequencer/KeyframeableTrack/[Category]/에 4개의 파일이 필요합니다.

파일목적
OBS[Property]PreAnimatedState.h/.cpp원래 OBS 상태 캡처/복원
MovieSceneOBS[Property]Section.h/.cppFMovieSceneFloatChannel 키프레임 저장
MovieSceneOBS[Property]Track.h/.cpp대상 식별 기능을 갖춘 컨테이너
MovieSceneOBS[Property]Template.h/.cpp연속 평가, 델타 임계값 전송

중요 구현 규칙:

  1. PreAnimatedState는 IPersistentEvaluationData를 상속합니다(USTRUCT 금지).
  2. Track::CreateTemplateForSection은 직접 반환을 사용합니다(*new 금지).
  3. Template은 영구 데이터에 GetOrAddSectionData<>() / FindSectionData<>()를 사용합니다.
  4. Setup()FOBSSequencerActionExecutor::GetClientForContext()를 통해 클라이언트를 PreAnimatedState에 캐시합니다.
  5. Evaluate()State->CachedClient.Get()에서 클라이언트를 가져옵니다(Evaluate에서 사용할 수 없는 Player 컨텍스트를 사용하지 않습니다).
  6. Evaluate()는 스로틀링/배치 처리를 위해 FOBSSequencerActionQueue::Get().EnqueueAction()을 통해 라우팅합니다.
  7. 델타 임계값 확인은 불필요한 동작 생성을 방지하기 위해 큐에 추가하기 전에 수행합니다.

Sequencer 에디터 UI

모든 트랙은 세련된 에디터 경험을 제공합니다.

트랙 아웃라이너:

  • 연결 상태 표시기(녹색/빨간색 점)
  • 플레이헤드 위치에 섹션을 추가하는 빠른 ”+” 버튼
  • FMovieSceneFloatChannel을 통한 자동 커브 에디터 통합

디테일 패널 커스터마이징:

트랙대상 선택비고
Volume / Balance오디오 입력 드롭다운오디오 가능 입력만 필터링
Transform장면 → 장면 항목 계단식장면 항목은 “SourceName (ID: 123)” 형식으로 표시
Filter Setting소스 → 필터 계단식설정 이름을 수동으로 입력(OBS 내부 키)
Transition Duration없음 (현재 전환에 적용)연결 시 현재 전환 정보 표시
Color Source색상 소스 드롭다운color_source 입력만 필터링
Media Cursor미디어 입력 드롭다운ffmpeg_source/vlc_source만 필터링

드롭다운 채우기:

  • 모든 드롭다운은 OBS 클라이언트 캐시에서 채워집니다.
  • 새로 고침 버튼은 OBS에서 전체 데이터를 새로 고침합니다.
  • 연결이 끊긴 경우 “(Connect to OBS first)” 안내 텍스트가 표시됩니다.
  • 계단식 선택 시 상위 항목이 변경되면 하위 항목이 초기화됩니다.

에디터 모듈 아키텍처

에디터 모듈은 디테일 패널 커스터마이징을 위해 섹션 빌더 패턴을 사용합니다.

FInhyeongOBSComponentCustomization
├── FOBSConnectionSectionBuilder
├── FOBSScenesSectionBuilder
├── FOBSSceneItemTransformsSectionBuilder
├── FOBSStudioModeSectionBuilder
├── FOBSTransitionsSectionBuilder
├── FOBSRecordingStreamingSectionBuilder
├── FOBSVirtualCamSectionBuilder
├── FOBSReplayBufferSectionBuilder
├── FOBSAdvancedOutputsSectionBuilder
├── FOBSAudioInputsSectionBuilder
├── FOBSMediaInputsSectionBuilder
├── FOBSInputSettingsSectionBuilder
├── FOBSFiltersSectionBuilder
├── FOBSScreenshotsSectionBuilder
├── FOBSWatchedScenesSectionBuilder
└── FOBSConfigSectionBuilder

FInhyeongOBSTriggerVolumeCustomization
├── FOBSTriggerShapeSectionBuilder
├── FOBSTriggerSettingsSectionBuilder
├── FOBSTriggerConditionsSectionBuilder
├── FOBSTriggerActionsSectionBuilder
└── FOBSTriggerTestSectionBuilder

섹션 빌더 기반 클래스

FOBSSectionBuilderBase: OBS Component 섹션의 기반 클래스:

class FOBSSectionBuilderBase : public TSharedFromThis<FOBSSectionBuilderBase>
{
public:
    void Initialize(const TSharedRef<FOBSSectionContext>& InContext);
    virtual void BuildSection(IDetailCategoryBuilder& Category) = 0;
    virtual FText GetSectionTitle() const = 0;
    virtual bool IsInitiallyCollapsed() const { return false; }
    virtual void BindToEvents() {}
    virtual void UnbindFromEvents() {}
    void RequestRefresh();

protected:
    bool IsConnected() const;
    UInhyeongOBSEditorSubsystem* GetSubsystem() const;
    UInhyeongOBSWebSocketClient* GetClient() const;
    TAttribute<bool> MakeEnabledWhenConnected() const;
};

FOBSTriggerVolumeSectionBuilderBase: Trigger Volume 섹션의 기반 클래스:

class FOBSTriggerVolumeSectionBuilderBase : public TSharedFromThis<FOBSTriggerVolumeSectionBuilderBase>
{
public:
    void Initialize(const TSharedRef<FOBSTriggerVolumeSectionContext>& InContext);
    virtual void BuildSection(IDetailCategoryBuilder& Category) = 0;
    virtual FText GetSectionTitle() const = 0;

protected:
    AInhyeongOBSTriggerVolume* GetTriggerVolume() const;
    // ... same helpers as FOBSSectionBuilderBase
};

섹션 컨텍스트 구조체

FOBSSectionContext: 컴포넌트 섹션을 위한 공유 데이터:

struct FOBSSectionContext
{
    UInhyeongOBSEditorSubsystem* Subsystem;
    UInhyeongOBSWebSocketClient* Client;
    TWeakObjectPtr<UInhyeongOBSComponent> Component;
    IDetailLayoutBuilder* DetailBuilder;
    TSharedPtr<bool> ValidityFlag;  // Set false on destruction

    bool IsValid() const;
    bool IsConnected() const;
    UInhyeongOBSOutputs* GetOutputs() const;
    UInhyeongOBSScenes* GetScenes() const;
    UInhyeongOBSAudio* GetAudio() const;
    UInhyeongOBSInputSettings* GetInputSettings() const;
    UInhyeongOBSMediaInputs* GetMediaInputs() const;
};

FOBSTriggerVolumeSectionContext: Trigger Volume 섹션을 위한 공유 데이터:

struct FOBSTriggerVolumeSectionContext
{
    UInhyeongOBSEditorSubsystem* Subsystem;
    UInhyeongOBSWebSocketClient* Client;
    TWeakObjectPtr<AInhyeongOBSTriggerVolume> TriggerVolume;
    IDetailLayoutBuilder* DetailBuilder;
    TSharedPtr<bool> ValidityFlag;

    bool IsValid() const;
    bool IsConnected() const;
    // ... handler accessors
};

주요 타입

열거형:

  • EOBSConnectionState: Disconnected, Connecting, Authenticating, Connected
  • EOBSOutputState: Starting, Started, Stopping, Stopped, Paused, Resumed 등
  • EOBSMediaInputAction: None, Play, Pause, Stop, Restart, Next, Previous
  • EOBSMediaState: Unknown, None, Playing, Paused, Stopped, Buffering, Ended, Error, Opening
  • EOBSTriggerActionType: 지원되는 모든 트리거 동작
  • EOBSTriggerShape: Box, Sphere
  • EOBSTriggerEvent: OnEnter, OnExit, Both
  • EOBSRequestBatchExecutionType: SerialRealtime, SerialFrame, Parallel
  • EOBSMonitorType: None, MonitorOnly, MonitorAndOutput

구조체:

  • FOBSScene: 장면 이름, UUID, 인덱스
  • FOBSSceneItem: 장면 내 소스 정보(잠금 상태, 블렌드 모드 포함)
  • FOBSSceneWithItems: 모든 항목을 포함한 장면
  • FOBSInput: 볼륨/음소거 정보를 포함한 입력
  • FOBSStreamStatus / FOBSRecordStatus: 타임코드를 포함한 출력 상태
  • FOBSMediaInputStatus: 미디어 상태, 재생 시간, 커서 위치
  • FOBSTriggerAction: Trigger Volume의 동작 설정
  • FOBSTriggerConditions: 트리거의 조건 설정
  • FOBSBatchRequest / FOBSBatchResult: 배치 요청/응답 데이터
  • FOBSTransition: 전환 이름, UUID, 종류, 설정 가능, 고정 플래그
  • FOBSSourceFilter: 필터 이름, 종류, 인덱스, 활성화 상태, 설정
  • FOBSCurrentTransitionInfo: 설정을 포함한 전환 세부 정보
  • FOBSSceneItemTransform: 위치, 스케일, 회전, 자르기, 경계, 소스 크기
  • EOBSBoundsType: None, Stretch, ScaleInner, ScaleOuter, ScaleToWidth, ScaleToHeight, MaxOnly
  • EOBSBlendMode: Normal, Additive, Subtract, Screen, Multiply, Lighten, Darken
  • FOBSScreenshotRequest: 스크린샷 캡처 매개변수(소스, 형식, 크기, 품질, 경로)
  • FOBSScreenshotResult: base64 이미지 데이터를 포함한 캡처 결과
  • FOBSScreenshotSavedResult: 파일 경로 확인을 포함한 저장 결과
  • FOBSSceneTransitionOverride: 장면별 전환 재정의(이름, 시간, bHasOverride)
  • FOBSProfileParameter: 매개변수 값 및 기본값
  • FOBSStreamServiceSettings: 방송 대상 설정(서버, 스트림 키, 인증)
  • FOBSAudioTracks: 트랙 1~6의 활성화 상태 및 헬퍼 메서드
  • FOBSSpecialInputs: 기본 오디오 장치 이름(Desktop1/2, Mic1~4)
  • FOBSOutput: 일반 출력 정보(이름, 종류, 크기, 활성 상태, 플래그)
  • FOBSOutputStatus: 일반 출력 상태(이름, 활성, 재연결, 타임코드, 재생 시간, 혼잡도, 바이트, 프레임)

캐시:

  • 입력 설정은 GetInputSettings()를 통해 가져온 후 UInhyeongOBSInputSettings에 캐시됩니다.
  • 캐시된 데이터에 접근하려면 GetCachedInputSettings() / GetCachedInputSettingsString()을 사용하십시오.
  • 데이터 사용 가능 여부를 확인하려면 HasCachedSettings()를 사용하십시오.
  • 캐시를 무효화하려면 ClearCachedSettings() / ClearAllCachedSettings()를 사용하십시오.

디테일 패널 커스터마이징

플러그인은 디테일 패널에 모듈식 섹션 빌더 패턴을 사용합니다.

  • FOBSSectionBuilderBase: OBS Component 섹션의 기반 클래스
  • FOBSTriggerVolumeSectionBuilderBase: Trigger Volume 섹션의 기반 클래스
  • FOBSDetailsPanelStyle: 공유 스타일 상수 및 위젯 빌더

각 섹션(연결, 장면, 녹화 등)은 별도의 빌더 클래스로 구현됩니다.

아이덴티티 리졸버 (이름 → UUID 재바인딩)

OBS는 장면 항목을 디자이너에게 보이지 않는 숫자형 SceneItemId로 관리하며, 소스 이름이 변경되면 이 ID가 바뀝니다. Core/InhyeongOBSIdentityResolver.h(OBSIdentity::FindSceneItemByName / FindSceneItemByUuids + FOBSIdentityBindingCache)는 이름으로 소스를 찾고 장면/소스 UUID를 기억하며, 이후 이름으로 찾지 못하면 UUID로 재바인딩합니다. 이를 통해 소스를 이름으로 대상으로 하는 트리거가 이름 변경 후에도 계속 작동합니다. Trigger Volume의 “Set Source Visibility” 동작에 연결되어 있으며, 캐시는 런타임 전용으로 장면 모음 변경 시 초기화됩니다.

인증

플러그인은 플랫폼 의존성 없이 SHA256 인증을 내부적으로 구현합니다. 구현 내용은 InhyeongOBSAuth.h를 참조하십시오.

요청 배치 처리

효율적인 배치 요청을 위해 FOBSRequestBatchBuilder를 사용하십시오.

FOBSRequestBatchBuilder::Create(Client)
    .SetCurrentProgramScene("Scene1")
    .StartRecord()
    .SetInputMute("Mic", false)
    .HaltOnFailure(true)
    .SetExecutionType(EOBSRequestBatchExecutionType::SerialRealtime)
    .ExecuteWithCallback([](const FOBSBatchResult& Result) {
        // Handle results
    });

사용 가능한 배치 메서드:

  • Scene: GetSceneList(), SetCurrentProgramScene(), GetCurrentProgramScene(), CreateScene(), RemoveScene(), SetSceneName(), GetSceneSceneTransitionOverride(), SetSceneSceneTransitionOverride(), SetSceneItemEnabled(), CreateSceneItem(), RemoveSceneItem(), DuplicateSceneItem(), GetSceneItemLocked(), SetSceneItemLocked(), GetSceneItemIndex(), SetSceneItemIndex(), GetSceneItemBlendMode(), SetSceneItemBlendMode()
  • Config: GetSceneCollectionList(), SetCurrentSceneCollection(), CreateSceneCollection(), GetProfileList(), SetCurrentProfile(), CreateProfile(), RemoveProfile(), GetProfileParameter(), SetProfileParameter(), GetVideoSettings(), SetVideoSettings(), SetBaseResolution(), SetOutputResolution(), SetFPS()
  • Stream: StartStream(), StopStream(), ToggleStream(), GetStreamStatus()
  • Record: StartRecord(), StopRecord(), ToggleRecord(), PauseRecord(), ResumeRecord(), GetRecordStatus()
  • VirtualCam: StartVirtualCam(), StopVirtualCam(), ToggleVirtualCam(), GetVirtualCamStatus()
  • ReplayBuffer: StartReplayBuffer(), StopReplayBuffer(), ToggleReplayBuffer(), SaveReplayBuffer(), GetReplayBufferStatus()
  • Record Directory: GetRecordDirectory(), SetRecordDirectory()
  • Record Split/Chapters: SplitRecordFile(), CreateRecordChapter()
  • Generic Outputs: GetOutputList(), GetOutputStatus(), GetOutputSettings(), SetOutputSettings(), StartOutput(), StopOutput(), ToggleOutput()
  • Stream Captions: SendStreamCaption()
  • Audio: GetInputList(), SetInputMute(), ToggleInputMute(), SetInputVolume(), GetInputKindList(), CreateInput(), RemoveInput(), RemoveInputByUuid(), SetInputName(), GetInputAudioBalance(), GetInputAudioBalanceByUuid(), SetInputAudioBalance(), SetInputAudioBalanceByUuid(), GetInputAudioSyncOffset(), GetInputAudioSyncOffsetByUuid(), SetInputAudioSyncOffset(), SetInputAudioSyncOffsetByUuid(), GetInputAudioMonitorType(), GetInputAudioMonitorTypeByUuid(), SetInputAudioMonitorType(), SetInputAudioMonitorTypeByUuid(), GetInputAudioTracks(), GetInputAudioTracksByUuid(), SetInputAudioTracks(), SetInputAudioTracksByUuid(), GetSpecialInputs()
  • Input Settings: GetInputSettings(), SetInputSettings(), GetInputDefaultSettings(), SetTextSourceText(), SetBrowserSourceUrl(), SetImageSourceFile(), SetMediaSourceFile(), SetColorSourceColor()
  • Media: TriggerMediaInputAction(), GetMediaInputStatus(), SetMediaInputCursor(), OffsetMediaInputCursor()
  • StudioMode: GetStudioModeEnabled(), SetStudioModeEnabled(), GetCurrentPreviewScene(), SetCurrentPreviewScene(), SetCurrentPreviewSceneByUuid(), TriggerStudioModeTransition()
  • Transitions: GetSceneTransitionList(), GetCurrentSceneTransition(), SetCurrentSceneTransition(), SetCurrentSceneTransitionDuration(), SetCurrentSceneTransitionSettings(), GetCurrentSceneTransitionCursor()
  • Screenshots: GetSourceScreenshot(), GetSourceScreenshotByUuid(), GetSourceScreenshotWithOptions(), SaveSourceScreenshot(), SaveSourceScreenshotByUuid(), SaveSourceScreenshotWithOptions()
  • Filters: GetSourceFilterKindList(), GetSourceFilterList(), GetSourceFilterListByUuid(), GetSourceFilter(), GetSourceFilterDefaultSettings(), CreateSourceFilter(), RemoveSourceFilter(), SetSourceFilterName(), SetSourceFilterIndex(), SetSourceFilterEnabled(), SetSourceFilterSettings()

내부 구성:

배치 빌더 구현은 유지보수성을 위해 여러 파일로 분리되어 있습니다.

파일내용
InhyeongOBSRequestBatch.cpp핵심, 설정, 실행
InhyeongOBSRequestBatch_Scenes.cpp장면 및 장면 항목 요청
InhyeongOBSRequestBatch_Outputs.cpp방송, 녹화, 가상 카메라, Replay Buffer
InhyeongOBSRequestBatch_Audio.cpp오디오, 미디어 입력, 입력 설정
InhyeongOBSRequestBatch_Filters.cpp소스 필터 관리
InhyeongOBSRequestBatch_StudioMode.cppStudio Mode 및 전환
InhyeongOBSRequestBatch_Config.cpp스크린샷, 프로필, 장면 모음, 비디오 설정

새 기능 추가하기

  1. InhyeongOBSTypes.h에 타입/델리게이트를 추가합니다.
  2. 적절한 핸들러(Outputs, Scenes, Inputs, MediaInputs)에 구현합니다.
  3. 필요한 경우 Client, Subsystem, Component에 편의 메서드를 추가합니다.
  4. 클라이언트의 ProcessOBSEvent()에서 이벤트를 처리합니다.
  5. 적절한 섹션 빌더에 UI를 추가합니다.

새 에디터 섹션 추가하기

  1. FOBSSectionBuilderBase 또는 FOBSTriggerVolumeSectionBuilderBase를 상속하는 새 섹션 빌더 클래스를 생성합니다.
  2. BuildSection(), GetSectionTitle()을 구현하고, 필요에 따라 IsInitiallyCollapsed()도 구현합니다.
  3. 섹션에 실시간 업데이트가 필요한 경우 BindToEvents()UnbindFromEvents()를 오버라이드합니다.
  4. 커스터마이징 클래스의 CreateSectionBuilders() 메서드에 빌더를 추가합니다.
  5. 일관된 스타일링을 위해 FOBSDetailsPanelStyle을 사용합니다.