Unreal Engine——源码阅读:AbilitySystemComponent.h(UE5.4.4)

Unreal Engine——源码阅读:AbilitySystemComponent.h(UE5.4.4)

ELecmark VIP

这是Unreal Engine 5的官方源码文件,来自GameplayAbilities模块的AbilitySystemComponent.h头文件, 是Gameplay Ability System(GAS)的核心组件,提供了管理游戏能力、效果和属性的完整框架:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
// 版权归Epic Games, Inc.所有。保留所有权利。

#pragma once

#include "CoreMinimal.h"
#include "UObject/ObjectMacros.h"
#include "Templates/SubclassOf.h"
#include "Engine/NetSerialization.h"
#include "Engine/EngineTypes.h"
#include "Engine/TimerHandle.h"
#include "GameplayTagContainer.h"
#include "AttributeSet.h"
#include "EngineDefines.h"
#include "GameplayPrediction.h"
#include "GameplayCueInterface.h"
#include "GameplayTagAssetInterface.h"
#include "GameplayAbilitySpec.h"
#include "GameplayEffect.h"
#include "GameplayTasksComponent.h"
#include "Abilities/GameplayAbilityRepAnimMontage.h"
#include "Abilities/GameplayAbilityTargetTypes.h"
#include "Abilities/GameplayAbility.h"
#include "AbilitySystemReplicationProxyInterface.h"
#include "Net/Core/PushModel/PushModel.h"

#if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_2
#include "Abilities/GameplayAbilityTypes.h"
#include "GameplayEffectTypes.h"
#endif

#include "AbilitySystemComponent.generated.h"

class AGameplayAbilityTargetActor;
class AHUD;
class FDebugDisplayInfo;
class UAnimMontage;
class UAnimSequenceBase;
class UCanvas;
class UInputComponent;

/**
* UAbilitySystemComponent(技能系统组件)
*
* 一个用于轻松与技能系统三个主要方面交互的组件:
*
* 游戏技能:
* -提供给予/分配可用能力的方式(例如玩家或AI使用)
* -提供实例化能力的管理(需要有对象持有它们)
* -提供复制功能
* -能力状态必须在UGameplayAbility本身上复制,但UAbilitySystemComponent为实际的能力激活提供RPC复制
*
* 游戏效果:
* -提供FActiveGameplayEffectsContainer用于持有活跃的游戏效果
* -提供将游戏效果应用到目标或自身的方法
* -提供查询FActiveGameplayEffectsContainers中信息的包装器(持续时间、大小等)
* -提供清除/移除游戏效果的方法
*
* 游戏属性
* -提供分配和初始化属性集的方法
* -提供获取AttributeSets的方法
*
*/

/** 当目标选择角色拒绝目标确认时调用 */
DECLARE_MULTICAST_DELEGATE_OneParam(FTargetingRejectedConfirmation, int32);

/** 当能力激活失败时调用,传递失败的能力和解释原因的标签 */
DECLARE_MULTICAST_DELEGATE_TwoParams(FAbilityFailedDelegate, const UGameplayAbility*, const FGameplayTagContainer&);

/** 当能力结束时调用 */
DECLARE_MULTICAST_DELEGATE_OneParam(FAbilityEnded, UGameplayAbility*);

/** 通知感兴趣方能力规格已被修改 */
DECLARE_MULTICAST_DELEGATE_OneParam(FAbilitySpecDirtied, const FGameplayAbilitySpec&);

/** 当游戏效果规格被活跃游戏效果因免疫而阻止时通知 */
DECLARE_MULTICAST_DELEGATE_TwoParams(FImmunityBlockGE, const FGameplayEffectSpec& /*被阻止的规格*/, const FActiveGameplayEffect* /*免疫游戏效果*/);

/** 我们允许一系列委托来决定游戏效果的应用是否可以被阻止。如果被阻止,将调用上面的ImmunityBlockGE */
DECLARE_DELEGATE_RetVal_TwoParams(bool, FGameplayEffectApplicationQuery, const FActiveGameplayEffectsContainer& /*活跃GE容器*/, const FGameplayEffectSpec& /*待考虑的GE规格*/);

/** 游戏效果如何复制到客户端 */
UENUM()
enum class EGameplayEffectReplicationMode : uint8
{
/** 仅复制最少的游戏效果信息。注意:这不适用于拥有的技能系统组件(使用混合模式)。 */
Minimal,
/** 仅向模拟代理复制最少的游戏效果信息,但向所有者和自主代理复制完整信息 */
Mixed,
/** 向所有对象复制完整的游戏信息 */
Full,
};

/** 执行操作时(例如收集可激活能力),如何处理待处理项(例如尚未添加或移除的能力) */
enum class EConsiderPending : uint8
{
/** 不考虑任何待处理操作(例如待添加或待移除的能力) */
None = 0,

/** 执行操作时考虑待添加项 */
PendingAdd = (1 << 0),

/** 执行操作时考虑待移除项 */
PendingRemove = (1 << 1),

All = PendingAdd | PendingRemove
};
ENUM_CLASS_FLAGS(EConsiderPending)

/** 与游戏技能系统交互的核心ActorComponent */
UCLASS(ClassGroup=AbilitySystem, hidecategories=(Object,LOD,Lighting,Transform,Sockets,TextureStreaming), editinlinenew, meta=(BlueprintSpawnableComponent))
class GAMEPLAYABILITIES_API UAbilitySystemComponent : public UGameplayTasksComponent, public IGameplayTagAssetInterface, public IAbilitySystemReplicationProxyInterface
{
GENERATED_UCLASS_BODY()

/** 用于注册能力键输入的回调 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAbilityAbilityKey, /*UGameplayAbility*, Ability, */int32, InputID);

/** 用于注册确认/取消输入的回调 */
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FAbilityConfirmOrCancel);

/** 当效果被应用时的委托 */
DECLARE_MULTICAST_DELEGATE_ThreeParams(FOnGameplayEffectAppliedDelegate, UAbilitySystemComponent*, const FGameplayEffectSpec&, FActiveGameplayEffectHandle);

// ----------------------------------------------------------------------------------------------------------------
// 属性
// ----------------------------------------------------------------------------------------------------------------

/** 查找现有的属性集 */
template <class T >
const T* GetSet() const
{
return (T*)GetAttributeSubobject(T::StaticClass());
}

/** 查找现有的属性集。如果不存在则断言。 */
template <class T >
const T* GetSetChecked() const
{
return (T*)GetAttributeSubobjectChecked(T::StaticClass());
}

/** 添加新的属性集(初始化为默认值) */
template <class T >
const T* AddSet()
{
return (T*)GetOrCreateAttributeSubobject(T::StaticClass());
}

/**
* 手动添加作为此技能系统组件子对象的新属性集。
* 初始化期间会自动添加此组件的所有子对象。
*/
template <class T>
const T* AddAttributeSetSubobject(T* Subobject)
{
AddSpawnedAttribute(Subobject);
return Subobject;
}

/**
* 此技能系统组件是否拥有此属性?
*
* @param Attribute 要检索目标标签的游戏效果句柄
*
* @return 如果Attribute有效且此技能系统组件包含包含Attribute的属性集,则返回true。否则返回false。
*/
bool HasAttributeSetForAttribute(FGameplayAttribute Attribute) const;

/** 从数据表初始化起始属性。支持不佳,使用带有曲线表引用的游戏效果可能是更好的解决方案 */
const UAttributeSet* InitStats(TSubclassOf<class UAttributeSet> Attributes, const UDataTable* DataTable);

UFUNCTION(BlueprintCallable, Category="Skills", meta=(DisplayName="InitStats", ScriptName="InitStats"))
void K2_InitStats(TSubclassOf<class UAttributeSet> Attributes, const UDataTable* DataTable);

/** 返回此技能系统组件的所有属性列表 */
UFUNCTION(BlueprintPure, Category="Gameplay Attributes")
void GetAllAttributes(TArray<FGameplayAttribute>& OutAttributes);

/**
* 如果此组件中存在实例,则返回属性集实例的引用
*
* @param AttributeSetClass 要查找的属性集类型
* @param bFound 如果属性集实例存在,则设置为true
*/
UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "Gameplay Attributes")
const UAttributeSet* GetAttributeSet(TSubclassOf<UAttributeSet> AttributeSetClass) const;

/**
* 返回给定游戏属性的当前值,如果未找到属性则返回零。
* 注意:这不会考虑预测的游戏效果修改器,因此客户端上的值可能不总是准确的。
*
* @param Attribute 要查询的游戏属性
* @param bFound 如果此组件中存在该属性,则设置为true
*/
UFUNCTION(BlueprintPure, Category = "Gameplay Attributes")
float GetGameplayAttributeValue(FGameplayAttribute Attribute, bool& bFound) const;

UPROPERTY(EditAnywhere, Category="AttributeTest")
TArray<FAttributeDefaults> DefaultStartingData;

/** 移除所有当前属性集并注册传递的数组中的属性集。注意:可能时应直接调用添加/移除。 */
void SetSpawnedAttributes(const TArray<UAttributeSet*>& NewAttributeSet);

UE_DEPRECATED(5.1, "此函数将被设为私有。请使用添加/移除SpawnedAttributes代替")
TArray<TObjectPtr<UAttributeSet>>& GetSpawnedAttributes_Mutable();

/** 访问生成的属性列表,当您不打算修改列表时使用。 */
const TArray<UAttributeSet*>& GetSpawnedAttributes() const;

/** 添加新的属性集 */
void AddSpawnedAttribute(UAttributeSet* Attribute);

/** 移除现有的属性集 */
void RemoveSpawnedAttribute(UAttributeSet* Attribute);

/** 移除所有属性集 */
void RemoveAllSpawnedAttributes();

/** 此组件将播放蒙太奇的链接动画实例。使用NAME_None表示主动画实例。 */
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = "Skills")
FName AffectedAnimInstanceTag;

/** 设置属性的基础值。现有的活跃修改器不会被清除,并将作用于新的基础值。 */
void SetNumericAttributeBase(const FGameplayAttribute &Attribute, float NewBaseValue);

/** 获取属性的基础值。即没有任何状态性修改器的属性值 */
float GetNumericAttributeBase(const FGameplayAttribute &Attribute) const;

/**
* 对给定属性应用原地修改。这会正确更新属性的聚合器,更新属性集属性,
* 并调用OnDirty回调。
* 这不会调用属性集上的Pre/PostGameplayEffectExecute。这不进行标签检查、应用要求、免疫等。
* 不会创建或应用GameplayEffectSpec!
* 这应仅在应用真实的GameplayEffectSpec太慢或不可能的情况下使用。
*/
void ApplyModToAttribute(const FGameplayAttribute &Attribute, TEnumAsByte<EGameplayModOp::Type> ModifierOp, float ModifierMagnitude);

/**
* 对给定属性应用原地修改。与ApplyModToAttribute不同,此函数将在客户端或服务器上运行。
* 这可能导致与预测相关的问题,并且无法正确回滚。
*/
void ApplyModToAttributeUnsafe(const FGameplayAttribute &Attribute, TEnumAsByte<EGameplayModOp::Type> ModifierOp, float ModifierMagnitude);

/** 返回属性的当前(最终)值 */
float GetNumericAttribute(const FGameplayAttribute &Attribute) const;
float GetNumericAttributeChecked(const FGameplayAttribute &Attribute) const;

/** 返回应用标签过滤器后的属性值 */
float GetFilteredAttributeValue(const FGameplayAttribute& Attribute, const FGameplayTagRequirements& SourceTags, const FGameplayTagContainer& TargetTags, const TArray<FActiveGameplayEffectHandle>& HandlesToIgnore = TArray<FActiveGameplayEffectHandle>());

// ----------------------------------------------------------------------------------------------------------------
// 复制
// ----------------------------------------------------------------------------------------------------------------

/** 强制头像Actor更新其复制。对于需要为移动/位置原因进行复制等情况很有用。 */
virtual void ForceAvatarReplication();

/** 当为true时,我们将不会为此技能系统组件复制活跃游戏效果,因此属性和标签 */
virtual void SetReplicationMode(EGameplayEffectReplicationMode NewReplicationMode);

/** 游戏效果如何被复制 */
EGameplayEffectReplicationMode ReplicationMode;

/** 如果启用ReplicationProxy,通过谁路由复制(如果返回null,当启用ReplicationProxy时,我们将不会复制) */
virtual IAbilitySystemReplicationProxyInterface* GetReplicationInterface();

/** 当前预测键,使用FScopedPredictionWindow设置 */
FPredictionKey ScopedPredictionKey;

/** 返回应用于任何操作的预测键 */
FPredictionKey GetPredictionKeyForNewAction() const
{
return ScopedPredictionKey.IsValidForMorePrediction() ? ScopedPredictionKey : FPredictionKey();
}

/** 我们是否有有效的预测键来进行更多预测操作 */
bool CanPredict() const
{
return ScopedPredictionKey.IsValidForMorePrediction();
}

/** 如果这在服务器上运行或具有有效的预测键,则返回true */
bool HasAuthorityOrPredictionKey(const FGameplayAbilityActivationInfo* ActivationInfo) const;

/** 如果此组件的Actor具有权限,则返回true */
virtual bool IsOwnerActorAuthoritative() const;

/** 如果此组件应记录蒙太奇复制信息,则返回true */
virtual bool ShouldRecordMontageReplication() const;

/** 向客户端或服务器(视情况而定)复制能力已结束/取消 */
virtual void ReplicateEndOrCancelAbility(FGameplayAbilitySpecHandle Handle, FGameplayAbilityActivationInfo ActivationInfo, UGameplayAbility* Ability, bool bWasCanceled);

/** 强制取消能力且不向另一端复制此操作。当能力被另一端取消时应调用此函数 */
virtual void ForceCancelAbilityDueToReplication(UGameplayAbility* Instance);

/** 无法立即激活的待处理激活,将在稍后时间点重新检查 */
struct FPendingAbilityInfo
{
bool operator==(const FPendingAbilityInfo& Other) const
{
// 不比较事件数据,不允许在具有相同键和句柄但不同事件数据的多个激活在飞行中
return PredictionKey == Other.PredictionKey && Handle == Other.Handle;
}

/** 需要激活的能力属性 */
FGameplayAbilitySpecHandle Handle;
FPredictionKey PredictionKey;
FGameplayEventData TriggerEventData;

/** 如果此能力已在远程激活且需要跟进,则为true;如果能力尚未激活,则为false */
bool bPartiallyActivated;

FPendingAbilityInfo()
: bPartiallyActivated(false)
{}
};

/** 这是在服务器上激活但尚不能在客户端执行的能力列表。它将在稍后时间点尝试执行这些操作 */
TArray<FPendingAbilityInfo> PendingServerActivatedAbilities;

// ----------------------------------------------------------------------------------------------------------------
// 游戏效果:供其他系统使用的主要对外API
// ----------------------------------------------------------------------------------------------------------------

/** 将先前创建的游戏效果规格应用于目标 */
UFUNCTION(BlueprintCallable, Category = GameplayEffects, meta = (DisplayName = "ApplyGameplayEffectSpecToTarget", ScriptName = "ApplyGameplayEffectSpecToTarget"))
FActiveGameplayEffectHandle BP_ApplyGameplayEffectSpecToTarget(const FGameplayEffectSpecHandle& SpecHandle, UAbilitySystemComponent* Target);

virtual FActiveGameplayEffectHandle ApplyGameplayEffectSpecToTarget(const FGameplayEffectSpec& GameplayEffect, UAbilitySystemComponent *Target, FPredictionKey PredictionKey=FPredictionKey());

/** 将先前创建的游戏效果规格应用到此组件 */
UFUNCTION(BlueprintCallable, Category = GameplayEffects, meta = (DisplayName = "ApplyGameplayEffectSpecToSelf", ScriptName = "ApplyGameplayEffectSpecToSelf"))
FActiveGameplayEffectHandle BP_ApplyGameplayEffectSpecToSelf(const FGameplayEffectSpecHandle& SpecHandle);

virtual FActiveGameplayEffectHandle ApplyGameplayEffectSpecToSelf(const FGameplayEffectSpec& GameplayEffect, FPredictionKey PredictionKey = FPredictionKey());

/** 基于传入的句柄获取FActiveGameplayEffect */
const UGameplayEffect* GetGameplayEffectDefForHandle(FActiveGameplayEffectHandle Handle);

/** 通过句柄移除游戏效果。StacksToRemove=-1将移除所有堆栈。 */
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = GameplayEffects)
virtual bool RemoveActiveGameplayEffect(FActiveGameplayEffectHandle Handle, int32 StacksToRemove=-1);

/**
* 移除其后端定义是特定游戏效果类的活跃游戏效果
*
* @param GameplayEffect 要移除的游戏效果类;如果留空则不执行任何操作
* @param InstigatorAbilitySystemComponent 如果指定,将仅移除从此发起者技能系统组件应用的游戏效果
* @param StacksToRemove 要移除的堆栈数,-1表示移除所有
*/
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = GameplayEffects)
virtual void RemoveActiveGameplayEffectBySourceEffect(TSubclassOf<UGameplayEffect> GameplayEffect, UAbilitySystemComponent* InstigatorAbilitySystemComponent, int32 StacksToRemove = -1);

/** 获取准备应用于其他对象的传出GameplayEffectSpec。 */
UFUNCTION(BlueprintCallable, Category = GameplayEffects)
virtual FGameplayEffectSpecHandle MakeOutgoingSpec(TSubclassOf<UGameplayEffect> GameplayEffectClass, float Level, FGameplayEffectContextHandle Context) const;

/** 为此AbilitySystemComponent的所有者创建EffectContext */
UFUNCTION(BlueprintCallable, Category = GameplayEffects)
virtual FGameplayEffectContextHandle MakeEffectContext() const;

/**
* 获取技能系统组件上指定源效果的数量。对于非堆叠效果,这是所有活跃实例的总和。
* 对于堆叠效果,这是所有有效堆叠计数的总和。如果指定了发起者,则仅计算来自该发起者的效果。
*
* @param SourceGameplayEffect 要计数的效果
* @param OptionalInstigatorFilterComponent 如果指定,仅计算由此技能系统组件应用的效果
*
* @return 指定源效果的计数
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category=GameplayEffects)
int32 GetGameplayEffectCount(TSubclassOf<UGameplayEffect> SourceGameplayEffect, UAbilitySystemComponent* OptionalInstigatorFilterComponent, bool bEnforceOnGoingCheck = true) const;

/**
* 获取技能系统组件上指定源效果的数量。对于非堆叠效果,这是所有活跃实例的总和。
* 对于堆叠效果,这是所有有效堆叠计数的总和。如果指定了发起者,则仅计算来自该发起者的效果。
*
* @param SoftSourceGameplayEffect 要计数的效果。如果当前未加载,则计数为0
* @param OptionalInstigatorFilterComponent 如果指定,仅计算由此技能系统组件应用的效果
*
* @return 指定源效果的计数
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = GameplayEffects)
int32 GetGameplayEffectCount_IfLoaded(TSoftClassPtr<UGameplayEffect> SoftSourceGameplayEffect, UAbilitySystemComponent* OptionalInstigatorFilterComponent, bool bEnforceOnGoingCheck = true) const;

/** 返回通过查询的所有游戏效果的StackCount总和 */
int32 GetAggregatedStackCount(const FGameplayEffectQuery& Query) const;

/** 此函数仅存在以便可以连接到多播委托 */
void RemoveActiveGameplayEffect_NoReturn(FActiveGameplayEffectHandle Handle, int32 StacksToRemove=-1)
{
RemoveActiveGameplayEffect(Handle, StacksToRemove);
}

/** 为预测添加的游戏提示调用。需要移除标签计数并在错误预测时可能调用OnRemove事件 */
virtual void OnPredictiveGameplayCueCatchup(FGameplayTag Tag);

/** 返回游戏效果的总持续时间 */
float GetGameplayEffectDuration(FActiveGameplayEffectHandle Handle) const;

/** 每当服务器时间通过游戏状态复制时调用,以保持我们的冷却计时器与服务器同步 */
virtual void RecomputeGameplayEffectStartTimes(const float WorldTime, const float ServerWorldTime);

/** 返回游戏效果的开始时间和总持续时间 */
void GetGameplayEffectStartTimeAndDuration(FActiveGameplayEffectHandle Handle, float& StartEffectTime, float& Duration) const;

/** 动态更新活跃游戏效果的set-by-caller大小 */
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = GameplayEffects)
virtual void UpdateActiveGameplayEffectSetByCallerMagnitude(FActiveGameplayEffectHandle ActiveHandle, UPARAM(meta=(Categories = "SetByCaller"))FGameplayTag SetByCallerTag, float NewValue);

/** 动态更新活跃游戏效果的多个set-by-caller大小 */
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = GameplayEffects)
virtual void UpdateActiveGameplayEffectSetByCallerMagnitudes(FActiveGameplayEffectHandle ActiveHandle, const TMap<FGameplayTag, float>& NewSetByCallerValues);

/** 更新已应用游戏效果的等级。意图是这是'无缝的',不会像移除/重新应用那样行为 */
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = GameplayEffects)
virtual void SetActiveGameplayEffectLevel(FActiveGameplayEffectHandle ActiveHandle, int32 NewLevel);

/** 更新已应用游戏效果的等级。意图是这是'无缝的',不会像移除/重新应用那样行为 */
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = GameplayEffects)
virtual void SetActiveGameplayEffectLevelUsingQuery(FGameplayEffectQuery Query, int32 NewLevel);

/** 抑制活跃游戏效果,使其被禁用但未被移除 */
UE_DEPRECATED(5.4, "请使用SetActiveGameplayEffectInhibit并传递MoveTemp(ActiveGEHandle),以便清楚地表明句柄不再有效。检查(然后使用)返回的FActiveGameplayEffectHandle以继续您的操作。")
virtual void InhibitActiveGameplayEffect(FActiveGameplayEffectHandle ActiveGEHandle, bool bInhibit, bool bInvokeGameplayCueEvents);

/**
* (取消)抑制活跃游戏效果,使其可能被禁用(并执行一些禁用操作,例如移除标签)。
* 被抑制的活跃游戏效果将处于休眠状态,以便在某些条件下(通常是标签)重新启用。当它被取消抑制时,将重新应用其部分功能。
* 注意:传入的ActiveGEHandle不再有效。使用返回的FActiveGameplayEffectHandle确定活跃GE句柄是否仍然活跃。
*/
virtual FActiveGameplayEffectHandle SetActiveGameplayEffectInhibit(FActiveGameplayEffectHandle&& ActiveGEHandle, bool bInhibit, bool bInvokeGameplayCueEvents);

/**
* 原始访问器,询问游戏效果的大小,不一定总是正确的。外部代码(UI等)应如何询问诸如'此游戏效果修改我的伤害多少'之类的问题
* (很可能我们希望在后台捕获这一点 - 当应用伤害时,我们可以获得数字如何达到当前状态的完整转储/历史。但我们仍然可能需要像下面这样的轮询方法(我的伤害会是多少)
*/
UFUNCTION(BlueprintCallable, Category = GameplayEffects)
float GetGameplayEffectMagnitude(FActiveGameplayEffectHandle Handle, FGameplayAttribute Attribute) const;

/** 返回已应用GE的当前堆叠计数 */
int32 GetCurrentStackCount(FActiveGameplayEffectHandle Handle) const;

/** 返回已应用GE的当前堆叠计数,但给定由GE授予的能力规格句柄 */
int32 GetCurrentStackCount(FGameplayAbilitySpecHandle Handle) const;

/** 返回描述活跃游戏效果的调试字符串 */
FString GetActiveGEDebugString(FActiveGameplayEffectHandle Handle) const;

/** 获取授予传入能力的GE句柄 */
FActiveGameplayEffectHandle FindActiveGameplayEffectHandle(FGameplayAbilitySpecHandle Handle) const;

/** 返回实际活跃游戏效果结构的常量指针 */
const FActiveGameplayEffect* GetActiveGameplayEffect(const FActiveGameplayEffectHandle Handle) const;

/** 返回此ASC上的所有活跃游戏效果 */
const FActiveGameplayEffectsContainer& GetActiveGameplayEffects() const;

/** 返回与活跃句柄关联的游戏效果CDO的常量指针。 */
const UGameplayEffect* GetGameplayEffectCDO(const FActiveGameplayEffectHandle Handle) const;

/**
* 如果可能,从指定句柄表示的游戏规格中获取源标签
*
* @param Handle 要从中检索源标签的游戏效果句柄
*
* @return 如果可能,从句柄表示的游戏规格中获取的源标签
*/
const FGameplayTagContainer* GetGameplayEffectSourceTagsFromHandle(FActiveGameplayEffectHandle Handle) const;

/**
* 如果可能,从指定句柄表示的游戏规格中获取目标标签
*
* @param Handle 要从中检索目标标签的游戏效果句柄
*
* @return 如果可能,从句柄表示的游戏规格中获取的目标标签
*/
const FGameplayTagContainer* GetGameplayEffectTargetTagsFromHandle(FActiveGameplayEffectHandle Handle) const;

/**
* 使用从组件捕获属性所需的数据填充指定的捕获规格
*
* @param OutCaptureSpec [输出] 用捕获数据填充的捕获规格
*/
void CaptureAttributeForGameplayEffect(OUT FGameplayEffectAttributeCaptureSpec& OutCaptureSpec);

// ----------------------------------------------------------------------------------------------------------------
// 回调/通知
// (这些需要在UObject级别,以便我们可以安全绑定,而不是绑定到ActiveGameplayEffect/Container级别的原始指针,这在AbilitySystemComponent被销毁时是不安全的)
// ----------------------------------------------------------------------------------------------------------------

/** 当特定属性聚合器值更改时调用,游戏效果在此发生时刷新其值 */
void OnAttributeAggregatorDirty(FAggregator* Aggregator, FGameplayAttribute Attribute, bool FromRecursiveCall=false);

/** 当属性大小更改时调用,以将信息转发给依赖的游戏效果 */
void OnMagnitudeDependencyChange(FActiveGameplayEffectHandle Handle, const FAggregator* ChangedAggregator);

/** 此ASC已成功将GE应用于某物(可能自身) */
void OnGameplayEffectAppliedToTarget(UAbilitySystemComponent* Target, const FGameplayEffectSpec& SpecApplied, FActiveGameplayEffectHandle ActiveHandle);
void OnGameplayEffectAppliedToSelf(UAbilitySystemComponent* Source, const FGameplayEffectSpec& SpecApplied, FActiveGameplayEffectHandle ActiveHandle);
void OnPeriodicGameplayEffectExecuteOnTarget(UAbilitySystemComponent* Target, const FGameplayEffectSpec& SpecExecuted, FActiveGameplayEffectHandle ActiveHandle);
void OnPeriodicGameplayEffectExecuteOnSelf(UAbilitySystemComponent* Source, const FGameplayEffectSpec& SpecExecuted, FActiveGameplayEffectHandle ActiveHandle);

/** 当游戏效果的持续时间更改时调用 */
virtual void OnGameplayEffectDurationChange(struct FActiveGameplayEffect& ActiveEffect);

/** 每当GE应用于自身时在服务器上调用。这包括即时和基于持续时间的GE。 */
FOnGameplayEffectAppliedDelegate OnGameplayEffectAppliedDelegateToSelf;

/** 每当GE应用于其他对象时在服务器上调用。这包括即时和基于持续时间的GE。 */
FOnGameplayEffectAppliedDelegate OnGameplayEffectAppliedDelegateToTarget;

/** 每当添加基于持续时间的GE时在客户端和服务器上调用(例如,即时GE不会触发此操作)。 */
FOnGameplayEffectAppliedDelegate OnActiveGameplayEffectAddedDelegateToSelf;

/** 每当周期性GE在自身上执行时在服务器上调用 */
FOnGameplayEffectAppliedDelegate OnPeriodicGameplayEffectExecuteDelegateOnSelf;

/** 每当周期性GE在目标上执行时在服务器上调用 */
FOnGameplayEffectAppliedDelegate OnPeriodicGameplayEffectExecuteDelegateOnTarget;

/** 免疫通知支持 */
FImmunityBlockGE OnImmunityBlockGameplayEffectDelegate;

/** 注册属性值更改时,应被GetGameplayAttributeValueChangeDelegate替换 */
FOnGameplayAttributeChange& RegisterGameplayAttributeEvent(FGameplayAttribute Attribute);

/** 注册属性值更改时 */
FOnGameplayAttributeValueChange& GetGameplayAttributeValueChangeDelegate(FGameplayAttribute Attribute);

/** 能力被激活(开始)时的通用回调 */
FGenericAbilityDelegate AbilityActivatedCallbacks;

/** 能力结束时的回调 */
FAbilityEnded AbilityEndedCallbacks;

/** 能力结束时的回调,带有额外信息 */
FGameplayAbilityEndedDelegate OnAbilityEnded;

/** 能力被提交(应用成本/冷却)时的通用回调 */
FGenericAbilityDelegate AbilityCommittedCallbacks;

/** 能力激活失败时调用,带有失败原因 */
FAbilityFailedDelegate AbilityFailedCallbacks;

/** 能力规格内部更改时调用 */
FAbilitySpecDirtied AbilitySpecDirtiedCallbacks;

/** 我们允许用户设置一系列必须为true才能允许应用游戏效果的函数 */
TArray<FGameplayEffectApplicationQuery> GameplayEffectApplicationQueries;

/** 调用上面的通知回调 */
virtual void NotifyAbilityCommit(UGameplayAbility* Ability);
virtual void NotifyAbilityActivated(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability);
virtual void NotifyAbilityFailed(const FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, const FGameplayTagContainer& FailureReason);

/** 当任何游戏效果被移除时调用 */
FOnGivenActiveGameplayEffectRemoved& OnAnyGameplayEffectRemovedDelegate();

/** 返回允许绑定到多个游戏效果更改的委托结构 */
FActiveGameplayEffectEvents* GetActiveEffectEventSet(FActiveGameplayEffectHandle Handle);
FOnActiveGameplayEffectRemoved_Info* OnGameplayEffectRemoved_InfoDelegate(FActiveGameplayEffectHandle Handle);
FOnActiveGameplayEffectStackChange* OnGameplayEffectStackChangeDelegate(FActiveGameplayEffectHandle Handle);
FOnActiveGameplayEffectTimeChange* OnGameplayEffectTimeChangeDelegate(FActiveGameplayEffectHandle Handle);
FOnActiveGameplayEffectInhibitionChanged* OnGameplayEffectInhibitionChangedDelegate(FActiveGameplayEffectHandle Handle);

// ----------------------------------------------------------------------------------------------------------------
// 游戏标签操作
// 使用TagCountContainer实现IGameplayTagAssetInterface
// ----------------------------------------------------------------------------------------------------------------
FORCEINLINE bool HasMatchingGameplayTag(FGameplayTag TagToCheck) const override
{
return GameplayTagCountContainer.HasMatchingGameplayTag(TagToCheck);
}

FORCEINLINE bool HasAllMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const override
{
return GameplayTagCountContainer.HasAllMatchingGameplayTags(TagContainer);
}

FORCEINLINE bool HasAnyMatchingGameplayTags(const FGameplayTagContainer& TagContainer) const override
{
return GameplayTagCountContainer.HasAnyMatchingGameplayTags(TagContainer);
}

FORCEINLINE void GetOwnedGameplayTags(FGameplayTagContainer& TagContainer) const override
{
TagContainer.Reset();
TagContainer.AppendTags(GetOwnedGameplayTags());
}

[[nodiscard]] FORCEINLINE const FGameplayTagContainer& GetOwnedGameplayTags() const
{
return GameplayTagCountContainer.GetExplicitGameplayTags();
}

/** 检查查询是否与拥有的GameplayTags匹配 */
FORCEINLINE bool MatchesGameplayTagQuery(const FGameplayTagQuery& TagQuery) const
{
return TagQuery.Matches(GameplayTagCountContainer.GetExplicitGameplayTags());
}

/** 返回给定标签的实例数量 */
FORCEINLINE int32 GetTagCount(FGameplayTag TagToCheck) const
{
return GameplayTagCountContainer.GetTagCount(TagToCheck);
}

/** 强制设置给定标签的实例数量 */
FORCEINLINE void SetTagMapCount(const FGameplayTag& Tag, int32 NewCount)
{
GameplayTagCountContainer.SetTagCount(Tag, NewCount);
}

/** 更新给定标签的实例数量并调用回调 */
FORCEINLINE void UpdateTagMap(const FGameplayTag& BaseTag, int32 CountDelta)
{
if (GameplayTagCountContainer.UpdateTagCount(BaseTag, CountDelta))
{
OnTagUpdated(BaseTag, CountDelta > 0);
}
}

/** 更新给定标签的实例数量并调用回调 */
FORCEINLINE void UpdateTagMap(const FGameplayTagContainer& Container, int32 CountDelta)
{
if (!Container.IsEmpty())
{
UpdateTagMap_Internal(Container, CountDelta);
}
}

/** 用BlockedAbilityTags填充TagContainer */
FORCEINLINE void GetBlockedAbilityTags(FGameplayTagContainer& TagContainer) const
{
TagContainer.AppendTags(GetBlockedAbilityTags());
}

[[nodiscard]] FORCEINLINE const FGameplayTagContainer& GetBlockedAbilityTags() const
{
return BlockedAbilityTags.GetExplicitGameplayTags();
}

/**
* 允许游戏代码添加不受游戏效果支持的松散游戏标签。
* 以此方式添加的标签不会被复制!如果需要复制,请使用这些函数的'Replicated'版本。
* 由调用游戏代码确保这些标签在必要的客户端/服务器上添加
*/
FORCEINLINE void AddLooseGameplayTag(const FGameplayTag& GameplayTag, int32 Count=1)
{
UpdateTagMap(GameplayTag, Count);
}

FORCEINLINE void AddLooseGameplayTags(const FGameplayTagContainer& GameplayTags, int32 Count = 1)
{
UpdateTagMap(GameplayTags, Count);
}

FORCEINLINE void RemoveLooseGameplayTag(const FGameplayTag& GameplayTag, int32 Count = 1)
{
UpdateTagMap(GameplayTag, -Count);
}

FORCEINLINE void RemoveLooseGameplayTags(const FGameplayTagContainer& GameplayTags, int32 Count = 1)
{
UpdateTagMap(GameplayTags, -Count);
}

FORCEINLINE void SetLooseGameplayTagCount(const FGameplayTag& GameplayTag, int32 NewCount)
{
SetTagMapCount(GameplayTag, NewCount);
}

/**
* 返回给定游戏标签的当前计数。
* 这包括松散标签以及由游戏效果和能力授予的标签。
* 此函数可以在客户端上调用,但它可能不会显示服务器上的最新计数。
*
* @param GameplayTag 要查询的游戏标签
*/
UFUNCTION(BlueprintPure, Category = "Gameplay Tags")
int32 GetGameplayTagCount(FGameplayTag GameplayTag) const;

/**
* 允许游戏代码添加不受游戏效果支持的松散游戏标签。使用
* 这些函数添加的标签将被复制。注意:复制的松散标签将覆盖模拟代理上任何本地设置的标签计数
* 在模拟代理上的任何本地设置的标签计数。
*/
FORCEINLINE void AddReplicatedLooseGameplayTag(const FGameplayTag& GameplayTag)
{
GetReplicatedLooseTags_Mutable().AddTag(GameplayTag);
}

FORCEINLINE void AddReplicatedLooseGameplayTags(const FGameplayTagContainer& GameplayTags)
{
GetReplicatedLooseTags_Mutable().AddTags(GameplayTags);
}

FORCEINLINE void RemoveReplicatedLooseGameplayTag(const FGameplayTag& GameplayTag)
{
GetReplicatedLooseTags_Mutable().RemoveTag(GameplayTag);
}

FORCEINLINE void RemoveReplicatedLooseGameplayTags(const FGameplayTagContainer& GameplayTags)
{
GetReplicatedLooseTags_Mutable().RemoveTags(GameplayTags);
}

FORCEINLINE void SetReplicatedLooseGameplayTagCount(const FGameplayTag& GameplayTag, int32 NewCount)
{
GetReplicatedLooseTags_Mutable().SetTagCount(GameplayTag, NewCount);
}

/**
* 最小复制标签是在bMinimalReplication模式下从GE复制的标签。
* (GE不复制,但它们授予的标签通过这些函数复制)
*/
FORCEINLINE void AddMinimalReplicationGameplayTag(const FGameplayTag& GameplayTag)
{
GetMinimalReplicationTags_Mutable().AddTag(GameplayTag);
}

FORCEINLINE void AddMinimalReplicationGameplayTags(const FGameplayTagContainer& GameplayTags)
{
GetMinimalReplicationTags_Mutable().AddTags(GameplayTags);
}

FORCEINLINE void RemoveMinimalReplicationGameplayTag(const FGameplayTag& GameplayTag)
{
GetMinimalReplicationTags_Mutable().RemoveTag(GameplayTag);
}

FORCEINLINE void RemoveMinimalReplicationGameplayTags(const FGameplayTagContainer& GameplayTags)
{
GetMinimalReplicationTags_Mutable().RemoveTags(GameplayTags);
}

/** 允许为特定游戏标签的添加或移除注册事件 */
FOnGameplayEffectTagCountChanged& RegisterGameplayTagEvent(FGameplayTag Tag, EGameplayTagEventType::Type EventType=EGameplayTagEventType::NewOrRemoved);

/** 取消注册先前添加的事件 */
bool UnregisterGameplayTagEvent(FDelegateHandle DelegateHandle, FGameplayTag Tag, EGameplayTagEventType::Type EventType=EGameplayTagEventType::NewOrRemoved);

/** 注册标签事件并立即调用它 */
FDelegateHandle RegisterAndCallGameplayTagEvent(FGameplayTag Tag, FOnGameplayEffectTagCountChanged::FDelegate Delegate, EGameplayTagEventType::Type EventType=EGameplayTagEventType::NewOrRemoved);

/** 返回多播委托,每当标签被添加或移除时调用(但不仅计数增加时。仅适用于'new'和'removed'事件) */
FOnGameplayEffectTagCountChanged& RegisterGenericGameplayTagEvent();

/** 执行游戏事件。返回由事件触发的成功能力激活数量 */
virtual int32 HandleGameplayEvent(FGameplayTag EventTag, const FGameplayEventData* Payload);

/** 添加新的委托以在游戏事件发生时调用。仅当匹配传递的过滤器容器中的任何标签时才会被调用 */
FDelegateHandle AddGameplayEventTagContainerDelegate(const FGameplayTagContainer& TagFilter, const FGameplayEventTagMulticastDelegate::FDelegate& Delegate);

/** 移除先前注册的委托 */
void RemoveGameplayEventTagContainerDelegate(const FGameplayTagContainer& TagFilter, FDelegateHandle DelegateHandle);

/** 绑定到游戏标签的回调,仅在使用确切标签时激活。要处理标签层次结构,请使用AddGameplayEventContainerDelegate */
TMap<FGameplayTag, FGameplayEventMulticastDelegate> GenericGameplayEventCallbacks;

// ----------------------------------------------------------------------------------------------------------------
// 系统属性
// ----------------------------------------------------------------------------------------------------------------

/** 修改此组件创建的游戏效果的持续时间的内部属性 */
UPROPERTY(meta=(SystemGameplayAttribute="true"))
float OutgoingDuration;

/** 修改应用于此组件的游戏效果的持续时间的内部属性 */
UPROPERTY(meta = (SystemGameplayAttribute = "true"))
float IncomingDuration;

static FProperty* GetOutgoingDurationProperty();
static FProperty* GetIncomingDurationProperty();

static const FGameplayEffectAttributeCaptureDefinition& GetOutgoingDurationCapture();
static const FGameplayEffectAttributeCaptureDefinition& GetIncomingDurationCapture();

// ----------------------------------------------------------------------------------------------------------------
// 额外辅助函数
// ----------------------------------------------------------------------------------------------------------------

/** 将游戏效果应用于传入的目标 */
UFUNCTION(BlueprintCallable, Category = GameplayEffects, meta=(DisplayName = "ApplyGameplayEffectToTarget", ScriptName = "ApplyGameplayEffectToTarget"))
FActiveGameplayEffectHandle BP_ApplyGameplayEffectToTarget(TSubclassOf<UGameplayEffect> GameplayEffectClass, UAbilitySystemComponent *Target, float Level, FGameplayEffectContextHandle Context);
FActiveGameplayEffectHandle ApplyGameplayEffectToTarget(UGameplayEffect *GameplayEffect, UAbilitySystemComponent *Target, float Level = UGameplayEffect::INVALID_LEVEL, FGameplayEffectContextHandle Context = FGameplayEffectContextHandle(), FPredictionKey PredictionKey = FPredictionKey());

/** 将游戏效果应用于自身 */
UFUNCTION(BlueprintCallable, Category = GameplayEffects, meta=(DisplayName = "ApplyGameplayEffectToSelf", ScriptName = "ApplyGameplayEffectToSelf"))
FActiveGameplayEffectHandle BP_ApplyGameplayEffectToSelf(TSubclassOf<UGameplayEffect> GameplayEffectClass, float Level, FGameplayEffectContextHandle EffectContext);
FActiveGameplayEffectHandle ApplyGameplayEffectToSelf(const UGameplayEffect *GameplayEffect, float Level, const FGameplayEffectContextHandle& EffectContext, FPredictionKey PredictionKey = FPredictionKey());

/** 返回当前在此技能系统组件上活跃的游戏效果数量 */
int32 GetNumActiveGameplayEffects() const
{
return ActiveGameplayEffects.GetNumGameplayEffects();
}

/** 复制此能力组件上的所有活跃效果 */
void GetAllActiveGameplayEffectSpecs(TArray<FGameplayEffectSpec>& OutSpecCopies) const
{
ActiveGameplayEffects.GetAllActiveGameplayEffectSpecs(OutSpecCopies);
}

/** 在OnRep函数中调用以在客户端上设置属性基础值 */
void SetBaseAttributeValueFromReplication(const FGameplayAttribute& Attribute, float NewValue, float OldValue)
{
ActiveGameplayEffects.SetBaseAttributeValueFromReplication(Attribute, NewValue, OldValue);
}

/** 在OnRep函数中调用以在客户端上设置属性基础值 */
void SetBaseAttributeValueFromReplication(const FGameplayAttribute& Attribute, const FGameplayAttributeData& NewValue, const FGameplayAttributeData& OldValue)
{
ActiveGameplayEffects.SetBaseAttributeValueFromReplication(Attribute, NewValue.GetBaseValue(), OldValue.GetBaseValue());
}

/** 测试此游戏效果中的所有修改器是否会使属性 > 0.f */
bool CanApplyAttributeModifiers(const UGameplayEffect *GameplayEffect, float Level, const FGameplayEffectContextHandle& EffectContext)
{
return ActiveGameplayEffects.CanApplyAttributeModifiers(GameplayEffect, Level, EffectContext);
}

/** 获取匹配查询的所有效果的剩余时间 */
TArray<float> GetActiveEffectsTimeRemaining(const FGameplayEffectQuery& Query) const;

/** 获取匹配查询的所有效果的总持续时间 */
TArray<float> GetActiveEffectsDuration(const FGameplayEffectQuery& Query) const;

/** 获取匹配查询的所有效果的剩余时间和总持续时间 */
TArray<TPair<float,float>> GetActiveEffectsTimeRemainingAndDuration(const FGameplayEffectQuery& Query) const;

/** 返回查询的活跃效果列表 */
UFUNCTION(BlueprintCallable, BlueprintPure=false, Category = "Gameplay Effects", meta=(DisplayName = "Get Active Gameplay Effects for Query"))
TArray<FActiveGameplayEffectHandle> GetActiveEffects(const FGameplayEffectQuery& Query) const;

/** 返回具有所有传入标签的活跃效果列表 */
UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "Gameplay Effects")
TArray<FActiveGameplayEffectHandle> GetActiveEffectsWithAllTags(FGameplayTagContainer Tags) const;

/** 这将给出匹配此查询的所有效果将完成的世界时间。如果多个效果匹配,则返回最后完成的效果 */
float GetActiveEffectsEndTime(const FGameplayEffectQuery& Query) const;
float GetActiveEffectsEndTimeWithInstigators(const FGameplayEffectQuery& Query, TArray<AActor*>& Instigators) const;

/** 返回结束时间和总持续时间 */
bool GetActiveEffectsEndTimeAndDuration(const FGameplayEffectQuery& Query, float& EndTime, float& Duration) const;

/** 修改游戏效果的开始时间,以处理计时器最初不同步的问题 */
virtual void ModifyActiveEffectStartTime(FActiveGameplayEffectHandle Handle, float StartTimeDiff);

/** 移除包含Tags中任何标签的所有活跃效果 */
UFUNCTION(BlueprintCallable, Category = GameplayEffects)
int32 RemoveActiveEffectsWithTags(FGameplayTagContainer Tags);

/** 移除具有包含Tags中任何标签的捕获源标签的所有活跃效果 */
UFUNCTION(BlueprintCallable, Category = GameplayEffects)
int32 RemoveActiveEffectsWithSourceTags(FGameplayTagContainer Tags);

/** 移除应用Tags中任何标签的所有活跃效果 */
UFUNCTION(BlueprintCallable, Category = GameplayEffects)
int32 RemoveActiveEffectsWithAppliedTags(FGameplayTagContainer Tags);

/** 移除授予Tags中任何标签的所有活跃效果 */
UFUNCTION(BlueprintCallable, Category = GameplayEffects)
int32 RemoveActiveEffectsWithGrantedTags(FGameplayTagContainer Tags);

/** 移除匹配给定查询的所有活跃效果。StacksToRemove=-1将移除所有堆栈。 */
virtual int32 RemoveActiveEffects(const FGameplayEffectQuery& Query, int32 StacksToRemove = -1);

// ----------------------------------------------------------------------------------------------------------------
// 游戏提示
// ----------------------------------------------------------------------------------------------------------------

// 不要直接调用这些函数,而是调用GameplayCueManager上的包装器
UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCueExecuted_FromSpec(const FGameplayEffectSpecForRPC Spec, FPredictionKey PredictionKey) override;

UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCueExecuted(const FGameplayTag GameplayCueTag, FPredictionKey PredictionKey, FGameplayEffectContextHandle EffectContext) override;

UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCuesExecuted(const FGameplayTagContainer GameplayCueTags, FPredictionKey PredictionKey, FGameplayEffectContextHandle EffectContext) override;

UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCueExecuted_WithParams(const FGameplayTag GameplayCueTag, FPredictionKey PredictionKey, FGameplayCueParameters GameplayCueParameters) override;

UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCuesExecuted_WithParams(const FGameplayTagContainer GameplayCueTags, FPredictionKey PredictionKey, FGameplayCueParameters GameplayCueParameters) override;

UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCueAdded(const FGameplayTag GameplayCueTag, FPredictionKey PredictionKey, FGameplayEffectContextHandle EffectContext) override;

UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCueAdded_WithParams(const FGameplayTag GameplayCueTag, FPredictionKey PredictionKey, FGameplayCueParameters Parameters) override;

UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCueAddedAndWhileActive_FromSpec(const FGameplayEffectSpecForRPC& Spec, FPredictionKey PredictionKey) override;

UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCueAddedAndWhileActive_WithParams(const FGameplayTag GameplayCueTag, FPredictionKey PredictionKey, FGameplayCueParameters GameplayCueParameters) override;

UFUNCTION(NetMulticast, unreliable)
void NetMulticast_InvokeGameplayCuesAddedAndWhileActive_WithParams(const FGameplayTagContainer GameplayCueTags, FPredictionKey PredictionKey, FGameplayCueParameters GameplayCueParameters) override;

/** 游戏提示也可以单独出现。这些接受可选的effect context以传递命中结果等 */
void ExecuteGameplayCue(const FGameplayTag GameplayCueTag, FGameplayEffectContextHandle EffectContext = FGameplayEffectContextHandle());
void ExecuteGameplayCue(const FGameplayTag GameplayCueTag, const FGameplayCueParameters& GameplayCueParameters);

/** 添加持久游戏提示 */
void AddGameplayCue(const FGameplayTag GameplayCueTag, FGameplayEffectContextHandle EffectContext = FGameplayEffectContextHandle());
void AddGameplayCue(const FGameplayTag GameplayCueTag, const FGameplayCueParameters& GameplayCueParameters);

/** 为最小复制模式添加游戏提示。应仅在如果不处于最小复制模式将通过其他方式(例如通过GE)复制游戏提示的路径中调用 */
void AddGameplayCue_MinimalReplication(const FGameplayTag GameplayCueTag, FGameplayEffectContextHandle EffectContext = FGameplayEffectContextHandle());

/** 移除持久游戏提示 */
void RemoveGameplayCue(const FGameplayTag GameplayCueTag);

/** 为最小复制模式移除游戏提示。应仅在如果不处于最小复制模式将通过其他方式(例如通过GE)复制游戏提示的路径中调用 */
void RemoveGameplayCue_MinimalReplication(const FGameplayTag GameplayCueTag);

/** 移除单独添加的任何GameplayCue,即不是作为游戏效果的一部分添加的。 */
void RemoveAllGameplayCues();

/** 处理来自外部源的游戏提示事件 */
void InvokeGameplayCueEvent(const FGameplayEffectSpecForRPC& Spec, EGameplayCueEvent::Type EventType);
void InvokeGameplayCueEvent(const FGameplayTag GameplayCueTag, EGameplayCueEvent::Type EventType, FGameplayEffectContextHandle EffectContext = FGameplayEffectContextHandle());
void InvokeGameplayCueEvent(const FGameplayTag GameplayCueTag, EGameplayCueEvent::Type EventType, const FGameplayCueParameters& GameplayCueParameters);

/** 允许轮询以查看GameplayCue是否活跃。我们期望大多数GameplayCue处理是基于事件的,但在某些情况下我们可能需要检查GameplayCue是否活跃(例如动画蓝图) */
UFUNCTION(BlueprintCallable, Category="GameplayCue", meta=(GameplayTagFilter="GameplayCue"))
bool IsGameplayCueActive(const FGameplayTag GameplayCueTag) const
{
return HasMatchingGameplayTag(GameplayCueTag);
}

/** 将使用此ASC的所有者(发起者)和AvatarActor(效果引起者)初始化游戏提示参数 */
virtual void InitDefaultGameplayCueParameters(FGameplayCueParameters& Parameters);

/** 我们准备好调用游戏提示了吗? */
virtual bool IsReadyForGameplayCues();

/** 处理可能因进行NetDeltaSerialize并等待头像Actor加载而被延迟的游戏提示 */
virtual void HandleDeferredGameplayCues(const FActiveGameplayEffectsContainer* GameplayEffectsContainer);

/** 为所有活跃、未抑制的GE上的GC调用WhileActive事件。这通常用于"重生"或某些avatar已更改的情况 */
UE_DEPRECATED(5.4, "ReinvokeActiveGameplayCues未使用且其逻辑与预测游戏效果不一致。如果需要,可以在自己的项目中实现它。")
virtual void ReinvokeActiveGameplayCues();

/**
* 游戏技能
*
* 技能系统组件在能力方面的作用是提供:
* -能力实例的管理(无论是每个actor还是每次执行实例)。
* -必须有人跟踪这些实例。
* -非实例化能力可以在没有AbilitySystemComponent中的任何能力内容的情况下执行。
* 它们应该能够在GameplayAbilityActorInfo + GameplayAbility上操作。
*
* 作为便利,它可能提供一些其他功能:
* -一些基本输入绑定(无论是实例化还是非实例化能力)。
* -诸如"此组件具有这些能力"的概念
*
*/

/*
* 授予能力。
* 如果actor不是权威的,则将被忽略。
* 返回可用于TryActivateAbility等的句柄。
*
* @param AbilitySpec 包含能力类、级别和要绑定到的输入ID信息的FGameplayAbilitySpec。
*/
FGameplayAbilitySpecHandle GiveAbility(const FGameplayAbilitySpec& AbilitySpec);

/*
* 授予能力并尝试恰好激活一次,这将导致其被移除。
* 仅在服务器上有效,并且能力的网络执行策略不能设置为Local或Local Predicted
*
* @param AbilitySpec 包含能力类、级别和要绑定到的输入ID信息的FGameplayAbilitySpec。
* @param GameplayEventData 可选的激活事件数据。如果提供,将调用Activate Ability From Event而不是ActivateAbility,传递事件数据
*/
FGameplayAbilitySpecHandle GiveAbilityAndActivateOnce(FGameplayAbilitySpec& AbilitySpec, const FGameplayEventData* GameplayEventData = nullptr);

/**
* 授予游戏能力并返回其句柄。
* 如果actor不是权威的,则将被忽略。
*
* @param AbilityClass 要授予的能力类型
* @param Level 授予能力的级别
* @param InputID 绑定能力激活的输入ID值。
*/
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Gameplay Abilities", meta = (DisplayName = "Give Ability", ScriptName = "GiveAbility"))
FGameplayAbilitySpecHandle K2_GiveAbility(TSubclassOf<UGameplayAbility> AbilityClass, int32 Level = 0, int32 InputID = -1);

/**
* 授予游戏能力,激活一次,然后移除它。
* 如果actor不是权威的,则将被忽略。
*
* @param AbilityClass 要授予的能力类型
* @param Level 授予能力的级别
* @param InputID 绑定能力激活的输入ID值。
*/
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Gameplay Abilities", meta = (DisplayName = "Give Ability And Activate Once", ScriptName = "GiveAbilityAndActivateOnce"))
FGameplayAbilitySpecHandle K2_GiveAbilityAndActivateOnce(TSubclassOf<UGameplayAbility> AbilityClass, int32 Level = 0, int32 InputID = -1);

/** 清除所有'授予'的能力。如果actor不是权威的,则将被忽略。 */
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category="Gameplay Abilities")
void ClearAllAbilities();

/**
* 清除绑定到给定输入ID的所有能力
* 如果actor不是权威的,则将被忽略
*
* @param InputID 要移除的能力的数字输入ID
*/
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Gameplay Abilities")
void ClearAllAbilitiesWithInputID(int32 InputID = 0);

/**
* 移除指定能力。
* 如果actor不是权威的,则将被忽略。
*
* @param Handle 要移除的能力的规格句柄
*/
UFUNCTION(BlueprintCallable, BlueprintAuthorityOnly, Category = "Gameplay Abilities")
void ClearAbility(const FGameplayAbilitySpecHandle& Handle);

/** 设置能力规格在其结束时移除。如果规格当前未活跃,则立即终止它。同时清除规格的InputID。 */
void SetRemoveAbilityOnEnd(FGameplayAbilitySpecHandle AbilitySpecHandle);

/**
* 获取匹配GameplayTagContainer中所有标签且满足
* DoesAbilitySatisfyTagRequirements()为true的所有可激活游戏能力。
* 后一个要求允许此函数在不要求预先知识的情况下找到正确的能力。
* 例如,如果有两个"近战"能力,一个需要武器,另一个需要徒手,
* 那么这些能力可以使用阻塞和必需标签来确定何时可以触发。
* 使用满足标签要求简化了许多使用情况。
* 例如,行为树可以使用各种装饰器来测试使用此机制获取的能力,
* 以及执行能力的任务,而不需要知道甚至存在多个这样的能力。
*/
void GetActivatableGameplayAbilitySpecsByAllMatchingTags(const FGameplayTagContainer& GameplayTagContainer, TArray < struct FGameplayAbilitySpec* >& MatchingGameplayAbilities, bool bOnlyAbilitiesThatSatisfyTagRequirements = true) const;

/**
* 尝试激活匹配给定标签且满足DoesAbilitySatisfyTagRequirements()的每个游戏能力。
* 如果任何尝试激活,则返回true。可以激活多个能力,并且能力可能稍后失败。
* 如果bAllowRemoteActivation为true,它将远程激活本地/服务器能力;如果为false,它将仅尝试本地激活能力。
*/
UFUNCTION(BlueprintCallable, Category = "Abilities")
bool TryActivateAbilitiesByTag(const FGameplayTagContainer& GameplayTagContainer, bool bAllowRemoteActivation = true);

/**
* 尝试激活传入的能力。这将在执行前检查成本和需求。
* 如果认为已激活,则返回true,但由于稍后激活失败,可能会返回误报。
* 如果bAllowRemoteActivation为true,它将远程激活本地/服务器能力;如果为false,它将仅尝试本地激活能力
*/
UFUNCTION(BlueprintCallable, Category = "Abilities")
bool TryActivateAbilityByClass(TSubclassOf<UGameplayAbility> InAbilityToActivate, bool bAllowRemoteActivation = true);

/**
* 尝试激活给定能力,将在执行前检查成本和需求。
* 如果认为已激活,则返回true,但由于稍后激活失败,可能会返回误报。
* 如果bAllowRemoteActivation为true,它将远程激活本地/服务器能力;如果为false,它将仅尝试本地激活能力
*/
UFUNCTION(BlueprintCallable, Category = "Abilities")
bool TryActivateAbility(FGameplayAbilitySpecHandle AbilityToActivate, bool bAllowRemoteActivation = true);

bool HasActivatableTriggeredAbility(FGameplayTag Tag);

/** 从游戏事件触发能力,将仅根据执行标志在本地/服务器上触发 */
bool TriggerAbilityFromGameplayEvent(FGameplayAbilitySpecHandle AbilityToTrigger, FGameplayAbilityActorInfo* ActorInfo, FGameplayTag Tag, const FGameplayEventData* Payload, UAbilitySystemComponent& Component);

// ----------------------------------------------------------------------------------------------------------------
// 能力取消/中断
// ----------------------------------------------------------------------------------------------------------------

/** 取消指定能力的CDO。 */
void CancelAbility(UGameplayAbility* Ability);

/** 取消传入规格句柄指示的能力。如果在reactivated能力中未找到句柄,则不执行任何操作。 */
void CancelAbilityHandle(const FGameplayAbilitySpecHandle& AbilityHandle);

/** 取消具有指定标签的所有能力。不会取消Ignore实例 */
void CancelAbilities(const FGameplayTagContainer* WithTags=nullptr, const FGameplayTagContainer* WithoutTags=nullptr, UGameplayAbility* Ignore=nullptr);

/** 取消所有能力,无论标签如何。不会取消ignore实例 */
void CancelAllAbilities(UGameplayAbility* Ignore=nullptr);

/** 取消所有能力并杀死任何剩余的实例化能力 */
virtual void DestroyActiveState();

/**
* 从能力激活或本机代码调用,将应用正确的能力阻塞标签并取消现有能力。子类可以覆盖此行为
*
* @param AbilityTags 具有阻塞和取消标志的能力标签
* @param RequestingAbility 请求更改的游戏能力,对于本机事件可以为NULL
* @param bEnableBlockTags 如果为true将启用阻塞标签,如果为false将禁用阻塞标签
* @param BlockTags 要阻塞的标签
* @param bExecuteCancelTags 如果为true将取消匹配标签的能力
* @param CancelTags 要取消的标签
*/
virtual void ApplyAbilityBlockAndCancelTags(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bEnableBlockTags, const FGameplayTagContainer& BlockTags, bool bExecuteCancelTags, const FGameplayTagContainer& CancelTags);

/** 当能力可取消或不可取消时调用。默认情况下不执行任何操作,可以重写以连接到游戏事件 */
virtual void HandleChangeAbilityCanBeCanceled(const FGameplayTagContainer& AbilityTags, UGameplayAbility* RequestingAbility, bool bCanBeCanceled) {}

/** 如果任何传入标签被阻塞,则返回true */
virtual bool AreAbilityTagsBlocked(const FGameplayTagContainer& Tags) const;

/** 阻塞或取消阻塞特定能力标签 */
void BlockAbilitiesWithTags(const FGameplayTagContainer& Tags);
void UnBlockAbilitiesWithTags(const FGameplayTagContainer& Tags);

/** 检查技能系统当前是否阻塞InputID。如果InputID被阻塞,则返回true,否则返回false。 */
bool IsAbilityInputBlocked(int32 InputID) const;

/** 阻塞或取消阻塞特定输入ID */
void BlockAbilityByInputID(int32 InputID);
void UnBlockAbilityByInputID(int32 InputID);

// ----------------------------------------------------------------------------------------------------------------
// 意味着从GameplayAbility及其子类调用但并非一般使用的函数
// ----------------------------------------------------------------------------------------------------------------

/** 返回所有可激活能力的列表。只读。 */
const TArray<FGameplayAbilitySpec>& GetActivatableAbilities() const
{
return ActivatableAbilities.Items;
}

/** 返回所有可激活能力的列表。 */
TArray<FGameplayAbilitySpec>& GetActivatableAbilities()
{
return ActivatableAbilities.Items;
}

/** 返回能力被激活的本地世界时间。在权威(服务器)和自主代理(控制客户端)上有效。 */
float GetAbilityLastActivatedTime() const { return AbilityLastActivatedTime; }

/** 从句柄返回能力规格。如果修改,请调用MarkAbilitySpecDirty。将返回值视为临时的,因为指针可能会在随后调用AbilitySystemComponent时失效。 */
FGameplayAbilitySpec* FindAbilitySpecFromHandle(FGameplayAbilitySpecHandle Handle, EConsiderPending ConsiderPending = EConsiderPending::PendingRemove) const;

/** 从GE句柄返回能力规格。如果修改,请调用MarkAbilitySpecDirty */
UE_DEPRECATED(5.3, "FindAbilitySpecFromGEHandle从不准确,因为GameplayEffect可以授予多个GameplayAbilities。现在它返回nullptr。")
FGameplayAbilitySpec* FindAbilitySpecFromGEHandle(FActiveGameplayEffectHandle Handle) const;

/**
* 返回从GE句柄授予的所有能力规格句柄。仅服务器可以调用此函数。
* @param ScopeLock - 用于与调用者通信的锁,返回值仅在此锁作用域内有效
* @param Handle - 授予我们正在寻找的能力的活跃游戏效果的句柄
* @param ConsiderPending - 我们是否返回待添加/移除的AbilitySpecs?
*/
TArray<const FGameplayAbilitySpec*> FindAbilitySpecsFromGEHandle(const FScopedAbilityListLock& ScopeLock, FActiveGameplayEffectHandle Handle, EConsiderPending ConsiderPending = EConsiderPending::PendingRemove) const;

/** 返回与给定能力类对应的能力规格。如果修改,请调用MarkAbilitySpecDirty */
FGameplayAbilitySpec* FindAbilitySpecFromClass(TSubclassOf<UGameplayAbility> InAbilityClass) const;

/** 从句柄返回能力规格。如果修改,请调用MarkAbilitySpecDirty */
FGameplayAbilitySpec* FindAbilitySpecFromInputID(int32 InputID) const;

/**
* 返回具有给定InputID的所有能力
*
* @param InputID 要匹配的输入ID
* @param OutAbilitySpecs 匹配规格的指针数组
*/
virtual void FindAllAbilitySpecsFromInputID(int32 InputID, TArray<const FGameplayAbilitySpec*>& OutAbilitySpecs) const;

/**
* 从类、级别和可选输入ID构建简单的FGameplayAbilitySpec
*/
virtual FGameplayAbilitySpec BuildAbilitySpecFromClass(TSubclassOf<UGameplayAbility> AbilityClass, int32 Level = 0, int32 InputID = -1);

/**
* 返回包含所有授予能力句柄的数组
* 注意:当前这不包括处于激活中的能力
*
* @param OutAbilityHandles 此数组将填充授予的能力规格句柄
*/
UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "Gameplay Abilities")
void GetAllAbilities(TArray<FGameplayAbilitySpecHandle>& OutAbilityHandles) const;

/**
* 返回匹配提供标签的所有能力的数组
*
* @param OutAbilityHandles 此数组将填充匹配的能力规格句柄
* @param Tags 要匹配的游戏标签
* @param bExactMatch 如果为true,标签必须完全匹配。否则,将返回匹配任何标签的能力
*/
UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "Gameplay Abilities")
void FindAllAbilitiesWithTags(TArray<FGameplayAbilitySpecHandle>& OutAbilityHandles, FGameplayTagContainer Tags, bool bExactMatch = true) const;

/**
* 返回匹配提供的游戏标签查询的所有能力的数组
*
* @param OutAbilityHandles 此数组将填充匹配的能力规格句柄
* @param Query 要匹配的游戏标签查询
*/
UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "Gameplay Abilities")
void FindAllAbilitiesMatchingQuery(TArray<FGameplayAbilitySpecHandle>& OutAbilityHandles, FGameplayTagQuery Query) const;

/**
* 返回绑定到输入ID值的所有能力的数组
*
* @param OutAbilityHandles 此数组将填充匹配的能力规格句柄
* @param InputID 要匹配的输入ID
*/
UFUNCTION(BlueprintCallable, BlueprintPure = false, Category = "Gameplay Abilities")
void FindAllAbilitiesWithInputID(TArray<FGameplayAbilitySpecHandle>& OutAbilityHandles, int32 InputID = 0) const;

/** 从活跃游戏效果的活跃游戏效果中检索EffectContext。 */
FGameplayEffectContextHandle GetEffectContextFromActiveGEHandle(FActiveGameplayEffectHandle Handle);

/** 调用以标记能力规格已被修改 */
void MarkAbilitySpecDirty(FGameplayAbilitySpec& Spec, bool WasAddOrRemove=false);

/** 尝试激活给定能力,仅当从正确的客户端/服务器上下文调用时才有效 */
bool InternalTryActivateAbility(FGameplayAbilitySpecHandle AbilityToActivate, FPredictionKey InPredictionKey = FPredictionKey(), UGameplayAbility ** OutInstancedAbility = nullptr, FOnGameplayAbilityEnded::FDelegate* OnGameplayAbilityEndedDelegate = nullptr, const FGameplayEventData* TriggerEventData = nullptr);

/** InternalTryActivateAbility使用的失败标签(例如,这存储上次调用InternalTryActivateAbility的FailureTags) */
FGameplayTagContainer InternalTryActivateAbilityFailureTags;

/** 从能力调用以让组件知道它已结束 */
virtual void NotifyAbilityEnded(FGameplayAbilitySpecHandle Handle, UGameplayAbility* Ability, bool bWasCancelled);

void ClearAbilityReplicatedDataCache(FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActivationInfo& ActivationInfo);

/** 从FScopedAbilityListLock调用 */
void IncrementAbilityListLock();
void DecrementAbilityListLock();

// ----------------------------------------------------------------------------------------------------------------
// 调试
// ----------------------------------------------------------------------------------------------------------------

struct FAbilitySystemComponentDebugInfo
{
FAbilitySystemComponentDebugInfo()
{
FMemory::Memzero(*this);
}

class UCanvas* Canvas;

bool bPrintToLog;

bool bShowAttributes;
bool bShowGameplayEffects;;
bool bShowAbilities;

float XPos;
float YPos;
float OriginalX;
float OriginalY;
float MaxY;
float NewColumnYPadding;
float YL;

bool Accumulate;
TArray<FString> Strings;

int32 GameFlags; // 供游戏在Debug_Internal中设置/读取的任意标志
};

static void OnShowDebugInfo(AHUD* HUD, UCanvas* Canvas, const FDebugDisplayInfo& DisplayInfo, float& YL, float& YPos);

virtual void DisplayDebug(class UCanvas* Canvas, const class FDebugDisplayInfo& DebugDisplay, float& YL, float& YPos);
virtual void PrintDebug();

void AccumulateScreenPos(FAbilitySystemComponentDebugInfo& Info);
virtual void Debug_Internal(struct FAbilitySystemComponentDebugInfo& Info);
void DebugLine(struct FAbilitySystemComponentDebugInfo& Info, FString Str, float XOffset, float YOffset, int32 MinTextRowsToAdvance = 0);
FString CleanupName(FString Str);

/** 打印所有游戏效果的调试列表 */
void PrintAllGameplayEffects() const;

/** 请求服务器将技能系统调试信息发送回客户端,通过ClientPrintDebug_Response */
UFUNCTION(Server, reliable, WithValidation)
void ServerPrintDebug_Request();

/** 与ServerPrintDebug_Request相同,但这包括客户端调试字符串,以便服务器可以将它们嵌入重放中 */
UFUNCTION(Server, reliable, WithValidation)
void ServerPrintDebug_RequestWithStrings(const TArray<FString>& Strings);

/** 当ServerPrintDebug函数在服务器上运行时,游戏可以覆盖的虚拟函数以执行自己的操作 */
virtual void OnServerPrintDebug_Request();

/** 确定是调用ServerPrintDebug_Request还是ServerPrintDebug_RequestWithStrings。 */
virtual bool ShouldSendClientDebugStringsToServer() const;

UFUNCTION(Client, reliable)
void ClientPrintDebug_Response(const TArray<FString>& Strings, int32 GameFlags);
virtual void OnClientPrintDebug_Response(const TArray<FString>& Strings, int32 GameFlags);

#if ENABLE_VISUAL_LOG
void ClearDebugInstantEffects();

virtual void GrabDebugSnapshot(FVisualLogEntry* Snapshot) const override;
#endif // ENABLE_VISUAL_LOG

UE_DEPRECATED(4.26, "这将在未来的引擎版本中变为私有。请改用SetClientDebugStrings、GetClientDebugStrings或GetClientDebugStrings_Mutable。")
UPROPERTY(ReplicatedUsing=OnRep_ClientDebugString)
TArray<FString> ClientDebugStrings;

void SetClientDebugStrings(TArray<FString>&& NewClientDebugStrings);
TArray<FString>& GetClientDebugStrings_Mutable();
const TArray<FString>& GetClientDebugStrings() const;

UE_DEPRECATED(4.26, "这将在未来的引擎版本中变为私有。请改用SetServerDebugStrings、GetServerDebugStrings或GetServerDebugStrings_Mutable。")
UPROPERTY(ReplicatedUsing=OnRep_ServerDebugString)
TArray<FString> ServerDebugStrings;

void SetServerDebugStrings(TArray<FString>&& NewServerDebugStrings);
TArray<FString>& GetServerDebugStrings_Mutable();
const TArray<FString>& GetServerDebugStrings() const;

UFUNCTION()
virtual void OnRep_ClientDebugString();

UFUNCTION()
virtual void OnRep_ServerDebugString();

// ----------------------------------------------------------------------------------------------------------------
// 批量处理客户端->服务器RPC
// 这是一个进行中的功能,用于批量处理客户端->服务器通信。它是可选的且不完整。它仅批量处理以下函数。在批处理窗口期间调用其他服务器RPC不安全。仅当您知道自己在做什么时才选择使用!
// ----------------------------------------------------------------------------------------------------------------

void CallServerTryActivateAbility(FGameplayAbilitySpecHandle AbilityToActivate, bool InputPressed, FPredictionKey PredictionKey);
void CallServerSetReplicatedTargetData(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, const FGameplayAbilityTargetDataHandle& ReplicatedTargetDataHandle, FGameplayTag ApplicationTag, FPredictionKey CurrentPredictionKey);
void CallServerEndAbility(FGameplayAbilitySpecHandle AbilityToEnd, FGameplayAbilityActivationInfo ActivationInfo, FPredictionKey PredictionKey);

virtual bool ShouldDoServerAbilityRPCBatch() const { return false; }
virtual void BeginServerAbilityRPCBatch(FGameplayAbilitySpecHandle AbilityHandle);
virtual void EndServerAbilityRPCBatch(FGameplayAbilitySpecHandle AbilityHandle);

/** 在EndServerAbilityRPCBatch上批量发送到服务器的累积客户端数据 */
TArray<FServerAbilityRPCBatch, TInlineAllocator<1> > LocalServerAbilityRPCBatchData;

UFUNCTION(Server, reliable, WithValidation)
void ServerAbilityRPCBatch(FServerAbilityRPCBatch BatchInfo);

// 供子类覆盖的函数
virtual void ServerAbilityRPCBatch_Internal(FServerAbilityRPCBatch& BatchInfo);

// ----------------------------------------------------------------------------------------------------------------
// 输入处理/目标选择
// ----------------------------------------------------------------------------------------------------------------

/**
* 这旨在用于从输入角度抑制激活能力。(例如,菜单已打开,另一个游戏机制正在消耗所有输入等)
* 这应仅在本地拥有的玩家上调用。
* 这不应用于游戏机制,如沉默或禁用。这些应通过游戏效果完成。
*/
UFUNCTION(BlueprintCallable, Category="Abilities")
bool GetUserAbilityActivationInhibited() const;

/** 禁用或启用本地用户激活能力的能力。这应仅用于输入/UI等相关抑制。不用于游戏机制。 */
UFUNCTION(BlueprintCallable, Category="Abilities")
virtual void SetUserAbilityActivationInhibited(bool NewInhibit);

/** 当前是否抑制激活 */
UPROPERTY()
bool UserAbilityActivationInhibited;

/** 启用时,GameplayCue RPC将通过AvatarActor的IAbilitySystemReplicationProxyInterface而不是此组件路由 */
UPROPERTY()
bool ReplicationProxyEnabled;

/** 抑制通过此组件上的GE授予的所有能力 */
UPROPERTY()
bool bSuppressGrantAbility;

/** 抑制此组件上的所有GameplayCues */
UPROPERTY()
bool bSuppressGameplayCues;

/** 当前活跃的目标选择角色列表 */
UPROPERTY()
TArray<TObjectPtr<AGameplayAbilityTargetActor>> SpawnedTargetActors;

/** 使用一些默认操作名称绑定到输入组件 */
virtual void BindToInputComponent(UInputComponent* InputComponent);

/** 使用自定义绑定绑定到输入组件 */
virtual void BindAbilityActivationToInputComponent(UInputComponent* InputComponent, FGameplayAbilityInputBinds BindInfo);

/** 初始化BlockedAbilityBindings变量 */
virtual void SetBlockAbilityBindingsArray(FGameplayAbilityInputBinds BindInfo);

/** 调用以处理能力绑定输入 */
virtual void AbilityLocalInputPressed(int32 InputID);
virtual void AbilityLocalInputReleased(int32 InputID);

/*
* 发送具有提供的输入ID的本地玩家输入按下事件,通知任何绑定的能力
*
* @param InputID 要匹配的输入ID
*/
UFUNCTION(BlueprintCallable, Category = "Gameplay Abilities")
void PressInputID(int32 InputID);

/**
* 发送具有提供的输入ID的本地玩家输入释放事件,通知任何绑定的能力
* @param InputID 要匹配的输入ID
*/
UFUNCTION(BlueprintCallable, Category = "Gameplay Abilities")
void ReleaseInputID(int32 InputID);

/** 为目标选择角色处理确认/取消 */
virtual void LocalInputConfirm();
virtual void LocalInputCancel();

/**
* 发送本地玩家输入确认事件,通知能力
*/
UFUNCTION(BlueprintCallable, Category = "Gameplay Abilities")
void InputConfirm();

/**
* 发送本地玩家输入取消事件,通知能力
*/
UFUNCTION(BlueprintCallable, Category = "Gameplay Abilities")
void InputCancel();

/** 用于绑定GenericConfirm/Cancel事件的InputID */
int32 GenericConfirmInputID;
int32 GenericCancelInputID;

bool IsGenericConfirmInputBound(int32 InputID) const { return ((InputID == GenericConfirmInputID) && GenericLocalConfirmCallbacks.IsBound()); }
bool IsGenericCancelInputBound(int32 InputID) const { return ((InputID == GenericCancelInputID) && GenericLocalCancelCallbacks.IsBound()); }

/** 任何能力都可以监听的通用确认事件的通用本地回调 */
FAbilityConfirmOrCancel GenericLocalConfirmCallbacks;

/** 任何能力都可以监听的通用取消事件的通用本地回调 */
FAbilityConfirmOrCancel GenericLocalCancelCallbacks;

/** 任何活跃的目标选择角色将被告知停止并返回当前目标数据 */
UFUNCTION(BlueprintCallable, Category = "Abilities")
virtual void TargetConfirm();

/** 任何活跃的目标选择角色将被停止并取消,不返回任何目标数据 */
UFUNCTION(BlueprintCallable, Category = "Abilities")
virtual void TargetCancel();

// ----------------------------------------------------------------------------------------------------------------
// 动画蒙太奇支持
// ----------------------------------------------------------------------------------------------------------------

/** 播放蒙太奇并根据传入的能力/激活信息处理复制和预测 */
virtual float PlayMontage(UGameplayAbility* AnimatingAbility, FGameplayAbilityActivationInfo ActivationInfo, UAnimMontage* Montage, float InPlayRate, FName StartSectionName = NAME_None, float StartTimeSeconds = 0.0f);

virtual UAnimMontage* PlaySlotAnimationAsDynamicMontage(UGameplayAbility* AnimatingAbility, FGameplayAbilityActivationInfo ActivationInfo, UAnimSequenceBase* AnimAsset, FName SlotName, float BlendInTime, float BlendOutTime, float InPlayRate = 1.f, float StartTimeSeconds = 0.0f);

/** 播放蒙太奇而不更新复制/预测结构。当复制告诉模拟代理播放蒙太奇时使用。 */
virtual float PlayMontageSimulated(UAnimMontage* Montage, float InPlayRate, FName StartSectionName = NAME_None);

virtual UAnimMontage* PlaySlotAnimationAsDynamicMontageSimulated(UAnimSequenceBase* AnimAsset, FName SlotName, float BlendInTime, float BlendOutTime, float InPlayRate = 1.f);

/** 停止当前正在播放的任何蒙太奇。期望调用者仅在他们当前是动画能力(或有充分理由不检查)时才停止它 */
virtual void CurrentMontageStop(float OverrideBlendOutTime = -1.0f);

/** 如果当前蒙太奇是作为参数给定的蒙太奇,则停止当前蒙太奇 */
virtual void StopMontageIfCurrent(const UAnimMontage& Montage, float OverrideBlendOutTime = -1.0f);

/** 如果传入的能力仍在当前动画中,则清除动画能力 */
virtual void ClearAnimatingAbility(UGameplayAbility* Ability);

/** 将当前蒙太奇跳转到给定部分。期望调用者仅在他们当前是动画能力(或有充分理由不检查)时才停止它 */
virtual void CurrentMontageJumpToSection(FName SectionName);

/** 设置当前蒙太奇的下一个部分名称。期望调用者仅在他们当前是动画能力(或有充分理由不检查)时才停止它 */
virtual void CurrentMontageSetNextSectionName(FName FromSectionName, FName ToSectionName);

/** 设置当前蒙太奇的播放速率 */
virtual void CurrentMontageSetPlayRate(float InPlayRate);

/** 如果传入的能力是当前动画能力,则返回true */
bool IsAnimatingAbility(UGameplayAbility* Ability) const;

/** 返回当前动画能力 */
UGameplayAbility* GetAnimatingAbility();

/** 返回当前正在播放的蒙太奇 */
UAnimMontage* GetCurrentMontage() const;

/** 获取当前播放的AnimMontage的SectionID */
int32 GetCurrentMontageSectionID() const;

/** 获取当前播放的AnimMontage的SectionName */
FName GetCurrentMontageSectionName() const;

/** 获取当前部分的时间长度 */
float GetCurrentMontageSectionLength() const;

/** 返回当前部分的剩余时间 */
float GetCurrentMontageSectionTimeLeft() const;

/** 设置蒙太奇中位置复制的方法 */
void SetMontageRepAnimPositionMethod(ERepAnimPositionMethod InMethod);

// ----------------------------------------------------------------------------------------------------------------
// Actor交互
// ----------------------------------------------------------------------------------------------------------------

private:

/** 逻辑上拥有此组件的actor */
UPROPERTY(ReplicatedUsing = OnRep_OwningActor)
TObjectPtr<AActor> OwnerActor;

/** 用于能力的物理表示的actor。可以为NULL */
UPROPERTY(ReplicatedUsing = OnRep_OwningActor)
TObjectPtr<AActor> AvatarActor;

public:

void SetOwnerActor(AActor* NewOwnerActor);
AActor* GetOwnerActor() const { return OwnerActor; }

void SetAvatarActor_Direct(AActor* NewAvatarActor);
AActor* GetAvatarActor_Direct() const { return AvatarActor; }

UFUNCTION()
void OnRep_OwningActor();

UFUNCTION()
void OnAvatarActorDestroyed(AActor* InActor);

UFUNCTION()
void OnOwnerActorDestroyed(AActor* InActor);

UFUNCTION()
void OnSpawnedAttributesEndPlayed(AActor* InActor, EEndPlayReason::Type EndPlayReason);

/** 缓存的关于拥有actor的数据,能力将需要频繁访问(移动组件、网格组件、动画实例等) */
TSharedPtr<FGameplayAbilityActorInfo> AbilityActorInfo;

/**
* 初始化能力的ActorInfo - 保存我们正在作用于谁以及谁控制我们的结构。
* OwnerActor是逻辑上拥有此组件的actor。
* AvatarActor是我们在世界中作用的物理actor。通常是Pawn,但也可以是塔、建筑、炮塔等,可能与Owner相同
*/
virtual void InitAbilityActorInfo(AActor* InOwnerActor, AActor* InAvatarActor);

/** 返回用于特定任务的头像actor,通常是GetAvatarActor */
virtual AActor* GetGameplayTaskAvatar(const UGameplayTask* Task) const override;

/** 返回此组件的头像actor */
AActor* GetAvatarActor() const;

/** 更改头像actor,保持拥有actor不变 */
void SetAvatarActor(AActor* InAvatarActor);

/** 当ASC的AbilityActorInfo设置了PlayerController时调用。 */
virtual void OnPlayerControllerSet() { }

/**
* 当初始化到此系统的actor死亡时调用,这将从此系统和FGameplayAbilityActorInfo中清除该actor
*/
virtual void ClearActorInfo();

/**
* 这将根据当前ActorInfo刷新能力的ActorInfo结构。也就是说,AvatarActor将相同,但我们将查找新的
* AnimInstance、MovementComponent、PlayerController等。
*/
void RefreshAbilityActorInfo();

// ----------------------------------------------------------------------------------------------------------------
// 同步RPC
// 虽然这些看起来像状态,但实际上这些是具有一些有效负载数据的同步事件
// ----------------------------------------------------------------------------------------------------------------

/** 将通用复制事件复制到服务器。 */
UFUNCTION(Server, reliable, WithValidation)
void ServerSetReplicatedEvent(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, FPredictionKey CurrentPredictionKey);

/** 将带有有效负载的通用复制事件复制到服务器。 */
UFUNCTION(Server, reliable, WithValidation)
void ServerSetReplicatedEventWithPayload(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, FPredictionKey CurrentPredictionKey, FVector_NetQuantize100 VectorPayload);

/** 将通用复制事件复制到客户端。 */
UFUNCTION(Client, reliable)
void ClientSetReplicatedEvent(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 调用使用给定通用复制事件注册的本地回调 */
bool InvokeReplicatedEvent(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, FPredictionKey CurrentPredictionKey = FPredictionKey());

/** 调用使用给定通用复制事件注册的本地回调 */
bool InvokeReplicatedEventWithPayload(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, FPredictionKey CurrentPredictionKey, FVector_NetQuantize100 VectorPayload);

/** 将目标数据复制到服务器 */
UFUNCTION(Server, reliable, WithValidation)
void ServerSetReplicatedTargetData(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, const FGameplayAbilityTargetDataHandle& ReplicatedTargetDataHandle, FGameplayTag ApplicationTag, FPredictionKey CurrentPredictionKey);

/** 向服务器复制目标选择已被取消 */
UFUNCTION(Server, reliable, WithValidation)
void ServerSetReplicatedTargetDataCancelled(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, FPredictionKey CurrentPredictionKey);

/** 设置当前目标数据并调用适用的回调 */
virtual void ConfirmAbilityTargetData(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, const FGameplayAbilityTargetDataHandle& TargetData, const FGameplayTag& ApplicationTag);

/** 取消能力目标数据并调用回调 */
virtual void CancelAbilityTargetData(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 删除所有缓存的能力客户端数据(原为:ConsumeAbilityTargetData)*/
void ConsumeAllReplicatedData(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);
/** 从客户端消耗缓存的目标数据(仅TargetData) */
void ConsumeClientReplicatedTargetData(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 消耗给定的通用复制事件(取消设置它)。 */
void ConsumeGenericReplicatedEvent(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 获取给定通用复制事件的复制数据。 */
FAbilityReplicatedData GetReplicatedDataOfGenericReplicatedEvent(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 调用已发送的任何复制委托(TargetData或通用复制事件)。注意,如果在能力中的多个位置注册事件然后调用此函数,则可能很危险。 */
void CallAllReplicatedDelegatesIfSet(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 如果已发送,则调用TargetData确认/取消事件。 */
bool CallReplicatedTargetDataDelegatesIfSet(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 如果事件已发送,则调用给定的通用复制事件委托 */
bool CallReplicatedEventDelegateIfSet(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 如果客户端事件已发送,则调用传入的委托。如果没有,则将委托添加到我们的多播回调中,当它发送时将触发。 */
bool CallOrAddReplicatedDelegate(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey, FSimpleMulticastDelegate::FDelegate Delegate);

/** 返回给定能力/预测键对的TargetDataSet委托 */
FAbilityTargetDataSetDelegate& AbilityTargetDataSetDelegate(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 返回给定能力/预测键对的TargetData取消委托 */
FSimpleMulticastDelegate& AbilityTargetDataCancelledDelegate(FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 返回给定能力/预测键对的通用复制事件 */
FSimpleMulticastDelegate& AbilityReplicatedEventDelegate(EAbilityGenericReplicatedEvent::Type EventType, FGameplayAbilitySpecHandle AbilityHandle, FPredictionKey AbilityOriginalPredictionKey);

/** 直接输入状态复制。如果能力上的bReplicateInputDirectly为true,则将调用这些函数,通常这不是好事。(相反,最好使用通用复制事件)。 */
UFUNCTION(Server, reliable, WithValidation)
void ServerSetInputPressed(FGameplayAbilitySpecHandle AbilityHandle);

UFUNCTION(Server, reliable, WithValidation)
void ServerSetInputReleased(FGameplayAbilitySpecHandle AbilityHandle);

/** 始终在本地玩家上调用。仅当GameplayAbility上设置了bReplicateInputDirectly时在服务器上调用。 */
virtual void AbilitySpecInputPressed(FGameplayAbilitySpec& Spec);

/** 始终在本地玩家上调用。仅当GameplayAbility上设置了bReplicateInputDirectly时在服务器上调用。 */
virtual void AbilitySpecInputReleased(FGameplayAbilitySpec& Spec);

// ----------------------------------------------------------------------------------------------------------------
// 组件覆盖
// ----------------------------------------------------------------------------------------------------------------

virtual void InitializeComponent() override;
virtual void UninitializeComponent() override;
virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;
virtual bool GetShouldTick() const override;
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
virtual void GetSubobjectsWithStableNamesForNetworking(TArray<UObject*>& Objs) override;
virtual bool ReplicateSubobjects(class UActorChannel *Channel, class FOutBunch *Bunch, FReplicationFlags *RepFlags) override;
/** 强制拥有actor更新其复制,以确保游戏提示快速发送。重写以更改其积极程度 */
virtual void ForceReplication() override;
virtual void PreNetReceive() override;
virtual void PostNetReceive() override;
virtual void OnRegister() override;
virtual void OnUnregister() override;
virtual void ReadyForReplication() override;
virtual void BeginPlay() override;

protected:
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
virtual void GetReplicatedCustomConditionState(FCustomPropertyConditionState& OutActiveState) const override;

void UpdateActiveGameplayEffectsReplicationCondition();
void UpdateMinimalReplicationGameplayCuesCondition();

/**
* 我们可以激活的能力。
* -这将包括非实例化能力和每次执行实例化能力的CDO。
* -Actor实例化能力将是实际实例(不是CDO)
*
* 此数组对于工作不是至关重要的。它是用于'给actor赋予能力'的便利功能。但能力也可以在事物上工作
* 而无需AbilitySystemComponent。例如,可以编写能力在StaticMeshActor上执行。只要能力不需要
* 实例化或AbilitySystemComponent提供的任何其他功能,那么它就不需要该组件来运行。
*/

UPROPERTY(ReplicatedUsing = OnRep_ActivateAbilities, BlueprintReadOnly, Transient, Category = "Abilities")
FGameplayAbilitySpecContainer ActivatableAbilities;

/** 从能力规格映射到目标数据。用于跟踪复制数据和回调 */
FGameplayAbilityReplicatedDataContainer AbilityTargetDataMap;

/** 游戏标签容器过滤器和它们调用的委托列表 */
TArray<TPair<FGameplayTagContainer, FGameplayEventTagMulticastDelegate>> GameplayEventTagContainerDelegates;

/** 与此组件关联的所有每次执行实例化游戏能力的完整列表 */
UE_DEPRECATED(5.1, "此数组将变为私有。请改用GetReplicatedInstancedAbilities、AddReplicatedInstancedAbility或RemoveReplicatedInstancedAbility。")
UPROPERTY()
TArray<TObjectPtr<UGameplayAbility>> AllReplicatedInstancedAbilities;

/** 与此组件关联的所有每次执行实例化游戏能力的完整列表 */
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const TArray<UGameplayAbility*>& GetReplicatedInstancedAbilities() const { return AllReplicatedInstancedAbilities; }
PRAGMA_ENABLE_DEPRECATION_WARNINGS

/** 添加与此组件关联的游戏能力 */
void AddReplicatedInstancedAbility(UGameplayAbility* GameplayAbility);

/** 移除与此组件关联的游戏能力 */
void RemoveReplicatedInstancedAbility(UGameplayAbility* GameplayAbility);

/** 取消注册此组件的所有游戏能力 */
void RemoveAllReplicatedInstancedAbilities();

/** 将从GiveAbility或OnRep调用。使用给定能力初始化事件(触发器和输入) */
virtual void OnGiveAbility(FGameplayAbilitySpec& AbilitySpec);

/** 将从RemoveAbility或OnRep调用。解除与给定能力的输入绑定 */
virtual void OnRemoveAbility(FGameplayAbilitySpec& AbilitySpec);

/** 从ClearAbility、ClearAllAbilities或OnRep调用。清除不应再存在的任何触发器。 */
void CheckForClearedAbilities();

/** 取消特定的能力规格 */
virtual void CancelAbilitySpec(FGameplayAbilitySpec& Spec, UGameplayAbility* Ignore);

/** 创建能力的新实例,将其存储在规格中 */
virtual UGameplayAbility* CreateNewInstanceOfAbility(FGameplayAbilitySpec& Spec, const UGameplayAbility* Ability);

/** 指示我们处于多少层ABILITY_SCOPE_LOCK()中。当AbilityScopeLockCount > 0时,能力列表可能不能被修改。 */
int32 AbilityScopeLockCount;
/** 退出当前能力作用域锁时将移除的能力。 */
TArray<FGameplayAbilitySpecHandle, TInlineAllocator<2> > AbilityPendingRemoves;
/** 退出当前能力作用域锁时将添加的能力。 */
TArray<FGameplayAbilitySpec, TInlineAllocator<2> > AbilityPendingAdds;
/** 退出当前能力作用域锁时是否应移除所有能力。将优先于待添加项。 */
bool bAbilityPendingClearAll;

/** 上次能力激活的本地世界时间。这用于AFK/空闲检测 */
float AbilityLastActivatedTime;

UFUNCTION()
virtual void OnRep_ActivateAbilities();

UFUNCTION(Server, reliable, WithValidation)
void ServerTryActivateAbility(FGameplayAbilitySpecHandle AbilityToActivate, bool InputPressed, FPredictionKey PredictionKey);

UFUNCTION(Server, reliable, WithValidation)
void ServerTryActivateAbilityWithEventData(FGameplayAbilitySpecHandle AbilityToActivate, bool InputPressed, FPredictionKey PredictionKey, FGameplayEventData TriggerEventData);

UFUNCTION(Client, reliable)
void ClientTryActivateAbility(FGameplayAbilitySpecHandle AbilityToActivate);

/** 由ServerEndAbility和ClientEndAbility调用;避免代码重复。 */
void RemoteEndOrCancelAbility(FGameplayAbilitySpecHandle AbilityToEnd, FGameplayAbilityActivationInfo ActivationInfo, bool bWasCanceled);

UFUNCTION(Server, reliable, WithValidation)
void ServerEndAbility(FGameplayAbilitySpecHandle AbilityToEnd, FGameplayAbilityActivationInfo ActivationInfo, FPredictionKey PredictionKey);

UFUNCTION(Client, reliable)
void ClientEndAbility(FGameplayAbilitySpecHandle AbilityToEnd, FGameplayAbilityActivationInfo ActivationInfo);

UFUNCTION(Server, reliable, WithValidation)
void ServerCancelAbility(FGameplayAbilitySpecHandle AbilityToCancel, FGameplayAbilityActivationInfo ActivationInfo);

UFUNCTION(Client, reliable)
void ClientCancelAbility(FGameplayAbilitySpecHandle AbilityToCancel, FGameplayAbilityActivationInfo ActivationInfo);

UFUNCTION(Client, Reliable)
void ClientActivateAbilityFailed(FGameplayAbilitySpecHandle AbilityToActivate, int16 PredictionKey);
int32 ClientActivateAbilityFailedCountRecent;
float ClientActivateAbilityFailedStartTime;


void OnClientActivateAbilityCaughtUp(FGameplayAbilitySpecHandle AbilityToActivate, FPredictionKey::KeyType PredictionKey);

UFUNCTION(Client, Reliable)
void ClientActivateAbilitySucceed(FGameplayAbilitySpecHandle AbilityToActivate, FPredictionKey PredictionKey);

UFUNCTION(Client, Reliable)
void ClientActivateAbilitySucceedWithEventData(FGameplayAbilitySpecHandle AbilityToActivate, FPredictionKey PredictionKey, FGameplayEventData TriggerEventData);

/** ServerTryActivateAbility的实现 */
virtual void InternalServerTryActivateAbility(FGameplayAbilitySpecHandle AbilityToActivate, bool InputPressed, const FPredictionKey& PredictionKey, const FGameplayEventData* TriggerEventData);

/** 当播放蒙太奇的预测键被拒绝时调用 */
void OnPredictiveMontageRejected(UAnimMontage* PredictiveMontage);

/** 将LocalAnimMontageInfo复制到RepAnimMontageInfo中 */
void AnimMontage_UpdateReplicatedData();
void AnimMontage_UpdateReplicatedData(FGameplayAbilityRepAnimMontage& OutRepAnimMontageInfo);

/** 复制重复动画数据的播放标志 */
void AnimMontage_UpdateForcedPlayFlags(FGameplayAbilityRepAnimMontage& OutRepAnimMontageInfo);

UE_DEPRECATED(4.26, "这将在未来的引擎版本中变为私有。请改用SetRepAnimMontageInfo、GetRepAnimMontageInfo或GetRepAnimMontageInfo_Mutable。")
/** 用于将蒙太奇信息复制到模拟客户端的数据结构 */
UPROPERTY(ReplicatedUsing=OnRep_ReplicatedAnimMontage)
FGameplayAbilityRepAnimMontage RepAnimMontageInfo;

void SetRepAnimMontageInfo(const FGameplayAbilityRepAnimMontage& NewRepAnimMontageInfo);
FGameplayAbilityRepAnimMontage& GetRepAnimMontageInfo_Mutable();
const FGameplayAbilityRepAnimMontage& GetRepAnimMontageInfo() const;

/** 是否是模拟actor的缓存值 */
UPROPERTY()
bool bCachedIsNetSimulated;

/** 如果当我们还没有与我们关联的animinstance时发生蒙太奇复制,则设置 */
UPROPERTY()
bool bPendingMontageRep;

/** 本地发起(如果是服务器,则为所有;如果是客户端,则为预测;如果是模拟代理,则为复制)的蒙太奇数据结构 */
UPROPERTY()
FGameplayAbilityLocalAnimMontage LocalAnimMontageInfo;

UFUNCTION()
virtual void OnRep_ReplicatedAnimMontage();

/** 如果我们准备好处理复制蒙太奇信息,则返回true */
virtual bool IsReadyForReplicatedMontage();

/** 从CurrentMontageSetNextSectionName调用的RPC函数,复制到其他客户端 */
UFUNCTION(reliable, server, WithValidation)
void ServerCurrentMontageSetNextSectionName(UAnimSequenceBase* ClientAnimation, float ClientPosition, FName SectionName, FName NextSectionName);

/** 从CurrentMontageJumpToSection调用的RPC函数,复制到其他客户端 */
UFUNCTION(reliable, server, WithValidation)
void ServerCurrentMontageJumpToSectionName(UAnimSequenceBase* ClientAnimation, FName SectionName);

/** 从CurrentMontageSetPlayRate调用的RPC函数,复制到其他客户端 */
UFUNCTION(reliable, server, WithValidation)
void ServerCurrentMontageSetPlayRate(UAnimSequenceBase* ClientAnimation, float InPlayRate);

/** 从游戏事件触发的能力 */
TMap<FGameplayTag, TArray<FGameplayAbilitySpecHandle > > GameplayEventTriggeredAbilities;

/** 从添加到所有者的标签触发的能力 */
TMap<FGameplayTag, TArray<FGameplayAbilitySpecHandle > > OwnedTagTriggeredAbilities;

/** 当绑定到能力的拥有标签更改时调用的回调 */
virtual void MonitoredTagChanged(const FGameplayTag Tag, int32 NewCount);

/** 如果指定能力应在此网络模式下从事件激活,则返回true */
bool HasNetworkAuthorityToActivateTriggeredAbility(const FGameplayAbilitySpec &Spec) const;

UE_DEPRECATED(5.3, "请直接使用OnImmunityBlockGameplayEffectDelegate。它从UImmunityGameplayEffectComponent触发。如果需要不同功能,可以创建自己的GameplayEffectComponent。")
virtual void OnImmunityBlockGameplayEffect(const FGameplayEffectSpec& Spec, const FActiveGameplayEffect* ImmunityGE);

// 内部游戏提示函数
virtual void AddGameplayCue_Internal(const FGameplayTag GameplayCueTag, FGameplayEffectContextHandle& EffectContext, FActiveGameplayCueContainer& GameplayCueContainer);
virtual void AddGameplayCue_Internal(const FGameplayTag GameplayCueTag, const FGameplayCueParameters& GameplayCueParameters, FActiveGameplayCueContainer& GameplayCueContainer);
virtual void RemoveGameplayCue_Internal(const FGameplayTag GameplayCueTag, FActiveGameplayCueContainer& GameplayCueContainer);

/** 实际将最终属性值推送到属性集的属性。不应由外部代码调用,因为这不会通过属性聚合器系统。 */
void SetNumericAttribute_Internal(const FGameplayAttribute &Attribute, float& NewFloatValue);

bool HasNetworkAuthorityToApplyGameplayEffect(FPredictionKey PredictionKey) const;

void ExecutePeriodicEffect(FActiveGameplayEffectHandle Handle);

void ExecuteGameplayEffect(FGameplayEffectSpec &Spec, FPredictionKey PredictionKey);

void CheckDurationExpired(FActiveGameplayEffectHandle Handle);

TArray<TObjectPtr<UGameplayTask>>& GetAbilityActiveTasks(UGameplayAbility* Ability);

/** 包含当前在此组件上活跃的所有游戏效果 */
UPROPERTY(Replicated)
FActiveGameplayEffectsContainer ActiveGameplayEffects;

/** 所有活跃游戏提示(在游戏效果之外执行)的列表 */
UPROPERTY(Replicated)
FActiveGameplayCueContainer ActiveGameplayCues;

/** 在最小复制模式下复制的游戏提示。这些通常来自ActiveGameplayEffects的提示(但由于我们不在最小模式下复制AGE,它们必须通过这里复制) */
UPROPERTY(Replicated)
FActiveGameplayCueContainer MinimalReplicationGameplayCues;

/** 具有这些标签的能力无法被激活 */
FGameplayTagCountContainer BlockedAbilityTags;

UE_DEPRECATED(4.26, "这将在未来的引擎版本中变为私有。请改用SetBlockedAbilityBindings、GetBlockedAbilityBindings或GetBlockedAbilityBindings_Mutable。")
/** 基于输入绑定跟踪被阻塞的能力。如果BlockedAbilityBindings[InputID] > 0,则能力被阻塞 */
UPROPERTY(Transient, Replicated)
TArray<uint8> BlockedAbilityBindings;

void SetBlockedAbilityBindings(const TArray<uint8>& NewBlockedAbilityBindings);
TArray<uint8>& GetBlockedAbilityBindings_Mutable();
const TArray<uint8>& GetBlockedAbilityBindings() const;

void DebugCyclicAggregatorBroadcasts(struct FAggregator* Aggregator);

/** 所有游戏标签(来自GE的OwnedGameplayTags和显式GameplayCueTags)的加速映射 */
FGameplayTagCountContainer GameplayTagCountContainer;

UE_DEPRECATED(4.26, "这将在未来的引擎版本中变为私有。请改用SetMinimalReplicationTags、GetMinimalReplicationTags或GetMinimalReplicationTags_Mutable。")
UPROPERTY(Replicated)
FMinimalReplicationTagCountMap MinimalReplicationTags;

void SetMinimalReplicationTags(const FMinimalReplicationTagCountMap& NewMinimalReplicationTags);
FMinimalReplicationTagCountMap& GetMinimalReplicationTags_Mutable();
const FMinimalReplicationTagCountMap& GetMinimalReplicationTags() const;

FMinimalReplicationTagCountMap& GetReplicatedLooseTags_Mutable();
const FMinimalReplicationTagCountMap& GetReplicatedLooseTags() const;

void ResetTagMap();

void NotifyTagMap_StackCountChange(const FGameplayTagContainer& Container);

virtual void OnTagUpdated(const FGameplayTag& Tag, bool TagExists) {};

const UAttributeSet* GetAttributeSubobject(const TSubclassOf<UAttributeSet> AttributeClass) const;
const UAttributeSet* GetAttributeSubobjectChecked(const TSubclassOf<UAttributeSet> AttributeClass) const;
const UAttributeSet* GetOrCreateAttributeSubobject(TSubclassOf<UAttributeSet> AttributeClass);

void UpdateTagMap_Internal(const FGameplayTagContainer& Container, int32 CountDelta);

friend struct FActiveGameplayEffect;
friend struct FActiveGameplayEffectAction;
friend struct FActiveGameplayEffectsContainer;
friend struct FActiveGameplayCue;
friend struct FActiveGameplayCueContainer;
friend struct FGameplayAbilitySpec;
friend struct FGameplayAbilitySpecContainer;
friend struct FAggregator;
friend struct FActiveGameplayEffectAction_Add;
friend struct FGameplayEffectSpec;
friend class AAbilitySystemDebugHUD;
friend class UAbilitySystemGlobals;

private:

// 修改SpawnedAttributes数组时必须调用,以使更改被复制
void SetSpawnedAttributesListDirty();

// 在AllReplicatedInstancedAbilities数组上的deprecation标签被移除,我们可以再次直接引用数组之前的私有访问器。
PRAGMA_DISABLE_DEPRECATION_WARNINGS
TArray<TObjectPtr<UGameplayAbility>>& GetReplicatedInstancedAbilities_Mutable() { return AllReplicatedInstancedAbilities; }
PRAGMA_ENABLE_DEPRECATION_WARNINGS

private:

/** 属性集列表 */
UPROPERTY(Replicated, ReplicatedUsing = OnRep_SpawnedAttributes, Transient)
TArray<TObjectPtr<UAttributeSet>> SpawnedAttributes;

UFUNCTION()
void OnRep_SpawnedAttributes(const TArray<UAttributeSet*>& PreviousSpawnedAttributes);

FDelegateHandle MonitoredTagChangedDelegateHandle;
FTimerHandle OnRep_ActivateAbilitiesTimerHandle;

/** 用于复制松散游戏标签的容器 */
UPROPERTY(Replicated)
FMinimalReplicationTagCountMap ReplicatedLooseTags;

uint8 bDestroyActiveStateInitiated : 1;
public:

/** 缓存指示此组件是否具有网络权限的标志。 */
void CacheIsNetSimulated();

/** PredictionKeys,请参阅GameplayPrediction.h中的更多信息。这必须放在AbilitySystemComponent上所有复制属性的*最后*,以确保OnRep/回调顺序。 */
UPROPERTY(Replicated, Transient)
FReplicatedPredictionKeyMap ReplicatedPredictionKeyMap;

protected:

struct FAbilityListLockActiveChange
{
FAbilityListLockActiveChange(UAbilitySystemComponent& InAbilitySystemComp,
TArray<FGameplayAbilitySpec, TInlineAllocator<2> >& PendingAdds,
TArray<FGameplayAbilitySpecHandle, TInlineAllocator<2> >& PendingRemoves) :
AbilitySystemComp(InAbilitySystemComp),
Adds(MoveTemp(PendingAdds)),
Removes(MoveTemp(PendingRemoves))
{
AbilitySystemComp.AbilityListLockActiveChanges.Add(this);
}

~FAbilityListLockActiveChange()
{
AbilitySystemComp.AbilityListLockActiveChanges.Remove(this);
}

UAbilitySystemComponent& AbilitySystemComp;
TArray<FGameplayAbilitySpec, TInlineAllocator<2> > Adds;
TArray<FGameplayAbilitySpecHandle, TInlineAllocator<2> > Removes;
};

TArray<FAbilityListLockActiveChange*> AbilityListLockActiveChanges;

};
  • Title: Unreal Engine——源码阅读:AbilitySystemComponent.h(UE5.4.4)
  • Author: ELecmark
  • Created at : 2025-12-15 23:48:06
  • Updated at : 2025-12-16 00:25:26
  • Link: https://elecmark.github.io/2025/12/15/UE5源码-AbilitySystemComponent-h/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
Unreal Engine——源码阅读:AbilitySystemComponent.h(UE5.4.4)