This commit is contained in:
GenZmeY 2022-05-20 23:45:26 +03:00
parent e5e2b711f0
commit 41f186ee15
8 changed files with 351 additions and 159 deletions

View File

@ -1,9 +1,40 @@
class KFGI_Access extends Object class KFGI_Access extends Object
within KFGameInfo_Survival; within KFGameInfo;
// Bypass protected modifier for these lists public function Array<class<KFPawn_Monster> > GetAIClassList()
{
local Array<class<KFPawn_Monster> > RV;
local class<KFPawn_Monster> KFPMC;
foreach AIClassList(KFPMC)
RV.AddItem(KFPMC);
return RV;
}
function bool IsCustomZed(class<KFPawn_Monster> KFPM) public function Array<class<KFPawn_Monster> > GetNonSpawnAIClassList()
{
local Array<class<KFPawn_Monster> > RV;
local class<KFPawn_Monster> KFPMC;
foreach NonSpawnAIClassList(KFPMC)
RV.AddItem(KFPMC);
return RV;
}
public function Array<class<KFPawn_Monster> > GetAIBossClassList()
{
local Array<class<KFPawn_Monster> > RV;
local class<KFPawn_Monster> KFPMC;
foreach AIBossClassList(KFPMC)
RV.AddItem(KFPMC);
return RV;
}
public function bool IsCustomZed(class<KFPawn_Monster> KFPM)
{ {
if (AIClassList.Find(KFPM) != INDEX_NONE) return false; if (AIClassList.Find(KFPM) != INDEX_NONE) return false;
if (NonSpawnAIClassList.Find(KFPM) != INDEX_NONE) return false; if (NonSpawnAIClassList.Find(KFPM) != INDEX_NONE) return false;
@ -11,6 +42,50 @@ function bool IsCustomZed(class<KFPawn_Monster> KFPM)
return true; return true;
} }
public function bool IsOriginalAI(class<KFPawn_Monster> KFPM, optional out EAIType AIType)
{
local int Type;
Type = AIClassList.Find(KFPM);
if (Type != INDEX_NONE)
{
AIType = EAIType(Type);
return true;
}
return false;
}
public function bool IsOriginalAIBoss(class<KFPawn_Monster> KFPM, optional out EBossAIType AIType)
{
local int Type;
Type = AIBossClassList.Find(KFPM);
if (Type != INDEX_NONE)
{
AIType = EBossAIType(Type);
return true;
}
return false;
}
public function class<KFPawn_Monster> AITypePawn(EAIType AIType)
{
if (AIType < AIClassList.Length)
return AIClassList[AIType];
else
return None;
}
public function class<KFPawn_Monster> BossAITypePawn(EBossAIType AIType)
{
if (AIType < AIBossClassList.Length)
return AIBossClassList[AIType];
else
return None;
}
defaultproperties defaultproperties
{ {

View File

@ -15,7 +15,23 @@ var config float SingleSpawnLimitCycleMultiplier;
var config int AliveSpawnLimit; var config int AliveSpawnLimit;
public static function InitConfig() public static function InitConfig(int Version, int LatestVersion)
{
switch (Version)
{
case `NO_CONFIG:
ApplyDefault();
default: break;
}
if (LatestVersion != Version)
{
StaticSaveConfig();
}
}
private static function ApplyDefault()
{ {
default.bCyclicalSpawn = true; default.bCyclicalSpawn = true;
default.bShadowSpawn = true; default.bShadowSpawn = true;
@ -25,8 +41,6 @@ public static function InitConfig()
default.SingleSpawnLimitPlayerMultiplier = 0.75; default.SingleSpawnLimitPlayerMultiplier = 0.75;
default.SingleSpawnLimitCycleMultiplier = 0.75; default.SingleSpawnLimitCycleMultiplier = 0.75;
default.AliveSpawnLimit = 0; default.AliveSpawnLimit = 0;
StaticSaveConfig();
} }
public static function bool Load(E_LogLevel LogLevel) public static function bool Load(E_LogLevel LogLevel)

View File

@ -16,24 +16,42 @@ struct S_SpawnEntryCfg
var config bool bStopRegularSpawn; var config bool bStopRegularSpawn;
var config Array<S_SpawnEntryCfg> Spawn; var config Array<S_SpawnEntryCfg> Spawn;
public static function InitConfig() public static function InitConfig(int Version, int LatestVersion, KFGI_Access KFGIA)
{
switch (Version)
{
case `NO_CONFIG:
ApplyDefault(KFGIA);
default: break;
}
if (LatestVersion != Version)
{
StaticSaveConfig();
}
}
private static function ApplyDefault(KFGI_Access KFGIA)
{ {
local S_SpawnEntryCfg SpawnEntry; local S_SpawnEntryCfg SpawnEntry;
local Array<class<KFPawn_Monster> > KFPM_Bosses;
local class<KFPawn_Monster> KFPMC;
default.bStopRegularSpawn = true; default.bStopRegularSpawn = true;
default.Spawn.Length = 0;
default.Spawn.Length = 0; SpawnEntry.ZedClass = "SomePackage.SomeClass";
SpawnEntry.BossClass = "KFGameContent.KFPawn_ZedFleshpoundKing";
SpawnEntry.ZedClass = "SomePackage.SomeFleshpoundClass";
SpawnEntry.SpawnCountBase = 2; SpawnEntry.SpawnCountBase = 2;
SpawnEntry.SingleSpawnLimit = 1; SpawnEntry.SingleSpawnLimit = 1;
SpawnEntry.Delay = 60; SpawnEntry.Delay = 30;
SpawnEntry.Probability = 100; SpawnEntry.Probability = 100;
SpawnEntry.bSpawnAtPlayerStart = false; SpawnEntry.bSpawnAtPlayerStart = false;
default.Spawn.AddItem(SpawnEntry); KFPM_Bosses = KFGIA.GetAIBossClassList();
foreach KFPM_Bosses(KFPMC)
StaticSaveConfig(); {
SpawnEntry.BossClass = "KFGameContent." $ String(KFPMC);
default.Spawn.AddItem(SpawnEntry);
}
} }
public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel) public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)

View File

@ -16,33 +16,46 @@ struct S_SpawnEntryCfg
var config Array<S_SpawnEntryCfg> Spawn; var config Array<S_SpawnEntryCfg> Spawn;
public static function InitConfig() public static function InitConfig(int Version, int LatestVersion, KFGI_Access KFGIA)
{
switch (Version)
{
case `NO_CONFIG:
ApplyDefault(KFGIA);
default: break;
}
if (LatestVersion != Version)
{
StaticSaveConfig();
}
}
private static function ApplyDefault(KFGI_Access KFGIA)
{ {
local S_SpawnEntryCfg SpawnEntry; local S_SpawnEntryCfg SpawnEntry;
local Array<class<KFPawn_Monster> > KFPM_Zeds;
local class<KFPawn_Monster> KFPMC;
default.Spawn.Length = 0; default.Spawn.Length = 0;
SpawnEntry.Wave = 1; SpawnEntry.Wave = 0;
SpawnEntry.ZedClass = "SomePackage.SomeZedClass1";
SpawnEntry.SpawnCountBase = 2;
SpawnEntry.SingleSpawnLimit = 1;
SpawnEntry.RelativeStart = 0;
SpawnEntry.Delay = 60;
SpawnEntry.Probability = 100;
SpawnEntry.bSpawnAtPlayerStart = false;
default.Spawn.AddItem(SpawnEntry);
SpawnEntry.Wave = 2;
SpawnEntry.ZedClass = "SomePackage.SomeZedClass2";
SpawnEntry.SpawnCountBase = 2; SpawnEntry.SpawnCountBase = 2;
SpawnEntry.SingleSpawnLimit = 1; SpawnEntry.SingleSpawnLimit = 1;
SpawnEntry.RelativeStart = 25; SpawnEntry.RelativeStart = 25;
SpawnEntry.Delay = 30; SpawnEntry.Delay = 60;
SpawnEntry.Probability = 50; SpawnEntry.Probability = 100;
SpawnEntry.bSpawnAtPlayerStart = false; SpawnEntry.bSpawnAtPlayerStart = false;
SpawnEntry.ZedClass = "SomePackage.SomeZedClass1";
default.Spawn.AddItem(SpawnEntry); default.Spawn.AddItem(SpawnEntry);
KFPM_Zeds = KFGIA.GetAIClassList();
StaticSaveConfig(); foreach KFPM_Zeds(KFPMC)
{
SpawnEntry.Wave++;
SpawnEntry.ZedClass = "KFGameContent." $ String(KFPMC);
default.Spawn.AddItem(SpawnEntry);
}
} }
public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel) public static function Array<S_SpawnEntry> Load(E_LogLevel LogLevel)

View File

@ -17,15 +17,29 @@ struct S_SpawnEntryCfg
var config bool bStopRegularSpawn; var config bool bStopRegularSpawn;
var config Array<S_SpawnEntryCfg> Spawn; var config Array<S_SpawnEntryCfg> Spawn;
public static function InitConfig() public static function InitConfig(int Version, int LatestVersion)
{
switch (Version)
{
case `NO_CONFIG:
ApplyDefault();
default: break;
}
if (LatestVersion != Version)
{
StaticSaveConfig();
}
}
private static function ApplyDefault()
{ {
local S_SpawnEntryCfg SpawnEntry; local S_SpawnEntryCfg SpawnEntry;
local EAIType AIType;
default.bStopRegularSpawn = true; default.bStopRegularSpawn = true;
default.Spawn.Length = 0; default.Spawn.Length = 0;
SpawnEntry.Wave = AT_Husk;
SpawnEntry.ZedClass = "SomePackage.SomeClass"; SpawnEntry.ZedClass = "SomePackage.SomeClass";
SpawnEntry.SpawnCountBase = 2; SpawnEntry.SpawnCountBase = 2;
SpawnEntry.SingleSpawnLimit = 1; SpawnEntry.SingleSpawnLimit = 1;
@ -33,9 +47,11 @@ public static function InitConfig()
SpawnEntry.Delay = 60; SpawnEntry.Delay = 60;
SpawnEntry.Probability = 100; SpawnEntry.Probability = 100;
SpawnEntry.bSpawnAtPlayerStart = false; SpawnEntry.bSpawnAtPlayerStart = false;
default.Spawn.AddItem(SpawnEntry); foreach class'KFGameInfo_Endless'.default.SpecialWaveTypes(AIType)
{
StaticSaveConfig(); SpawnEntry.Wave = AIType;
default.Spawn.AddItem(SpawnEntry);
}
} }
public static function Array<S_SpawnEntry> Load(KFGameInfo_Endless KFGIE, E_LogLevel LogLevel) public static function Array<S_SpawnEntry> Load(KFGameInfo_Endless KFGIE, E_LogLevel LogLevel)

View File

@ -1,6 +1,8 @@
class ZedSpawner extends Info class ZedSpawner extends Info
config(ZedSpawner); config(ZedSpawner);
const LatestVersion = 1;
const dt = 1; const dt = 1;
const CfgSpawn = class'Spawn'; const CfgSpawn = class'Spawn';
@ -24,7 +26,7 @@ struct S_SpawnEntry
{ {
var class<KFPawn_Monster> BossClass; var class<KFPawn_Monster> BossClass;
var class<KFPawn_Monster> ZedClass; var class<KFPawn_Monster> ZedClass;
var int Wave; var byte Wave;
var int SpawnCountBase; var int SpawnCountBase;
var int SingleSpawnLimitDefault; var int SingleSpawnLimitDefault;
var int SingleSpawnLimit; var int SingleSpawnLimit;
@ -38,7 +40,7 @@ struct S_SpawnEntry
var bool SpawnAtPlayerStart; var bool SpawnAtPlayerStart;
}; };
var config bool bConfigInitialized; var config int Version;
var config E_LogLevel LogLevel; var config E_LogLevel LogLevel;
var private Array<S_SpawnEntry> SpawnListR; var private Array<S_SpawnEntry> SpawnListR;
@ -66,6 +68,169 @@ var private Array<class<KFPawn_Monster> > CustomZeds;
delegate bool WaveCondition(S_SpawnEntry SE); delegate bool WaveCondition(S_SpawnEntry SE);
event PreBeginPlay()
{
`ZS_Trace(`Location);
if (WorldInfo.NetMode == NM_Client)
{
`ZS_Fatal("NetMode == NM_Client, Destroy...");
Destroy();
return;
}
Super.PreBeginPlay();
}
event PostBeginPlay()
{
`ZS_Trace(`Location);
if (bPendingDelete) return;
Super.PostBeginPlay();
Init();
}
private function InitConfig()
{
if (Version == `NO_CONFIG)
{
LogLevel = LL_Info;
SaveConfig();
}
CfgSpawn.static.InitConfig(Version, LatestVersion);
CfgSpawnListR.static.InitConfig(Version, LatestVersion, KFGIA);
CfgSpawnListBW.static.InitConfig(Version, LatestVersion, KFGIA);
CfgSpawnListSW.static.InitConfig(Version, LatestVersion);
switch (Version)
{
case `NO_CONFIG:
`ZS_Info("Config created");
case MaxInt:
`ZS_Info("Config updated to version"@LatestVersion);
break;
case LatestVersion:
`ZS_Info("Config is up-to-date");
break;
default:
`ZS_Warn("The config version is higher than the current version (are you using an old mutator?)");
`ZS_Warn("Config version is" @ Version @ "but current version is" @ LatestVersion);
`ZS_Warn("The config version will be changed to" @ LatestVersion);
break;
}
if (LatestVersion != Version)
{
Version = LatestVersion;
SaveConfig();
}
}
private function Init()
{
local S_SpawnEntry SE;
`ZS_Trace(`Location);
KFGIS = KFGameInfo_Survival(WorldInfo.Game);
if (KFGIS == None)
{
`ZS_Fatal("Incompatible gamemode:" @ WorldInfo.Game $ ". Destroy...");
Destroy();
return;
}
KFGIA = new(KFGIS) class'KFGI_Access';
KFGIE = KFGameInfo_Endless(KFGIS);
InitConfig();
if (LogLevel == LL_WrongLevel)
{
LogLevel = LL_Info;
`ZS_Warn("Wrong 'LogLevel', return to default value");
SaveConfig();
}
`ZS_Log("LogLevel:" @ LogLevel);
if (!CfgSpawn.static.Load(LogLevel))
{
`ZS_Fatal("Wrong settings, Destroy...");
Destroy();
return;
}
SpawnListR = CfgSpawnListR.static.Load(LogLevel);
SpawnListBW = CfgSpawnListBW.static.Load(LogLevel);
SpawnListSW = CfgSpawnListSW.static.Load(KFGIE, LogLevel);
CurrentWave = INDEX_NONE;
SpecialWave = INDEX_NONE;
CurrentCycle = 1;
if (CfgSpawn.default.bCyclicalSpawn)
{
CycleWaveSize = 0;
CycleWaveShift = MaxInt;
foreach SpawnListR(SE)
{
CycleWaveShift = Min(CycleWaveShift, SE.Wave);
CycleWaveSize = Max(CycleWaveSize, SE.Wave);
}
CycleWaveSize = CycleWaveSize - CycleWaveShift + 1;
}
CreateBossCache();
PreloadContent();
SetTimer(float(dt), true, nameof(SpawnTimer));
}
private function CreateBossCache()
{
local S_SpawnEntry SE;
foreach SpawnListBW(SE)
if (BossClassCache.Find(SE.BossClass) == INDEX_NONE)
BossClassCache.AddItem(SE.BossClass);
}
private function PreloadContent()
{
local class<KFPawn_Monster> PawnClass;
ExtractCustomZedsFromSpawnList(SpawnListR, CustomZeds);
ExtractCustomZedsFromSpawnList(SpawnListBW, CustomZeds);
ExtractCustomZedsFromSpawnList(SpawnListSW, CustomZeds);
foreach CustomZeds(PawnClass)
{
`ZS_Info("Preload content:" @ PawnClass);
PawnClass.static.PreloadContent();
}
}
private function ExtractCustomZedsFromSpawnList(Array<S_SpawnEntry> SpawnList, out Array<class<KFPawn_Monster> > Out)
{
local S_SpawnEntry SE;
foreach SpawnList(SE)
{
if (Out.Find(SE.ZedClass) == INDEX_NONE
&& KFGIA.IsCustomZed(SE.ZedClass))
{
Out.AddItem(SE.ZedClass);
}
}
}
public function bool WaveConditionRegular(S_SpawnEntry SE) public function bool WaveConditionRegular(S_SpawnEntry SE)
{ {
`ZS_Trace(`Location); `ZS_Trace(`Location);
@ -108,119 +273,6 @@ public function bool WaveConditionSpecial(S_SpawnEntry SE)
return (SE.Wave == SpecialWave); return (SE.Wave == SpecialWave);
} }
event PostBeginPlay()
{
`ZS_Trace(`Location);
Super.PostBeginPlay();
if (WorldInfo.NetMode == NM_Client)
{
Destroy();
return;
}
Init();
}
private function Init()
{
local S_SpawnEntry SE;
`ZS_Trace(`Location);
if (!bConfigInitialized)
{
bConfigInitialized = true;
LogLevel = LL_Info;
SaveConfig();
CfgSpawn.static.InitConfig();
CfgSpawnListR.static.InitConfig();
CfgSpawnListBW.static.InitConfig();
CfgSpawnListSW.static.InitConfig();
`ZS_Info("Config initialized.");
}
if (LogLevel == LL_WrongLevel)
{
LogLevel = LL_Info;
`ZS_Warn("Wrong 'LogLevel', return to default value");
SaveConfig();
}
`ZS_Log("LogLevel:" @ LogLevel);
if (!CfgSpawn.static.Load(LogLevel))
{
`ZS_Fatal("Wrong settings, Destroy...");
Destroy();
return;
}
CurrentWave = INDEX_NONE;
KFGIS = KFGameInfo_Survival(WorldInfo.Game);
if (KFGIS == None)
{
`ZS_Fatal("Incompatible gamemode:" @ WorldInfo.Game $ ". Destroy...");
Destroy();
return;
}
KFGIA = new(KFGIS) class'KFGI_Access';
KFGIE = KFGameInfo_Endless(KFGIS);
SpawnListR = CfgSpawnListR.static.Load(LogLevel);
SpawnListBW = CfgSpawnListBW.static.Load(LogLevel);
SpawnListSW = CfgSpawnListSW.static.Load(KFGIE, LogLevel);
SpecialWave = INDEX_NONE;
CurrentCycle = 1;
CycleWaveSize = 0;
CycleWaveShift = MaxInt;
foreach SpawnListR(SE)
{
if (CustomZeds.Find(SE.ZedClass) == INDEX_NONE
&& KFGIA.IsCustomZed(SE.ZedClass))
{
`ZS_Debug("Add custom zed:" @ SE.ZedClass);
CustomZeds.AddItem(SE.ZedClass);
SE.ZedClass.static.PreloadContent();
}
CycleWaveShift = Min(CycleWaveShift, SE.Wave);
CycleWaveSize = Max(CycleWaveSize, SE.Wave);
}
CycleWaveSize = CycleWaveSize - CycleWaveShift + 1;
foreach SpawnListBW(SE)
{
if (CustomZeds.Find(SE.ZedClass) == INDEX_NONE
&& KFGIA.IsCustomZed(SE.ZedClass))
{
`ZS_Debug("Add custom zed:" @ SE.ZedClass);
CustomZeds.AddItem(SE.ZedClass);
SE.ZedClass.static.PreloadContent();
}
if (BossClassCache.Find(SE.BossClass) == INDEX_NONE)
BossClassCache.AddItem(SE.BossClass);
}
foreach SpawnListSW(SE)
{
if (CustomZeds.Find(SE.ZedClass) == INDEX_NONE
&& KFGIA.IsCustomZed(SE.ZedClass))
{
`ZS_Debug("Add custom zed:" @ SE.ZedClass);
CustomZeds.AddItem(SE.ZedClass);
SE.ZedClass.static.PreloadContent();
}
}
SetTimer(float(dt), true, nameof(SpawnTimer));
}
private function SpawnTimer() private function SpawnTimer()
{ {
`ZS_Trace(`Location); `ZS_Trace(`Location);

View File

@ -10,6 +10,8 @@ replication
LogLevel; LogLevel;
} }
public simulated function bool SafeDestroy() { if (!bPendingDelete) return Destroy(); else return true; }
public reliable client function ClientSync(class<KFPawn_Monster> CustomZed) public reliable client function ClientSync(class<KFPawn_Monster> CustomZed)
{ {
`ZS_Trace(`Location); `ZS_Trace(`Location);
@ -31,18 +33,18 @@ public reliable client function SyncFinished()
CustomZed.static.PreloadContent(); CustomZed.static.PreloadContent();
} }
Destroy(); SafeDestroy();
} }
public reliable server function ServerSync() public reliable server function ServerSync()
{ {
`ZS_Trace(`Location); `ZS_Trace(`Location);
if (CustomZeds.Length == Recieved) if (CustomZeds.Length == Recieved || WorldInfo.NetMode == NM_StandAlone)
{ {
`ZS_Debug("Sync finished"); `ZS_Debug("Sync finished");
SyncFinished(); SyncFinished();
Destroy(); SafeDestroy();
} }
else else
{ {

View File

@ -8,3 +8,5 @@
`define ZS_Info(msg) `log("INFO:" @ `msg, (LogLevel >= LL_Info), `ZS_Tag) `define ZS_Info(msg) `log("INFO:" @ `msg, (LogLevel >= LL_Info), `ZS_Tag)
`define ZS_Debug(msg) `log("DEBUG:" @ `msg, (LogLevel >= LL_Debug), `ZS_Tag) `define ZS_Debug(msg) `log("DEBUG:" @ `msg, (LogLevel >= LL_Debug), `ZS_Tag)
`define ZS_Trace(msg) `log("TRACE:" @ `msg, (LogLevel >= LL_Trace), `ZS_Tag) `define ZS_Trace(msg) `log("TRACE:" @ `msg, (LogLevel >= LL_Trace), `ZS_Tag)
`define NO_CONFIG 0