1
0
KF2-Dev-Scripts/WebAdmin/Classes/DataStoreCache.uc
2020-12-13 18:01:13 +03:00

758 lines
16 KiB
Ucode

/**
* DataStore access class.
*
* Copyright 2008 Epic Games, Inc. All Rights Reserved
* Copyright (C) 2015 Tripwire Interactive LLC
*
* @author Michiel 'elmuerte' Hendriks
*/
class DataStoreCache extends Object config(WebAdmin);
`include(WebAdmin.uci)
/**
* Instance providing lookup functionality. Don't access directly, use getDatasource()
*/
var UIDataStore_GameResource datasource;
/**
* List of gametypes
*/
var array<DCEGameInfo> gametypes;
/**
* List of all maps
*/
var array<DCEMapInfo> maps;
struct GameTypeMaps
{
var string gametype;
var array<DCEMapInfo> maps;
};
var array<GameTypeMaps> gameTypeMapCache;
struct MutatorGroup
{
var string GroupName;
var array<DCEMutator> mutators;
};
/**
* List of mutators grouped by group
*/
var array<MutatorGroup> mutatorGroups;
/**
* Simple list of all mutators
*/
var array<DCEMutator> mutators;
struct GameTypeMutators
{
var string gametype;
var array<MutatorGroup> mutatorGroups;
};
/**
* Cache of the mutators available for a specific gametype
*/
var array<GameTypeMutators> gameTypeMutatorCache;
struct MutatorAllowance
{
var string id;
var bool allowed;
};
/**
* Cache mutator allowance to avoid loading packages at runtime as much as
* possible.
*/
var config array<MutatorAllowance> allowanceCache;
`define WITH_WEAPONS
`if(`WITH_WEAPONS)
var array<UIWeaponSummary> weapons;
`endif
function cleanup()
{
gametypes.remove(0, gametypes.length);
maps.remove(0, maps.length);
gameTypeMapCache.remove(0, gameTypeMapCache.length);
mutatorGroups.remove(0, mutatorGroups.length);
gameTypeMutatorCache.remove(0, gameTypeMutatorCache.length);
`if(`WITH_WEAPONS)
weapons.remove(0, weapons.length);
`endif
}
function array<DCEGameInfo> getGameTypes(optional string sorton = "FriendlyName")
{
local array<DCEGameInfo> result;
local int i, j;
if (gametypes.Length == 0)
{
loadGameTypes();
}
if (sorton ~= "FriendlyName")
{
result = gametypes;
return result;
}
for (i = 0; i < gametypes.length; i++)
{
for (j = 0; j < result.length; j++)
{
if (compareGameType(result[j], gametypes[i], sorton))
{
result.Insert(j, 1);
result[j] = gametypes[i];
break;
}
}
if (j == result.length)
{
result.AddItem(gametypes[i]);
}
}
return result;
}
/**
* Resolve a partial classname of a gametype (e.g. without package name) to the
* entry in the cache list.
*/
function int resolveGameType(coerce string classname)
{
local int idx;
if (gametypes.Length == 0)
{
loadGameTypes();
}
classname = "."$classname;
for (idx = 0; idx < gametypes.length; idx++)
{
if (Right("."$gametypes[idx].data.ClassName, Len(classname)) ~= classname)
{
return idx;
}
}
return INDEX_NONE;
}
function loadGameTypes()
{
local array<UIResourceDataProvider> ProviderList;
local UIGameInfoSummary item;
local DCEGameInfo entry;
local int i, j;
if (gametypes.Length > 0)
{
return;
}
getDatasource().GetResourceProviders('GameTypes', ProviderList);
for (i = 0; i < ProviderList.length; i++)
{
item = UIGameInfoSummary(ProviderList[i]);
if (item.bIsDisabled) {
continue;
}
for (j = 0; j < gametypes.length; j++)
{
if (gametypes[j].name == item.name)
{
`log("Found duplicate game mode with name: "$item.name,,'WebAdmin');
break;
}
}
if (j != gametypes.length)
{
continue;
}
entry = new(self, string(item.name)) class'DCEGameInfo';
entry.init(item);
for (j = 0; j < gametypes.length; j++)
{
if (compareGameType(gametypes[j], entry, "FriendlyName"))
{
gametypes.Insert(j, 1);
gametypes[j] = entry;
break;
}
}
if (j == gametypes.length)
{
gametypes.AddItem(entry);
}
}
}
static function bool compareGameType(DCEGameInfo g1, DCEGameInfo g2, string sorton)
{
if (sorton ~= "FriendlyName")
{
return g1.FriendlyName > g2.FriendlyName;
}
else if (sorton ~= "GameName")
{
return g1.data.GameName > g2.data.GameName;
}
else if (sorton ~= "Description")
{
return g1.Description > g2.Description;
}
else if (sorton ~= "ClassName" || sorton ~= "GameMode")
{
return g1.data.ClassName > g2.data.ClassName;
}
else if (sorton ~= "GameAcronym" || sorton ~= "Acronym")
{
return g1.data.GameAcronym > g2.data.GameAcronym;
}
else if (sorton ~= "GameSettingsClass")
{
return g1.data.GameSettingsClassName > g2.data.GameSettingsClassName;
}
}
static function string getMapPrefix(string MapName)
{
local int idx;
idx = InStr(MapName, "-");
if (idx == INDEX_NONE) idx = InStr(MapName, "-");
if (idx == INDEX_NONE) return "";
return Caps(Left(MapName, idx));
}
function array<DCEMapInfo> getMaps(optional string gametype = "", optional string sorton = "MapName")
{
local array<DCEMapInfo> result, workset;
local int i, j, idx;
local array<string> prefixes;
local string prefix;
if (maps.Length == 0)
{
loadMaps();
}
if (gametype == "")
{
workset = maps;
}
else {
idx = resolveGameType(gametype);
if (idx == INDEX_NONE)
{
`Log("gametype not found "$gametype);
return result;
}
j = gameTypeMapCache.find('gametype', gametypes[idx].data.ClassName);
if (j == INDEX_NONE)
{
ParseStringIntoArray(Caps(gametypes[idx].data.MapPrefix), prefixes, "|", true);
for (i = 0; i < maps.length; i++)
{
prefix = getMapPrefix(maps[i].data.MapName);
if (prefixes.find(prefix) > INDEX_NONE)
{
workset.AddItem(maps[i]);
}
}
gameTypeMapCache.add(1);
gameTypeMapCache[gameTypeMapCache.length-1].gametype = gametypes[idx].data.ClassName;
gameTypeMapCache[gameTypeMapCache.length-1].maps = workset;
}
else {
workset = gameTypeMapCache[j].maps;
}
}
if (sorton ~= "MapName")
{
return workset;
}
for (i = 0; i < workset.length; i++)
{
for (j = 0; j < result.length; j++)
{
if (compareMap(result[j], workset[i], sorton))
{
result.Insert(j, 1);
result[j] = workset[i];
break;
}
}
if (j == result.length)
{
result.AddItem(workset[i]);
}
}
return result;
}
/**
* Get a list of gametypes for the given map
*/
function array<string> getGametypesByMap(string MapName)
{
local string prefix;
local array<string> result, prefixes;
local int i;
prefix = getMapPrefix(MapName);
if (len(prefix) == 0) return result;
loadGameTypes();
for (i = 0; i < gametypes.length; ++i)
{
ParseStringIntoArray(Caps(gametypes[i].data.MapPrefix), prefixes, "|", true);
if (prefixes.find(prefix) > INDEX_NONE)
{
result.AddItem(gametypes[i].data.ClassName);
}
}
return result;
}
function loadMaps()
{
local array<UIResourceDataProvider> ProviderList;
local UIMapSummary item;
local DCEMapInfo entry;
local int i, j;
if (maps.Length > 0)
{
return;
}
gameTypeMapCache.Remove(0, gameTypeMapCache.length);
getDatasource().GetResourceProviders('Maps', ProviderList);
for (i = 0; i < ProviderList.length; i++)
{
item = UIMapSummary(ProviderList[i]);
for (j = 0; j < maps.length; j++)
{
if (maps[j].name == item.name)
{
`log("Found duplicate map with name: "$item.name,,'WebAdmin');
break;
}
}
if (j != maps.length)
{
continue;
}
entry = new(self, string(item.name)) class'DCEMapInfo';
entry.init(item);
for (j = 0; j < maps.length; j++)
{
if (compareMap(maps[j], entry, "MapName"))
{
maps.Insert(j, 1);
maps[j] = entry;
break;
}
}
if (j == maps.length)
{
maps.AddItem(entry);
}
}
}
static function bool compareMap(DCEMapInfo g1, DCEMapInfo g2, string sorton)
{
if (sorton ~= "MapName")
{
return g1.data.MapName > g2.data.MapName;
}
else if (sorton ~= "DisplayName")
{
return g1.data.DisplayName > g2.data.DisplayName;
}
else if (sorton ~= "FriendlyName")
{
return g1.FriendlyName > g2.FriendlyName;
}
else if (sorton ~= "Description")
{
return g1.Description > g2.Description;
}
}
function array<MutatorGroup> getMutators(optional string gametype = "", optional string sorton = "FriendlyName")
{
local array<MutatorGroup> result, workset;
local int j, idx;
if (mutatorGroups.Length == 0)
{
loadMutators();
}
if (gametype == "")
{
workset = mutatorGroups;
}
else {
idx = resolveGameType(gametype);
if (idx == INDEX_NONE)
{
`Log("gametype not found "$gametype);
result.length = 0;
return result;
}
j = gameTypeMutatorCache.find('gametype', gametypes[idx].data.ClassName);
if (j == INDEX_NONE)
{
workset = filterMutators(mutatorGroups, gametypes[idx].data.ClassName);
gameTypeMutatorCache.add(1);
gameTypeMutatorCache[gameTypeMutatorCache.length-1].gametype = gametypes[idx].data.ClassName;
gameTypeMutatorCache[gameTypeMutatorCache.length-1].mutatorGroups = workset;
}
else {
workset = gameTypeMutatorCache[j].mutatorGroups;
}
}
if (sorton ~= "FriendlyName")
{
return workset;
}
return workset;
// TODO: implement sorting
/*
for (i = 0; i < workset.length; i++)
{
for (j = 0; j < result.length; j++)
{
if (compareMap(result[j], workset[i], sorton))
{
result.Insert(j, 1);
result[j] = workset[i];
break;
}
}
if (j == result.length)
{
result.AddItem(workset[i]);
}
}
return result;
*/
}
/**
* Filter the source mutator group list on the provided gametype
*/
function array<MutatorGroup> filterMutators(array<MutatorGroup> source, string gametype)
{
local int i, j, k;
local array<MutatorGroup> result;
local MutatorGroup group;
local class<GameInfo> GameModeClass;
local bool findGameType, allowanceChanged;
local string GameTypeMutatorId;
findGameType = true;
for (i = 0; i < source.length; i++)
{
group.GroupName = source[i].groupname;
group.mutators.length = 0;
for (j = 0; j < source[i].mutators.length; j++)
{
if (source[i].mutators[j].data.SupportedGameTypes.length > 0)
{
k = source[i].mutators[j].data.SupportedGameTypes.Find(gametype);
if (k != INDEX_NONE)
{
group.mutators.AddItem(source[i].mutators[j]);
}
}
else {
GameTypeMutatorId = gametype$"@"$source[i].mutators[j].data.ClassName;
k = allowanceCache.find('id', GameTypeMutatorId);
if (k != INDEX_NONE)
{
if (allowanceCache[k].allowed)
{
group.mutators.AddItem(source[i].mutators[j]);
}
}
else {
if (GameModeClass == none && findGameType)
{
findGameType = false;
GameModeClass = class<GameInfo>(DynamicLoadObject(gametype, class'class'));
if (GameModeClass == none)
{
`Log("DataStoreCache::filterMutators() - Unable to find game class: "$gametype);
}
}
if(GameModeClass != none)
{
allowanceChanged = true;
k = allowanceCache.length;
allowanceCache.length = k+1;
allowanceCache[k].id = GameTypeMutatorId;
if (GameModeClass.static.AllowMutator(source[i].mutators[j].data.ClassName))
{
group.mutators.AddItem(source[i].mutators[j]);
allowanceCache[k].allowed = true;
}
}
}
}
}
if (group.mutators.length > 0)
{
result.AddItem(group);
}
}
if (allowanceChanged)
{
SaveConfig();
}
return result;
}
function loadMutators()
{
local array<UIResourceDataProvider> ProviderList;
local KFMutatorSummary item;
local DCEMutator entry;
local int i, j, groupid, emptyGroupId;
local array<string> groups;
local string group;
if (mutatorGroups.Length > 0)
{
return;
}
mutators.Remove(0, mutators.length);
gameTypeMutatorCache.Remove(0, gameTypeMutatorCache.length);
emptyGroupId = 0;
// the empty group
mutatorGroups.Length = 1;
getDatasource().GetResourceProviders('Mutators', ProviderList);
for (i = 0; i < ProviderList.length; i++)
{
item = KFMutatorSummary(ProviderList[i]);
if (item.bIsDisabled)
{
continue;
}
for (j = 0; j < mutators.length; j++)
{
if (mutators[j].name == item.name)
{
`log("Found duplicate mutator with name: "$item.name,,'WebAdmin');
break;
}
}
if (j != mutators.length)
{
continue;
}
entry = new(self, string(item.Name)) class'DCEMutator';
entry.init(item);
groups = item.GroupNames;
if (groups.length == 0)
{
groups.AddItem("");
}
foreach groups(group)
{
groupid = mutatorGroups.find('GroupName', group);
if (groupid == INDEX_NONE)
{
for (groupid = 0; groupid < mutatorGroups.length; groupid++)
{
if (mutatorGroups[groupid].GroupName > group)
{
break;
}
}
mutatorGroups.Insert(groupid, 1);
mutatorGroups[groupid].GroupName = Caps(group);
}
if (emptyGroupId == -1 && len(group) == 0)
{
emptyGroupId = groupid;
}
for (j = 0; j < mutatorGroups[groupid].mutators.length; j++)
{
if (compareMutator(mutatorGroups[groupid].mutators[j], entry, "FriendlyName"))
{
mutatorGroups[groupid].mutators.Insert(j, 1);
mutatorGroups[groupid].mutators[j] = entry;
break;
}
}
if (j == mutatorGroups[groupid].mutators.length)
{
mutatorGroups[groupid].mutators.AddItem(entry);
}
}
for (j = 0; j < mutators.length; j++)
{
if (compareMutator(mutators[j], entry, "FriendlyName"))
{
mutators.Insert(j, 1);
mutators[j] = entry;
break;
}
}
if (j == mutators.length)
{
mutators.AddItem(entry);
}
}
if (emptyGroupId == -1)
{
emptyGroupId = mutatorGroups.length;
mutatorGroups[emptyGroupId].GroupName = "";
}
// remove groups with single entries
for (i = mutatorGroups.length-1; i >= 0 ; i--)
{
if (i == emptyGroupId) continue;
if (mutatorGroups[i].mutators.length > 1) continue;
entry = mutatorGroups[i].mutators[0];
for (j = 0; j < mutatorGroups[emptyGroupId].mutators.length; j++)
{
if (mutatorGroups[emptyGroupId].mutators[j] == entry)
{
break;
}
if (compareMutator(mutatorGroups[emptyGroupId].mutators[j], entry, "FriendlyName"))
{
mutatorGroups[emptyGroupId].mutators.Insert(j, 1);
mutatorGroups[emptyGroupId].mutators[j] = entry;
break;
}
}
if (j == mutatorGroups[emptyGroupId].mutators.length)
{
mutatorGroups[emptyGroupId].mutators.AddItem(entry);
}
mutatorGroups.Remove(i, 1);
}
if (mutatorGroups[emptyGroupId].mutators.Length == 0)
{
mutatorGroups.Remove(emptyGroupId, 1);
}
}
static function bool compareMutator(DCEMutator m1, DCEMutator m2, string sorton)
{
if (sorton ~= "ClassName")
{
return m1.data.ClassName > m2.data.ClassName;
}
else if (sorton ~= "FriendlyName")
{
return m1.FriendlyName > m2.FriendlyName;
}
else if (sorton ~= "Description")
{
return m1.Description > m2.Description;
}
}
`if(`WITH_WEAPONS)
function loadWeapons()
{
local array<UIResourceDataProvider> ProviderList;
local UIWeaponSummary item;
local int i, j;
if (weapons.Length > 0)
{
return;
}
getDatasource().GetResourceProviders('Weapons', ProviderList);
for (i = 0; i < ProviderList.length; i++)
{
item = UIWeaponSummary(ProviderList[i]);
for (j = 0; j < weapons.length; j++)
{
if (compareWeapon(weapons[j], item, "FriendlyName"))
{
weapons.Insert(j, 1);
weapons[j] = item;
break;
}
}
if (j == weapons.length)
{
weapons.AddItem(item);
}
}
}
static function bool compareWeapon(UIWeaponSummary w1, UIWeaponSummary w2, string sorton)
{
if (sorton ~= "ClassName")
{
return w1.ClassName > w2.ClassName;
}
else if (sorton ~= "FriendlyName")
{
return w1.FriendlyName > w2.FriendlyName;
}
else if (sorton ~= "Description")
{
return w1.Description > w2.Description;
}
/*
else if (sorton ~= "AmmoClassPath")
{
return w1.AmmoClassPath > w2.AmmoClassPath;
}
*/
/*
// not available everywhere, and not really that interesting
else if (sorton ~= "MeshReference")
{
return w1.MeshReference > w2.MeshReference;
}
*/
}
`endif
function UIDataStore_GameResource getDatasource()
{
if (datasource == none)
{
datasource = UIDataStore_GameResource(class'UIRoot'.static.StaticResolveDataStore(class'UIDataStore_GameResource'.default.Tag));
}
return datasource;
}