IVSmoke 1.0
Loading...
Searching...
No Matches
IVSmokeHoleRequestComponent.cpp
1// Copyright (c) 2026, Team SDB. All rights reserved.
2
3#include "IVSmokeHoleRequestComponent.h"
4
5#include "IVSmoke.h"
6#include "IVSmokeHoleGeneratorComponent.h"
7#include "IVSmokeHolePreset.h"
8#include "GameFramework/Pawn.h"
9#include "GameFramework/PlayerController.h"
10
11UIVSmokeHoleRequestComponent::UIVSmokeHoleRequestComponent()
12{
13 SetIsReplicatedByDefault(true);
14}
15
16//~============================================================================
17// Public API
18#pragma region API
19
20void UIVSmokeHoleRequestComponent::RequestPenetrationHole(AActor* Caller, AActor* IVSmokeVoxelVolume, const FVector3f& BulletOrigin, const FVector3f& BulletDirection, UIVSmokeHolePreset* BulletPreset)
21{
22 if (!Caller)
23 {
24 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] Caller is null"));
25 return;
26 }
27
28 if (!IVSmokeVoxelVolume)
29 {
30 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] IVSmokeVoxelVolume is null"));
31 return;
32 }
33
34 if (!BulletPreset)
35 {
36 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] BulletPreset is null"));
37 return;
38 }
39
40 UIVSmokeHoleGeneratorComponent* Generator = IVSmokeVoxelVolume->FindComponentByClass<UIVSmokeHoleGeneratorComponent>();
41 if (!Generator)
42 {
43 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] Generator not found on IVSmokeVoxelVolume"));
44 return;
45 }
46
47 // Server/AI → Direct call
48 if (Generator->GetOwner() && Generator->GetOwner()->HasAuthority())
49 {
50 Generator->CreatePenetrationHole(BulletOrigin, BulletDirection, BulletPreset->GetPresetID());
51 return;
52 }
53
54 // Client → RPC via Caller's Instigator chain
55 APawn* InstigatorPawn = Caller->GetInstigator();
56 if (!InstigatorPawn)
57 {
58 InstigatorPawn = Cast<APawn>(Caller);
59 }
60
61 if (!InstigatorPawn)
62 {
63 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] InstigatorPawn not found"));
64 return;
65 }
66
67 APlayerController* PC = Cast<APlayerController>(InstigatorPawn->GetController());
68 if (!PC)
69 {
70 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] PlayerController not found"));
71 return;
72 }
73
74 UIVSmokeHoleRequestComponent* Requester = PC->FindComponentByClass<UIVSmokeHoleRequestComponent>();
75 if (!Requester)
76 {
77 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] RequestComponent not found on PlayerController"));
78 return;
79 }
80
81 Requester->Internal_RequestPenetrationHole(Generator, BulletOrigin, BulletDirection, BulletPreset);
82}
83
84void UIVSmokeHoleRequestComponent::RequestExplosionHole(AActor* Caller, AActor* IVSmokeVoxelVolume, const FVector3f& ExplosionOrigin, UIVSmokeHolePreset* ExplosionPreset)
85{
86 if (!Caller)
87 {
88 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] Caller is null"));
89 return;
90 }
91
92 if (!IVSmokeVoxelVolume)
93 {
94 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] IVSmokeVoxelVolume is null"));
95 return;
96 }
97
98 if (!ExplosionPreset)
99 {
100 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] ExplosionPreset is null"));
101 return;
102 }
103
104 UIVSmokeHoleGeneratorComponent* Generator = IVSmokeVoxelVolume->FindComponentByClass<UIVSmokeHoleGeneratorComponent>();
105 if (!Generator)
106 {
107 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] Generator not found on IVSmokeVoxelVolume"));
108 return;
109 }
110
111 // Server/AI → Direct call
112 if (Generator->GetOwner() && Generator->GetOwner()->HasAuthority())
113 {
114 Generator->CreateExplosionHole(ExplosionOrigin, ExplosionPreset->GetPresetID());
115 return;
116 }
117
118 // Client → RPC via Caller's Instigator chain
119 APawn* InstigatorPawn = Caller->GetInstigator();
120 if (!InstigatorPawn)
121 {
122 InstigatorPawn = Cast<APawn>(Caller);
123 }
124
125 if (!InstigatorPawn)
126 {
127 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] InstigatorPawn not found"));
128 return;
129 }
130
131 APlayerController* PC = Cast<APlayerController>(InstigatorPawn->GetController());
132 if (!PC)
133 {
134 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] PlayerController not found"));
135 return;
136 }
137
138 UIVSmokeHoleRequestComponent* Requester = PC->FindComponentByClass<UIVSmokeHoleRequestComponent>();
139 if (!Requester)
140 {
141 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] RequestComponent not found on PlayerController"));
142 return;
143 }
144
145 Requester->Internal_RequestExplosionHole(Generator, ExplosionOrigin, ExplosionPreset);
146}
147
148void UIVSmokeHoleRequestComponent::RequestDynamicHole(
149 AActor* Caller,
150 AActor* IVSmokeVoxelVolume,
151 UIVSmokeHolePreset* DynamicPreset
152)
153{
154 if (!Caller)
155 {
156 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] Caller is null"));
157 return;
158 }
159
160 if (!IVSmokeVoxelVolume)
161 {
162 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] IVSmokeVoxelVolume is null"));
163 return;
164 }
165
166 if (!DynamicPreset)
167 {
168 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] DynamicPreset is null"));
169 return;
170 }
171
172 UIVSmokeHoleGeneratorComponent* Generator = IVSmokeVoxelVolume->FindComponentByClass<UIVSmokeHoleGeneratorComponent>();
173 if (!Generator)
174 {
175 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] Generator not found on IVSmokeVoxelVolume"));
176 return;
177 }
178
179 // Server/AI → Direct call (Caller = TargetActor)
180 if (Generator->GetOwner() && Generator->GetOwner()->HasAuthority())
181 {
182 Generator->RegisterTrackDynamicHole(Caller, DynamicPreset->GetPresetID());
183 return;
184 }
185
186 // Client → RPC via Caller's Instigator chain (Caller = TargetActor = Pawn)
187 APawn* InstigatorPawn = Cast<APawn>(Caller);
188 if (!InstigatorPawn)
189 {
190 InstigatorPawn = Caller->GetInstigator();
191 }
192
193 if (!InstigatorPawn)
194 {
195 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] InstigatorPawn not found"));
196 return;
197 }
198
199 APlayerController* PC = Cast<APlayerController>(InstigatorPawn->GetController());
200 if (!PC)
201 {
202 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] PlayerController not found"));
203 return;
204 }
205
206 UIVSmokeHoleRequestComponent* Requester = PC->FindComponentByClass<UIVSmokeHoleRequestComponent>();
207 if (!Requester)
208 {
209 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] RequestComponent not found on PlayerController"));
210 return;
211 }
212
213 Requester->Internal_RequestDynamicHole(Generator, Caller, DynamicPreset);
214}
215#pragma endregion
216
217//~============================================================================
218// Server RPC
219#pragma region RPC
220void UIVSmokeHoleRequestComponent::Internal_RequestPenetrationHole_Implementation(UIVSmokeHoleGeneratorComponent* IVSmokeHoleGeneratorComponent, const FVector3f& Origin, const FVector3f& Direction, UIVSmokeHolePreset* Preset)
221{
222 if (!IVSmokeHoleGeneratorComponent)
223 {
224 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] IVSmokeHoleGeneratorComponent is null"));
225 return;
226 }
227
228 if (!Preset)
229 {
230 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] Preset is null"));
231 return;
232 }
233
234 if (Preset->HoleType != EIVSmokeHoleType::Penetration)
235 {
236 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestPenetrationHole] Preset type mismatch"));
237 return;
238 }
239
240 IVSmokeHoleGeneratorComponent->CreatePenetrationHole(Origin, Direction, Preset->GetPresetID());
241}
242
243void UIVSmokeHoleRequestComponent::Internal_RequestExplosionHole_Implementation(UIVSmokeHoleGeneratorComponent* IVSmokeHoleGeneratorComponent, const FVector3f& Origin, UIVSmokeHolePreset* Preset)
244{
245 if (!IVSmokeHoleGeneratorComponent)
246 {
247 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] IVSmokeHoleGeneratorComponent is null"));
248 return;
249 }
250
251 if (!Preset)
252 {
253 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] Preset is null"));
254 return;
255 }
256
257 if (Preset->HoleType != EIVSmokeHoleType::Explosion)
258 {
259 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestExplosionHole] Preset type mismatch"));
260 return;
261 }
262
263 IVSmokeHoleGeneratorComponent->CreateExplosionHole(Origin, Preset->GetPresetID());
264}
265
266void UIVSmokeHoleRequestComponent::Internal_RequestDynamicHole_Implementation(UIVSmokeHoleGeneratorComponent* IVSmokeHoleGeneratorComponent, AActor* TargetActor, UIVSmokeHolePreset* Preset)
267{
268 if (!IVSmokeHoleGeneratorComponent)
269 {
270 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] IVSmokeHoleGeneratorComponent is null"));
271 return;
272 }
273
274 if (!Preset)
275 {
276 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] Preset is null"));
277 return;
278 }
279
280 if (Preset->HoleType != EIVSmokeHoleType::Dynamic)
281 {
282 UE_LOG(LogIVSmoke, Warning, TEXT("[UIVSmokeHoleRequestComponent::RequestDynamicHole] Preset type mismatch"));
283 return;
284 }
285
286 IVSmokeHoleGeneratorComponent->RegisterTrackDynamicHole(TargetActor, Preset->GetPresetID());
287}
288#pragma endregion
Component that generates hole texture for volumetric smoke. Provides public API for penetration and e...
void CreateExplosionHole(const FVector3f &Origin, const uint8 PresetID)
void CreatePenetrationHole(const FVector3f &Origin, const FVector3f &Direction, const uint8 PresetID)
void RegisterTrackDynamicHole(AActor *TargetActor, const uint8 PresetID)
FORCEINLINE uint8 GetPresetID() const
EIVSmokeHoleType HoleType
Handles network routing for hole requests. This component enables clients to request holes on VoxelVo...