AlphaStarX

LagCompensationComponent

Feb 28th, 2025
16
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 20.38 KB | None | 0 0
  1. // Fill out your copyright notice in the Description page of Project Settings.
  2.  
  3.  
  4. #include "LagCompensationComponent.h"
  5. #include "Components/BoxComponent.h"
  6. #include "ShooterProject/Character/BlasterCharacter.h"
  7. #include "Kismet/GameplayStatics.h"
  8. #include "DrawDebugHelpers.h"
  9. #include "ShooterProject/Weapon/Weapon.h"
  10. #include "ShooterProject/ShooterProject.h"
  11.  
  12.  
  13. ULagCompensationComponent::ULagCompensationComponent()
  14. {
  15. PrimaryComponentTick.bCanEverTick = true;
  16. }
  17.  
  18. void ULagCompensationComponent::BeginPlay()
  19. {
  20. Super::BeginPlay();
  21. FFramePackage Package;
  22. SaveFramePackage(Package);
  23. ShowFramePackage(Package, FColor::Orange);
  24. }
  25.  
  26. FFramePackage ULagCompensationComponent::InterpBetweenFrames(const FFramePackage& OlderFrame,
  27. const FFramePackage& YoungerFrame, float HitTime)
  28. {
  29. const float Distance = YoungerFrame.Time - OlderFrame.Time;
  30. const float InterpFraction = FMath::Clamp((HitTime - OlderFrame.Time) / Distance, 0.f, 1.f);
  31. FFramePackage InterpFramePackage;
  32. InterpFramePackage.Time = HitTime;
  33.  
  34. for(auto& YoungerPair : YoungerFrame.HitBoxInfo)
  35. {
  36. const FName& BoxInfoName = YoungerPair.Key;
  37. const FBoxInformation& OlderBox = OlderFrame.HitBoxInfo[BoxInfoName];
  38. const FBoxInformation& YoungerBox = YoungerFrame.HitBoxInfo[BoxInfoName];
  39.  
  40. FBoxInformation InterpBoxInfo;
  41. InterpBoxInfo.Location = FMath::VInterpTo(OlderBox.Location,YoungerBox.Location,1.f,InterpFraction);
  42. InterpBoxInfo.Rotation = FMath::RInterpTo(OlderBox.Rotation, YoungerBox.Rotation, 1.f,InterpFraction);
  43. InterpBoxInfo.BoxExtent = YoungerBox.BoxExtent;
  44.  
  45. InterpFramePackage.HitBoxInfo.Add(BoxInfoName, InterpBoxInfo);
  46. }
  47. return InterpFramePackage;
  48. }
  49.  
  50. FServerSideRewindResult ULagCompensationComponent::ConfirmHit(const FFramePackage& Package,
  51. ABlasterCharacter* HitCharacter, const FVector_NetQuantize& TraceStart, const FVector_NetQuantize& HitLocation)
  52. {
  53. if (HitCharacter == nullptr) return FServerSideRewindResult();
  54.  
  55. FFramePackage CurrentFrame;
  56. CacheBoxPositions(HitCharacter, CurrentFrame);
  57. MoveBoxes(HitCharacter, Package);
  58. EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::NoCollision);
  59.  
  60. // Enable Collision for the head first
  61. UBoxComponent* HeadBox = HitCharacter->HitCollisionBoxes[FName("head")];
  62. HeadBox->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
  63. HeadBox->SetCollisionResponseToChannel(ECC_HitBox, ECR_Block);
  64.  
  65. FHitResult ConfirmHitResult;
  66. const FVector TraceEnd = TraceStart + (HitLocation - TraceStart) * 1.25f;
  67. UWorld* World = GetWorld();
  68. if (World)
  69. {
  70. World->LineTraceSingleByChannel(
  71. ConfirmHitResult,
  72. TraceStart,
  73. TraceEnd,
  74. ECC_HitBox
  75. );
  76.  
  77. if (ConfirmHitResult.bBlockingHit) // We hit head return early
  78. {
  79. if (ConfirmHitResult.Component.IsValid())
  80. {
  81. UBoxComponent* Box = Cast<UBoxComponent>(ConfirmHitResult.Component);
  82. if (Box)
  83. {
  84. DrawDebugBox(GetWorld(), Box->GetComponentLocation(), Box->GetScaledBoxExtent(), FQuat(Box->GetComponentRotation()), FColor::Red, false, 8.f);
  85. }
  86. }
  87. ResetHitBoxes(HitCharacter, CurrentFrame);
  88. EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::QueryAndPhysics);
  89. return FServerSideRewindResult{true,true};
  90. }
  91. else // didn't hit the head, check the rest of the boxes
  92. {
  93. for (auto& HitBoxPair : HitCharacter->HitCollisionBoxes)
  94. {
  95. if (HitBoxPair.Value != nullptr)
  96. {
  97. HitBoxPair.Value->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
  98. HitBoxPair.Value->SetCollisionResponseToChannel(ECC_HitBox,ECR_Block);
  99. }
  100. }
  101. World->LineTraceSingleByChannel(ConfirmHitResult, TraceStart, TraceEnd , ECC_HitBox);
  102. if (ConfirmHitResult.bBlockingHit)
  103. {
  104. if (ConfirmHitResult.Component.IsValid())
  105. {
  106. UBoxComponent* Box = Cast<UBoxComponent>(ConfirmHitResult.Component);
  107. if (Box)
  108. {
  109. DrawDebugBox(GetWorld(), Box->GetComponentLocation(), Box->GetScaledBoxExtent(), FQuat(Box->GetComponentRotation()), FColor::Blue, false, 8.f);
  110. }
  111. }
  112. ResetHitBoxes(HitCharacter, CurrentFrame);
  113. EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::QueryAndPhysics);
  114. return FServerSideRewindResult{true,false};
  115. }
  116. }
  117. }
  118. ResetHitBoxes(HitCharacter, CurrentFrame);
  119. EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::QueryAndPhysics);
  120. return FServerSideRewindResult{false,false};
  121. }
  122.  
  123. FServerSideRewindResult ULagCompensationComponent::ProjectileConfirmHit(const FFramePackage& Package, ABlasterCharacter* HitCharacter,
  124. const FVector_NetQuantize& TraceStart, const FVector_NetQuantize100& InitialVelocity, float HitTime)
  125. {
  126. FFramePackage CurrentFrame;
  127. CacheBoxPositions(HitCharacter, CurrentFrame);
  128. MoveBoxes(HitCharacter, Package);
  129. EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::NoCollision);
  130.  
  131. // Enable Collision for the head first
  132. UBoxComponent* HeadBox = HitCharacter->HitCollisionBoxes[FName("head")];
  133. HeadBox->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
  134. HeadBox->SetCollisionResponseToChannel(ECC_HitBox, ECR_Block);
  135.  
  136. FPredictProjectilePathParams PathParams;
  137. PathParams.bTraceWithCollision = true;
  138. PathParams.MaxSimTime = MaxRecordTime;
  139. PathParams.LaunchVelocity = InitialVelocity;
  140. PathParams.StartLocation = TraceStart;
  141. PathParams.SimFrequency = 15.f;
  142. PathParams.ProjectileRadius = 5.f;
  143. PathParams.TraceChannel = ECC_HitBox;
  144. PathParams.ActorsToIgnore.Add(GetOwner());
  145. PathParams.DrawDebugTime = 5.f;
  146. PathParams.DrawDebugType = EDrawDebugTrace::ForDuration;
  147.  
  148. FPredictProjectilePathResult PathResult;
  149.  
  150. UGameplayStatics::PredictProjectilePath(this, PathParams, PathResult);
  151.  
  152. if (PathResult.HitResult.bBlockingHit) // we hit the head, return early
  153. {
  154. if (PathResult.HitResult.Component.IsValid())
  155. {
  156. UBoxComponent* Box = Cast<UBoxComponent>(PathResult.HitResult.Component);
  157. if (Box)
  158. {
  159. DrawDebugBox(GetWorld(), Box->GetComponentLocation(), Box->GetScaledBoxExtent(), FQuat(Box->GetComponentRotation()), FColor::Red, false, 8.f);
  160. }
  161. }
  162. ResetHitBoxes(HitCharacter, CurrentFrame);
  163. EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::QueryAndPhysics);
  164. return FServerSideRewindResult{true,true};
  165. }
  166. else // we didn't hit the head, check the rest of the boxes
  167. {
  168. for (auto& HitBoxPair : HitCharacter->HitCollisionBoxes)
  169. {
  170. if (HitBoxPair.Value != nullptr)
  171. {
  172. HitBoxPair.Value->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
  173. HitBoxPair.Value->SetCollisionResponseToChannel(ECC_HitBox,ECR_Block);
  174. }
  175. }
  176. UGameplayStatics::PredictProjectilePath(this, PathParams, PathResult);
  177. if (PathResult.HitResult.bBlockingHit)
  178. {
  179. if (PathResult.HitResult.Component.IsValid())
  180. {
  181. UBoxComponent* Box = Cast<UBoxComponent>(PathResult.HitResult.Component);
  182. if (Box)
  183. {
  184. DrawDebugBox(GetWorld(), Box->GetComponentLocation(), Box->GetScaledBoxExtent(), FQuat(Box->GetComponentRotation()), FColor::Blue, false, 8.f);
  185. }
  186. }
  187. ResetHitBoxes(HitCharacter, CurrentFrame);
  188. EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::QueryAndPhysics);
  189. return FServerSideRewindResult{true,false};
  190. }
  191. }
  192. ResetHitBoxes(HitCharacter, CurrentFrame);
  193. EnableCharacterMeshCollision(HitCharacter, ECollisionEnabled::QueryAndPhysics);
  194. return FServerSideRewindResult{false,false};
  195. }
  196.  
  197. FShotgunServerSideRewindResult ULagCompensationComponent::ShotgunConfirmHit(const TArray<FFramePackage>& FramePackages, const FVector_NetQuantize& TraceStart, const TArray<FVector_NetQuantize>& HitLocations)
  198. {
  199. for (auto& Frame : FramePackages)
  200. {
  201. if (Frame.Character == nullptr) return FShotgunServerSideRewindResult();
  202. }
  203.  
  204. FShotgunServerSideRewindResult ShotgunResult;
  205. TArray<FFramePackage> CurrentFrames;
  206. for (auto& Frame : FramePackages)
  207. {
  208. FFramePackage CurrentFrame;
  209. CurrentFrame.Character = Frame.Character;
  210. CacheBoxPositions(Frame.Character, CurrentFrame);
  211. MoveBoxes(Frame.Character, Frame);
  212. EnableCharacterMeshCollision(Frame.Character, ECollisionEnabled::NoCollision);
  213. CurrentFrames.Add(CurrentFrame);
  214. }
  215.  
  216. for (auto& Frame : FramePackages)
  217. {
  218. // Enable Collision for the head first
  219. UBoxComponent* HeadBox = Frame.Character->HitCollisionBoxes[FName("head")];
  220. HeadBox->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
  221. HeadBox->SetCollisionResponseToChannel(ECC_HitBox, ECR_Block);
  222. }
  223.  
  224. UWorld* World = GetWorld();
  225. // Check for Head shots
  226. for (auto& HitLocation : HitLocations)
  227. {
  228. FHitResult ConfirmHitResult;
  229. const FVector TraceEnd = TraceStart + (HitLocation - TraceStart) * 1.25f;
  230. if (World)
  231. {
  232. World->LineTraceSingleByChannel(
  233. ConfirmHitResult,
  234. TraceStart,
  235. TraceEnd,
  236. ECC_HitBox
  237. );
  238. ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(ConfirmHitResult.GetActor());
  239. if (BlasterCharacter)
  240. {
  241. if (ConfirmHitResult.Component.IsValid())
  242. {
  243. UBoxComponent* Box = Cast<UBoxComponent>(ConfirmHitResult.Component);
  244. if (Box)
  245. {
  246. DrawDebugBox(GetWorld(), Box->GetComponentLocation(), Box->GetScaledBoxExtent(), FQuat(Box->GetComponentRotation()), FColor::Red, false, 8.f);
  247. }
  248. }
  249. if (ShotgunResult.HeadShots.Contains(BlasterCharacter))
  250. {
  251. ShotgunResult.HeadShots[BlasterCharacter]++;
  252. }
  253. else
  254. {
  255. ShotgunResult.HeadShots.Emplace(BlasterCharacter, 1);
  256. }
  257. }
  258. }
  259. }
  260.  
  261. // Enable collision for all boxes, then disable for head box
  262. for (auto& Frame : FramePackages)
  263. {
  264. for (auto& HitBoxPair : Frame.Character->HitCollisionBoxes)
  265. {
  266. if (HitBoxPair.Value != nullptr)
  267. {
  268. HitBoxPair.Value->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
  269. HitBoxPair.Value->SetCollisionResponseToChannel(ECC_HitBox,ECR_Block);
  270. }
  271. }
  272. UBoxComponent* HeadBox = Frame.Character->HitCollisionBoxes[FName("head")];
  273. HeadBox->SetCollisionEnabled(ECollisionEnabled::NoCollision);
  274. }
  275.  
  276. // check for body shots
  277. for (auto& HitLocation : HitLocations)
  278. {
  279. FHitResult ConfirmHitResult;
  280. const FVector TraceEnd = TraceStart + (HitLocation - TraceStart) * 1.25f;
  281. if (World)
  282. {
  283. World->LineTraceSingleByChannel(
  284. ConfirmHitResult,
  285. TraceStart,
  286. TraceEnd,
  287. ECC_HitBox
  288. );
  289. ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(ConfirmHitResult.GetActor());
  290. if (BlasterCharacter)
  291. {
  292. if (ConfirmHitResult.Component.IsValid())
  293. {
  294. UBoxComponent* Box = Cast<UBoxComponent>(ConfirmHitResult.Component);
  295. if (Box)
  296. {
  297. DrawDebugBox(GetWorld(), Box->GetComponentLocation(), Box->GetScaledBoxExtent(), FQuat(Box->GetComponentRotation()), FColor::Blue, false, 8.f);
  298. }
  299. }
  300. if (ShotgunResult.BodyShots.Contains(BlasterCharacter))
  301. {
  302. ShotgunResult.BodyShots[BlasterCharacter]++;
  303. }
  304. else
  305. {
  306. ShotgunResult.BodyShots.Emplace(BlasterCharacter, 1);
  307. }
  308. }
  309. }
  310. }
  311.  
  312. for (auto& Frame : CurrentFrames)
  313. {
  314. ResetHitBoxes(Frame.Character, Frame);
  315. EnableCharacterMeshCollision(Frame.Character, ECollisionEnabled::QueryAndPhysics);
  316. }
  317.  
  318. return ShotgunResult;
  319. }
  320.  
  321. void ULagCompensationComponent::CacheBoxPositions(ABlasterCharacter* HitCharacter, FFramePackage& OutFramePackage)
  322. {
  323. if (HitCharacter == nullptr) return;
  324. for(auto& HitBoxPair : HitCharacter->HitCollisionBoxes)
  325. {
  326. if(HitBoxPair.Value != nullptr)
  327. {
  328. FBoxInformation BoxInfo;
  329. BoxInfo.Location = HitBoxPair.Value->GetComponentLocation();
  330. BoxInfo.Rotation = HitBoxPair.Value->GetComponentRotation();
  331. BoxInfo.BoxExtent = HitBoxPair.Value->GetScaledBoxExtent();
  332. OutFramePackage.HitBoxInfo.Add(HitBoxPair.Key, BoxInfo);
  333. }
  334. }
  335. }
  336.  
  337. void ULagCompensationComponent::MoveBoxes(ABlasterCharacter* HitCharacter, const FFramePackage& Package)
  338. {
  339. if (HitCharacter == nullptr) return;
  340. for (auto& HitBoxPair : HitCharacter->HitCollisionBoxes)
  341. {
  342. if (HitBoxPair.Value != nullptr)
  343. {
  344. const FBoxInformation* BoxValue = Package.HitBoxInfo.Find(HitBoxPair.Key);
  345.  
  346. if (BoxValue)
  347. {
  348. HitBoxPair.Value->SetWorldLocation(Package.HitBoxInfo[HitBoxPair.Key].Location);
  349. HitBoxPair.Value->SetWorldRotation(Package.HitBoxInfo[HitBoxPair.Key].Rotation);
  350. HitBoxPair.Value->SetBoxExtent(Package.HitBoxInfo[HitBoxPair.Key].BoxExtent);
  351. }
  352. }
  353. }
  354. }
  355.  
  356. void ULagCompensationComponent::ResetHitBoxes(ABlasterCharacter* HitCharacter, const FFramePackage& Package)
  357. {
  358. if (HitCharacter == nullptr) return;
  359. for (auto& HitBoxPair : HitCharacter->HitCollisionBoxes)
  360. {
  361. if (HitBoxPair.Value != nullptr)
  362. {
  363. const FBoxInformation* BoxValue = Package.HitBoxInfo.Find(HitBoxPair.Key);
  364.  
  365. if (BoxValue)
  366. {
  367. HitBoxPair.Value->SetWorldLocation(Package.HitBoxInfo[HitBoxPair.Key].Location);
  368. HitBoxPair.Value->SetWorldRotation(Package.HitBoxInfo[HitBoxPair.Key].Rotation);
  369. HitBoxPair.Value->SetBoxExtent(Package.HitBoxInfo[HitBoxPair.Key].BoxExtent);
  370. HitBoxPair.Value->SetCollisionEnabled(ECollisionEnabled::NoCollision);
  371. }
  372. }
  373. }
  374. }
  375.  
  376. void ULagCompensationComponent::EnableCharacterMeshCollision(ABlasterCharacter* HitCharacter,
  377. ECollisionEnabled::Type CollisionEnabled)
  378. {
  379. if (HitCharacter && HitCharacter->GetMesh())
  380. {
  381. HitCharacter->GetMesh()->SetCollisionEnabled(CollisionEnabled);
  382. }
  383. }
  384.  
  385. void ULagCompensationComponent::ShowFramePackage(const FFramePackage& Package, const FColor& Color)
  386. {
  387. for (auto& BoxInfo : Package.HitBoxInfo)
  388. {
  389. DrawDebugBox(
  390. GetWorld(),
  391. BoxInfo.Value.Location,
  392. BoxInfo.Value.BoxExtent,
  393. FQuat(BoxInfo.Value.Rotation),
  394. Color,
  395. false,
  396. 4.f
  397. );
  398. }
  399. }
  400.  
  401. FServerSideRewindResult ULagCompensationComponent::ServerSideRewind(ABlasterCharacter* HitCharacter, const FVector_NetQuantize& TraceStart,
  402. const FVector_NetQuantize& HitLocation, float HitTime)
  403. {
  404. FFramePackage FrameToCheck = GetFrameToCheck(HitCharacter, HitTime);
  405. return ConfirmHit(FrameToCheck, HitCharacter, TraceStart, HitLocation);
  406. }
  407.  
  408. FServerSideRewindResult ULagCompensationComponent::ProjectileServerSideRewind(ABlasterCharacter* HitCharacter,
  409. const FVector_NetQuantize& TraceStart, const FVector_NetQuantize100& InitialVelocity, float HitTime)
  410. {
  411. FFramePackage FrameToCheck = GetFrameToCheck(HitCharacter, HitTime);
  412. return ProjectileConfirmHit(FrameToCheck, HitCharacter, TraceStart, InitialVelocity, HitTime);
  413. }
  414.  
  415. FShotgunServerSideRewindResult ULagCompensationComponent::ShotgunServerSideRewind(
  416. const TArray<ABlasterCharacter*>& HitCharacters, const FVector_NetQuantize& TraceStart,
  417. const TArray<FVector_NetQuantize>& HitLocations, float HitTime)
  418. {
  419. TArray<FFramePackage> FramesToCheck;
  420. for (ABlasterCharacter* HitCharacter : HitCharacters)
  421. {
  422. FramesToCheck.Add(GetFrameToCheck(HitCharacter, HitTime));
  423. }
  424. return ShotgunConfirmHit(FramesToCheck, TraceStart, HitLocations);
  425. }
  426.  
  427. FFramePackage ULagCompensationComponent::GetFrameToCheck(ABlasterCharacter* HitCharacter, float HitTime)
  428. {
  429. bool bReturn =
  430. HitCharacter == nullptr ||
  431. HitCharacter->GetLagCompensation() ||
  432. HitCharacter->GetLagCompensation()->FrameHistory.GetHead() == nullptr ||
  433. HitCharacter->GetLagCompensation()->FrameHistory.GetTail() == nullptr;
  434. if (bReturn) return FFramePackage();
  435.  
  436. // Frame Package that we check to verify a hit
  437. FFramePackage FrameToCheck;
  438. bool bShouldInterpolate = true;
  439. // Frame History of the HitCharacter
  440. const TDoubleLinkedList<FFramePackage>& History = HitCharacter->GetLagCompensation()->FrameHistory;
  441. const float OldestHistoryTime = History.GetTail()->GetValue().Time;
  442. const float NewestHistoryTime = History.GetHead()->GetValue().Time;
  443. if (OldestHistoryTime > HitTime)
  444. {
  445. // Too far back - too laggy to do Server side rewind
  446. return FFramePackage();
  447. }
  448. if (OldestHistoryTime == HitTime)
  449. {
  450. FrameToCheck = History.GetTail()->GetValue();
  451. bShouldInterpolate = false;
  452. }
  453. if (NewestHistoryTime <= HitTime)
  454. {
  455. FrameToCheck = History.GetHead()->GetValue();
  456. bShouldInterpolate = false;
  457. }
  458.  
  459. TDoubleLinkedList<FFramePackage>::TDoubleLinkedListNode* Younger = History.GetHead();
  460. TDoubleLinkedList<FFramePackage>::TDoubleLinkedListNode* Older = Younger;
  461. while (Older->GetValue().Time > HitTime) // is Older Still younger than HitTime?
  462. {
  463. // March back until: OlderTime < HitTime < YoungerTime
  464. if (Older->GetNextNode() == nullptr) break;
  465. Older = Older->GetNextNode();
  466. if (Older->GetValue().Time > HitTime)
  467. {
  468. Younger = Older;
  469. }
  470. }
  471. if (Older->GetValue().Time == HitTime) // Highly unlikely, but we found our frame to check
  472. {
  473. FrameToCheck = Older->GetValue();
  474. bShouldInterpolate = false;
  475. }
  476. if (bShouldInterpolate)
  477. {
  478. // Interpolate between Younger and Older
  479. FrameToCheck = InterpBetweenFrames(Older->GetValue(), Younger->GetValue(), HitTime);
  480. }
  481. FrameToCheck.Character = HitCharacter;
  482. return FrameToCheck;
  483. }
  484.  
  485. void ULagCompensationComponent::ServerScoreRequest_Implementation(
  486. ABlasterCharacter* HitCharacter,const FVector_NetQuantize& TraceStart,
  487. const FVector_NetQuantize& HitLocation, float HitTime, AWeapon* DamageCauser)
  488. {
  489. FServerSideRewindResult Confirm = ServerSideRewind(HitCharacter, TraceStart, HitLocation, HitTime);
  490.  
  491. if (Character && HitCharacter && DamageCauser && Confirm.bHitConfirmed)
  492. {
  493. UGameplayStatics::ApplyDamage(
  494. HitCharacter,
  495. DamageCauser->GetDamage(),
  496. Character->Controller,
  497. DamageCauser,
  498. UDamageType::StaticClass()
  499. );
  500. }
  501. }
  502.  
  503. void ULagCompensationComponent::ProjectileServerScoreRequest_Implementation(ABlasterCharacter* HitCharacter,
  504. const FVector_NetQuantize& TraceStart, const FVector_NetQuantize100& InitialVelocity, float HitTime)
  505. {
  506. FServerSideRewindResult Confirm = ProjectileServerSideRewind(HitCharacter, TraceStart, InitialVelocity, HitTime);
  507.  
  508. if (Character && HitCharacter && Confirm.bHitConfirmed)
  509. {
  510. UGameplayStatics::ApplyDamage(
  511. HitCharacter,
  512. Character->GetEquippedWeapon()->GetDamage(),
  513. Character->Controller,
  514. Character->GetEquippedWeapon(),
  515. UDamageType::StaticClass()
  516. );
  517. }
  518. }
  519.  
  520. void ULagCompensationComponent::ShotgunServerScoreRequest_Implementation(
  521. const TArray<ABlasterCharacter*>& HitCharacters, const FVector_NetQuantize& TraceStart,
  522. const TArray<FVector_NetQuantize>& HitLocations, float HitTime)
  523. {
  524. FShotgunServerSideRewindResult Confirm = ShotgunServerSideRewind(HitCharacters, TraceStart, HitLocations, HitTime);
  525.  
  526. for (auto& HitCharacter : HitCharacters)
  527. {
  528. if (HitCharacter == nullptr || HitCharacter->GetEquippedWeapon() == nullptr || Character == nullptr) continue;
  529. float TotalDamage = 0.f;
  530. if (Confirm.HeadShots.Contains(HitCharacter))
  531. {
  532. float HeadShotDamage = Confirm.HeadShots[HitCharacter] * HitCharacter->GetEquippedWeapon()->GetDamage();
  533. TotalDamage += HeadShotDamage;
  534. }
  535. if (Confirm.BodyShots.Contains(HitCharacter))
  536. {
  537. float BodyShotDamage = Confirm.BodyShots[HitCharacter] * HitCharacter->GetEquippedWeapon()->GetDamage();
  538. TotalDamage += BodyShotDamage;
  539. }
  540. UGameplayStatics::ApplyDamage(
  541. HitCharacter,
  542. TotalDamage,
  543. Character->Controller,
  544. HitCharacter->GetEquippedWeapon(),
  545. UDamageType::StaticClass()
  546. );
  547. }
  548. }
  549.  
  550. void ULagCompensationComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
  551. {
  552. Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
  553.  
  554. SaveFramePackage();
  555. }
  556.  
  557. void ULagCompensationComponent::SaveFramePackage()
  558. {
  559. if (Character == nullptr || !Character->HasAuthority()) return;
  560. if (FrameHistory.Num() <= 1)
  561. {
  562. FFramePackage ThisFrame;
  563. SaveFramePackage(ThisFrame);
  564. FrameHistory.AddHead(ThisFrame);
  565. }
  566. else
  567. {
  568. float HistoryLength = FrameHistory.GetHead()->GetValue().Time - FrameHistory.GetTail()->GetValue().Time;
  569. while (HistoryLength > MaxRecordTime)
  570. {
  571. FrameHistory.RemoveNode(FrameHistory.GetTail());
  572. HistoryLength = FrameHistory.GetHead()->GetValue().Time - FrameHistory.GetTail()->GetValue().Time;
  573. }
  574. FFramePackage ThisFrame;
  575. SaveFramePackage(ThisFrame);
  576. FrameHistory.AddHead(ThisFrame);
  577.  
  578. //ShowFramePackage(ThisFrame, FColor::Red);
  579. }
  580. }
  581.  
  582. void ULagCompensationComponent::SaveFramePackage(FFramePackage& Package)
  583. {
  584. Character = Character == nullptr ? Cast<ABlasterCharacter>(GetOwner()) : Character;
  585. if (Character)
  586. {
  587. Package.Time = GetWorld()->GetTimeSeconds();
  588. Package.Character = Character;
  589. for (auto& BoxPair : Character->HitCollisionBoxes)
  590. {
  591. FBoxInformation BoxInformation;
  592. BoxInformation.Location = BoxPair.Value->GetComponentLocation();
  593. BoxInformation.Rotation = BoxPair.Value->GetComponentRotation();
  594. BoxInformation.BoxExtent = BoxPair.Value->GetScaledBoxExtent();
  595. Package.HitBoxInfo.Add(BoxPair.Key, BoxInformation);
  596. }
  597. }
  598. }
  599.  
  600.  
  601.  
Advertisement
Add Comment
Please, Sign In to add comment