- Replaced the single-stream runner with endpoint-scoped StreamHub sessions:
each exact PONG endpoint receives one unicast STREAM session, while logical
sources on that endpoint are mixed independently with gain/pan/loop/stop. - Stream output is normalized to 16 kHz stereo PCM16. Unresolved sources stay
Deferred(NoResolvedEndpoint)and never broadcast STREAM packets; empty
endpoint sessions linger for 300 ms before END. - An unambiguous logical-route change now migrates its endpoint session in
place, preserving runner/cursors without END/BEGIN. Live exact endpoints
that merely share an IP or address remain separate; ambiguous routes are not
collapsed. Sources that stop matching a migrated address are detached from
that runner immediately and become Deferred when no endpoint remains. - Runtime
Playback.Loopis authoritative for existing, late, and rejoined
endpoints. Source admission no longer restores the authored initial loop
value, and an EOF source can rejoin at frame 0 when loop is enabled. - Removed the remaining public runnable broadcast fallback parameters. STREAM
sessions accept exact unicast endpoints only.
Hapbeat Unreal Engine SDK の主要な変更点をまとめます。
形式は Keep a Changelog に、
バージョン付けは Semantic Versioning に従います。
修正(Fixed)
Unity SDK v0.4.0 で確定した接続まわりの修正を移植した。
-
Test Play(EventMap のエディタ再生)が常にブロードキャストになっていたのを
修正した。FHapbeatEditorSenderは送信専用でリプライを読まなかったため、既知デバイスが
0 件のままだった。ブロードキャストは AP が DTIM ビーコン(100〜300 ms 周期)まで保留
するため、デザイナーには発火遅れとして体感される。- ソケット作成直後に PING し、送信のたびに届いている PONG を回収するようにした
(このクラスは tick を持たないため、送信直前の機会的な回収で足りる。各送信のあとにも
PING を撃つので、2 回目のクリック時には 1 回目の応答が既にキューにある)。 - 応答があったデバイスへユニキャストする。1 台も無い間だけブロードキャストへ
フォールバックする。ファームウェア v0.3.0 未満は PLAY/STOP の seq 重複排除を
持たないため、二重送信すると触覚が 2 回鳴る。
- ソケット作成直後に PING し、送信のたびに届いている PONG を回収するようにした
-
送信エラーが完全に不可視だったのを修正した。
UHapbeatSubsystem::SendPacketは
SendToの戻り値を捨てていた。ソケットは壊さないまま(UDP の送信失敗はデータグラムが
失われただけで、ソケットは有効)、障害ごとに 1 回だけ警告し、復旧時に 1 行出す。
ストリームは 1 秒あたり約 100 パケット送るため、抑制しないと現場調査に使えるログが
残らない。 -
マルチホーム PC でデバイスを 1 台も発見できない問題を修正した。
255.255.255.255(limited broadcast)はインターフェイスメトリックが最小の 1 本から
しか送出されない。Hyper-V / WSL2 / Docker を入れると作られる仮想アダプタは
LAN ケーブルを繋いでいなくても常時 Connected で、Windows の既定で Wi-Fi より
優先されることがある。この場合パケットは Hapbeat のいるネットワークに一生届かない。- 探索(PING / CONNECT_STATUS)をローカルの各サブネット宛てへ送るようにした。
宛先は各 NIC の実ネットマスクから(ip & mask) | ~maskで算出する(/16 は
x.y.255.255、/25 はx.y.z.127になるため.255決め打ちにはできない)。
同一サブネットに NIC が 2 枚ある場合は宛先で重複排除する。 - UE の公開 API はネットマスクを返さない(
ISocketSubsystem::GetLocalAdapterAddresses
はアドレスのみ)ため、HapbeatNetInterfaces.cppでプラットフォーム API を直接呼ぶ
(Windows はGetAdaptersAddresses、Linux/macOS はgetifaddrs)。プラグイン内で
唯一のプラットフォーム依存コードをこの 1 ファイルに隔離してある。取得できない
プラットフォームは空を返し、従来どおり limited broadcast のみで動く。 - PONG が返ったサブネットに確定し、以後のブロードキャストをそこへ向ける。
endpoint-scoped stream session にも適用される。 - PLAY / STOP / STOP_ALL / STREAM_* は従来どおり単一宛先。ファームウェア v0.3.0
未満は seq 重複排除を持たないため、複数経路へ送ると触覚が 2 回鳴る。Test Play の
ブロードキャストフォールバックも単一宛先のまま(SendSingleBroadcast)。 - Win64 のみ
iphlpapi.libをリンクする(HapbeatSDK.Build.cs)。
- 探索(PING / CONNECT_STATUS)をローカルの各サブネット宛てへ送るようにした。
検証
- サンプルプロジェクトで Basic Example、Showcase、VR Config Example の
Editor/PIE 動作を確認済み。 - Unreal Engine のコンパイルツールチェーンはこのリポジトリの CI にはないため、
自動コンパイルは実行していない。配布前に確認すべき箇所はHapbeatSDK.Build.cs、
HapbeatNetInterfaces.cpp、エディタ送信側の PONG 回収経路である。
Initial release. Hapbeat Unity SDK の Unreal 版として、wire protocol・EventMap・
ストリーミング・Trigger コンポーネント・Editor 支援・サンプルを一式実装。
Added(追加)
Core runtime (HapbeatSDK module)
FHapbeatProtocol— PLAY / STOP / STOP_ALL / PING / CONNECT_STATUS /
STREAM_BEGIN / STREAM_DATA / STREAM_END のパケットビルダーと PONG / ERROR の
パーサー(UnityHapbeatProtocol.csとバイト互換)。UHapbeatSubsystem(UGameInstanceSubsystem) — UDP broadcast の送受信、
Connect/Play/Stop/StopAll/Ping、PONG ベースの疎通判定
(AliveDeviceCount/IsAlive)、OnConnected/OnDisconnected/OnError/
OnPongの Blueprint delegate。UHapbeatConfig— Port・AppName・PingInterval・StreamSendAheadSeconds・
HapticDelaySeconds・StreamUnicast・CommandUnicast 等の接続設定。- 専用スレッドによる CLIP 送出 — STREAM_DATA を game thread ではなく専用
スレッドから ~10ms 等間隔で送出(FHapbeatStreamRunnable)。フレームヒッチ
(GC / 描画 / 物理)でデバイスのリングバッファが枯渇して起きる不定期な途切れを
根治。Gain/Pan は atomic ミラー経由で読むため送出スレッドは UObject に触れない。 - unicast 送信(DTIM 対策) — Wi-Fi AP の省電力バッチングでブロードキャストが
最大 1 ビーコン間隔(~100-300ms)保留される問題を回避するため、PONG で既知の
デバイスへ直接送信。StreamUnicast(CLIP)とCommandUnicast(Play/Stop/
StopAll)を個別に制御でき、既定は両方 on。宛先はデバイスが PONG で報告した
アドレスで絞り込み(未報告のデバイスは fail-open で送信対象に残す)。
該当デバイスが 0 件のとき、コマンドはブロードキャストにフォールバック
(デバイス側が同じ target フィルタを再適用するため誤発火しない)。
PING / CONNECT_STATUS は discovery のため常にブロードキャスト。 - Address Override(player/group の実行時上書き) —
SetAddressOverride(Player, Group, bPersist)/ClearPersistedAddressOverride()/
GetOverridePlayer()/GetOverrideGroup()。設定すると EventMap 側の target
文字列に関わらず、Play/Stop/StopAll/StreamClip の全送信経路にこの player/group
が強制適用される。UHapbeatTargetLibrary::ResolveTargetは Unity
HapbeatClient.ResolveTargetの verbatim 移植。永続化はGConfig/
GGameUserSettingsIni(HapbeatSDKセクション)。
EventMap(調整側)
UHapbeatEventMap(UDataAsset) +FHapbeatEventEntry— event id・
EHapticMode(Command / StreamClip)・gain・target・loop・delay offset を
ネイティブ Details パネルで編集。Trigger からは安定 GUID (FGuid Id) で参照。GetEffectiveGain()—entry.Gain × CachedManifestIntensityを計算
(intensity 未 bake 時はスキップ)。
ストリーミング
UHapbeatClip(UDataAsset) — 16 kHz PCM16 WAV を実行時にFFileHelperで
ロード(USoundWavedecode を経由しない全バージョン安全な経路)。UHapbeatStreamPlayback— 再生中ハンドル。Gain/Pan
(リニア L/R バランス)をゲームスレッドからリアルタイム変更可能。FHapbeatStreamer+UHapbeatSubsystem::StreamClip/StopStream—
ゲームスレッドFTSTickerペーシングで PCM16 chunk を送信先行バッファ付きで
送出。単一セッション・新規呼び出しで既存ストリームを置換 (REPLACE semantics)。
Trigger コンポーネント(起点側)
UHapbeatTriggerComponent— EventMap entry を解決して Command/StreamClip を
発火する基底コンポーネント。Fire()/FireWithGain()/Stop()。UHapbeatCollisionTriggerComponent— Hit / BeginOverlap に連動、
タグ・コリジョンチャンネルフィルタ、速度スケールゲイン (FRuntimeFloatCurve)。UHapbeatSequenceComponent— grab/hold/release の 3-phase シーケンス
(On-Start one-shot + Loop StreamClip + 遅延 On-Stop one-shot)。UHapbeatParameterBinding— Transform/Rigidbody の値(位置・速度・
角速度・フレーム差分・外部値)を正規化 → カーブ → StreamGain/StreamPan に
マッピングするTickComponent。
Editor module (HapbeatSDKEditor)
- Kit manifest(schema 2.0.0)の intensity を event id + mode で解決し、
UHapbeatEventMapのCachedManifestIntensityを一括 bake する
"Refresh Intensities" アクション。 - EventMap の各エントリに "Test Play" ボタンを追加する
IDetailCustomization
(PIE 用ソケットとは独立した Editor 専用送信経路)。 UHapbeatTargetLibraryの target 文字列コーデック
(ParseTarget/BuildTargetFromParts) +StandardPositions。
サンプル (HapbeatSDKSamples module)
AHapbeatBasicExampleActor— Space/R/F/S/C キーで
StreamClip 1-shot・StreamClip loop・Command play・stop-all・ping を確認する
最小構成 (basic-exam-kit)。- Showcase 5 ゾーン(
showcase-kit)— Z1 Bowling(衝突トリガー、速度スケール)/
Z2 Door(状態遷移で命令的に発火)/ Z3 Fishing
(UHapbeatSequenceComponent+ velocity→StreamGain binding) / Z4 Stream
Console(スライダー→Gain/Pan binding)/ Z5 ChargeShot(チャージループ +
ApplyGainModulation+ playbackStop())。全ゾーン C++ 製 Actor + engine
primitive visuals(同梱 WAV・Kit manifest は Unity Showcase と共通)。
パッケージング
CanContainContent: true+Config/FilterPlugin.ini
(/Content/HapbeatSamples/...を raw WAV/manifest ごとパッケージに含める)。- CI: タグ push (
v*) から CHANGELOG を抽出して GitHub Release を自動公開。