| 143 | } |
| 144 | |
| 145 | void AAMjManager::BeginPlay() |
| 146 | { |
| 147 | Super::BeginPlay(); |
| 148 | |
| 149 | if (Instance != nullptr && Instance != this) |
| 150 | { |
| 151 | UE_LOG(LogURLab, Error, TEXT("[AAMjManager] Multiple AAMjManager actors detected in level. Only one is supported — this instance (%s) will be ignored."), *GetName()); |
| 152 | return; |
| 153 | } |
| 154 | Instance = this; |
| 155 | |
| 156 | // Auto-create ReplayManager BEFORE the dispatcher / ZMQ components so the |
| 157 | // dispatcher's Init can cache its pointer. (Transport worker threads later |
| 158 | // read this cache to avoid TActorIterator, which asserts IsInGameThread.) |
| 159 | { |
| 160 | AMjReplayManager* ExistingReplay = Cast<AMjReplayManager>( |
| 161 | UGameplayStatics::GetActorOfClass(GetWorld(), AMjReplayManager::StaticClass())); |
| 162 | if (!ExistingReplay) |
| 163 | { |
| 164 | FActorSpawnParameters SpawnParams; |
| 165 | AMjReplayManager* ReplayMgr = GetWorld()->SpawnActor<AMjReplayManager>(SpawnParams); |
| 166 | if (ReplayMgr) |
| 167 | { |
| 168 | UE_LOG(LogURLab, Log, TEXT("[AAMjManager] Auto-created AMjReplayManager")); |
| 169 | } |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | // Resolve a bridge server. In editor builds the URLabEditor module |
| 174 | // installs a resolver via URLabBridgeProvider that hands back the |
| 175 | // subsystem's server (lifetime spans PIE sessions). Cooked builds |
| 176 | // have no resolver, fall through to creating our own and marking it |
| 177 | // as owned-by-manager so EndPlay tears it down. |
| 178 | UURLabBridgeServer* ResolvedServer = URLabBridgeProvider::ResolveEditorServer(); |
| 179 | if (ResolvedServer) |
| 180 | { |
| 181 | BridgeServer = ResolvedServer; |
| 182 | // Don't claim ownership — subsystem controls lifetime. |
| 183 | } |
| 184 | else |
| 185 | { |
| 186 | // Cooked path: no editor subsystem. Manager owns its bridge and |
| 187 | // brings up both RPC transports inline. Bridge owns all RPC |
| 188 | // transports; manager only owns publish/subscribe streams. |
| 189 | BridgeServer = NewObject<UURLabBridgeServer>(this, TEXT("BridgeServer")); |
| 190 | BridgeServer->SetOwnedByManager(true); |
| 191 | BridgeServer->Start(); // ZMQ on tcp://0.0.0.0:5559 |
| 192 | BridgeServer->EnsureShmBound(); // SHM under "live" |
| 193 | } |
| 194 | BridgeServer->RegisterManager(this); |
| 195 | |
| 196 | // Auto-create the streaming transports (PIE-only producers — they |
| 197 | // tap PhysicsEngine pre/post-step callbacks). Bridge-style UObject |
| 198 | // lifecycle: NewObject + SetOwningManager + TransportInit. Manager |
| 199 | // owns streaming; bridge owns RPC. |
| 200 | { |
| 201 | UE_LOG(LogURLab, Log, TEXT("[AAMjManager] Creating manager-owned streaming transports")); |
| 202 |
nothing calls this directly
no test coverage detected