1
0
KF2-Dev-Scripts/KFGame/Classes/KFLightPool.uc

146 lines
4.3 KiB
Ucode
Raw Permalink Normal View History

2020-12-13 15:01:13 +00:00
//=============================================================================
// KFLightPool
//=============================================================================
// A client pool to dynamical scale active lights spawned during gameplay based
// on scene relevance and priority. Unlike other pools this doesn't have a list
// of blank components to re-use, because there is no light template system.
// Instead, expect the caller to handle component management.
//
// We can categorize lights based on lifetime in the world. On one end you have
// very brief lights that work well with bDropDetail, but on the other we have
// environment lights that work better with GFX settings such as detail mode.
// 1. Flash / Burst (e.g. explosion, muzzle flash)
// 2. Lifespan (e.g. projectile)
// 3. Indefinite / No-Lifespan (e.g. character, weapon)
// 4. Persistent (e.g. environment)
//=============================================================================
// Killing Floor 2
// Copyright (C) 2016 Tripwire Interactive LLC
// - Andrew "Strago" Ladenberger
//=============================================================================
class KFLightPool extends Actor
native(Effect);
struct native LightPoolInfo
{
var PointLightComponent Component;
var int Priority;
var bool bAllowReenable;
};
enum LightPoolPriority
{
LPP_Low,
LPP_High,
LPP_GameplayUsed
};
/** components currently active */
var private array<LightPoolInfo> ActiveComponents;
/** maximum allowed active components */
var() int MaxOnScreenLights;
/** Save values from last frame to use when new lights are registered */
var transient int CurrentOnScreenLights;
var transient int CurrentLowestPriority;
cpptext
{
void TickSpecial(FLOAT DeltaTime);
UBOOL ReenableLight(UPointLightComponent* LightComp, FVector& ViewLocation);
}
//
// Called immediately before gameplay begins.
//
event PreBeginPlay()
{
switch( WorldInfo.GetDetailMode() )
{
case DM_Low:
MaxOnScreenLights = 5;
break;
case DM_Medium:
MaxOnScreenLights = 10;
break;
case DM_High:
MaxOnScreenLights = 20;
break;
}
Super.PreBeginPlay();
}
/**
* Register a light with the pool so it can be managed relative to other lights
*/
function bool RegisterPointLight(PointLightComponent LightComp, optional LightPoolPriority PriorityType=LPP_Low)
{
local LightPoolInfo NewLight;
local int i;
// Requires attachment before calling (for now), so that we can get info on the owner.
// Maybe later we want to pass the owner as a function param?
if ( LightComp.Owner == None || !LightComp.bAttached )
{
`log(GetFuncName()@"failed because light has not been attached");
LightComp.SetEnabled(false);
return false;
}
if ( WorldInfo.NetMode == NM_DedicatedServer )
{
`log(GetFuncName()@"perf warning: dedicated server shouldn't be playing with lights on"@LightComp.Owner);
LightComp.DetachFromAny();
return false;
}
NewLight.Component = LightComp;
NewLight.Priority = 100 * PriorityType;
NewLight.bAllowReenable = LightComp.bEnabled && (Owner.LifeSpan == 0 || PriorityType == LPP_GameplayUsed);
if ( LightComp.Owner.Instigator != None && LightComp.Owner.Instigator.IsLocallyControlled() )
{
NewLight.Priority += 50.f;
}
// If the list is full start the light disabled
if ( CurrentOnScreenLights >= MaxOnScreenLights && NewLight.Priority < CurrentLowestPriority )
{
`log(GetFuncName()@"disabling incoming light for Owner:"$LightComp.Owner@"Priority:"$NewLight.Priority@"Total:"$ActiveComponents.Length,bDebug);
LightComp.SetEnabled(false);
// If the lifespan is too short to re-enable, don't bother tracking it
if ( !NewLight.bAllowReenable )
{
LightComp.DetachFromAny();
return false;
}
}
// insert into sorted list
for (i = 0; i < ActiveComponents.Length; i++)
{
if ( NewLight.Priority >= ActiveComponents[i].Priority)
{
break;
}
}
`log(GetFuncName()@"adding light for Owner:"$LightComp.Owner@"Priority:"$NewLight.Priority@"Total:"$ActiveComponents.Length,bDebug);
// Add to the end
ActiveComponents.InsertItem(i, NewLight);
SetTickIsDisabled(false);
return TRUE;
}
defaultproperties
{
//bDebug=true
TickGroup=TG_DuringAsyncWork
bTickIsDisabled=true
MaxOnScreenLights=20
}