2023-10-28 03:31:09 +08:00
using CodeWalker.Core.Utils ;
using SharpDX ;
2017-09-21 18:33:05 +08:00
using System ;
using System.Collections.Concurrent ;
using System.Collections.Generic ;
2023-10-28 03:31:09 +08:00
using System.Diagnostics ;
2018-12-13 23:14:14 +08:00
using System.IO ;
2017-09-21 18:33:05 +08:00
using System.Linq ;
using System.Text ;
using System.Threading ;
using System.Threading.Tasks ;
using System.Xml ;
namespace CodeWalker.GameFiles
{
2023-10-28 03:31:09 +08:00
public partial class GameFileCache
2017-09-21 18:33:05 +08:00
{
public RpfManager RpfMan ;
2023-10-28 03:31:09 +08:00
public event Action < string > UpdateStatus ;
public event Action < string > ErrorLog ;
public int MaxItemsPerLoop = 3 ; //to keep things flowing...
2017-09-21 18:33:05 +08:00
2019-01-08 15:57:24 +08:00
private ConcurrentQueue < GameFile > requestQueue = new ConcurrentQueue < GameFile > ( ) ;
2017-09-21 18:33:05 +08:00
////dynamic cache
2018-02-24 21:59:00 +08:00
private Cache < GameFileCacheKey , GameFile > mainCache ;
2017-09-21 18:33:05 +08:00
public volatile bool IsInited = false ;
private volatile bool archetypesLoaded = false ;
2023-10-28 03:31:09 +08:00
private ConcurrentDictionary < uint , Archetype > archetypeDict = new ConcurrentDictionary < uint , Archetype > ( ) ;
private ConcurrentDictionary < uint , RpfFileEntry > textureLookup = new ConcurrentDictionary < uint , RpfFileEntry > ( ) ;
2019-01-06 02:04:33 +08:00
private Dictionary < MetaHash , MetaHash > textureParents ;
private Dictionary < MetaHash , MetaHash > hdtexturelookup ;
2017-09-21 18:33:05 +08:00
private object updateSyncRoot = new object ( ) ;
private object requestSyncRoot = new object ( ) ;
2023-10-28 03:31:09 +08:00
private ConcurrentDictionary < GameFileCacheKey , GameFile > projectFiles = new ConcurrentDictionary < GameFileCacheKey , GameFile > ( ) ; //for cache files loaded in project window: ydr,ydd,ytd,yft
private ConcurrentDictionary < uint , Archetype > projectArchetypes = new ConcurrentDictionary < uint , Archetype > ( ) ; //used to override archetypes in world view with project ones
2017-09-21 18:33:05 +08:00
//static indexes
public Dictionary < uint , RpfFileEntry > YdrDict { get ; private set ; }
public Dictionary < uint , RpfFileEntry > YddDict { get ; private set ; }
public Dictionary < uint , RpfFileEntry > YtdDict { get ; private set ; }
public Dictionary < uint , RpfFileEntry > YmapDict { get ; private set ; }
public Dictionary < uint , RpfFileEntry > YftDict { get ; private set ; }
public Dictionary < uint , RpfFileEntry > YbnDict { get ; private set ; }
public Dictionary < uint , RpfFileEntry > YcdDict { get ; private set ; }
2020-03-06 00:02:40 +08:00
public Dictionary < uint , RpfFileEntry > YedDict { get ; private set ; }
2017-09-21 18:33:05 +08:00
public Dictionary < uint , RpfFileEntry > YnvDict { get ; private set ; }
2019-11-25 17:44:16 +08:00
public Dictionary < uint , RpfFileEntry > Gxt2Dict { get ; private set ; }
2017-09-21 18:33:05 +08:00
public Dictionary < uint , RpfFileEntry > AllYmapsDict { get ; private set ; }
//static cached data loaded at init
2023-10-28 03:31:09 +08:00
public ConcurrentDictionary < uint , YtypFile > YtypDict { get ; set ; }
2017-09-21 18:33:05 +08:00
public List < CacheDatFile > AllCacheFiles { get ; set ; }
public Dictionary < uint , MapDataStoreNode > YmapHierarchyDict { get ; set ; }
public List < YmfFile > AllManifests { get ; set ; }
public bool EnableDlc { get ; set ; } = false ; //true;//
public bool EnableMods { get ; set ; } = false ;
public List < string > DlcPaths { get ; set ; } = new List < string > ( ) ;
public List < RpfFile > DlcActiveRpfs { get ; set ; } = new List < RpfFile > ( ) ;
public List < DlcSetupFile > DlcSetupFiles { get ; set ; } = new List < DlcSetupFile > ( ) ;
public List < DlcExtraFolderMountFile > DlcExtraFolderMounts { get ; set ; } = new List < DlcExtraFolderMountFile > ( ) ;
public Dictionary < string , string > DlcPatchedPaths { get ; set ; } = new Dictionary < string , string > ( ) ;
public List < string > DlcCacheFileList { get ; set ; } = new List < string > ( ) ;
public List < string > DlcNameList { get ; set ; } = new List < string > ( ) ;
public string SelectedDlc { get ; set ; } = string . Empty ;
public Dictionary < string , RpfFile > ActiveMapRpfFiles { get ; set ; } = new Dictionary < string , RpfFile > ( ) ;
public Dictionary < uint , World . TimecycleMod > TimeCycleModsDict = new Dictionary < uint , World . TimecycleMod > ( ) ;
2019-01-11 11:24:50 +08:00
public Dictionary < MetaHash , VehicleInitData > VehiclesInitDict { get ; set ; }
2019-11-06 01:53:20 +08:00
public Dictionary < MetaHash , CPedModelInfo__InitData > PedsInitDict { get ; set ; }
2019-11-07 00:51:35 +08:00
public Dictionary < MetaHash , PedFile > PedVariationsDict { get ; set ; }
public Dictionary < MetaHash , Dictionary < MetaHash , RpfFileEntry > > PedDrawableDicts { get ; set ; }
public Dictionary < MetaHash , Dictionary < MetaHash , RpfFileEntry > > PedTextureDicts { get ; set ; }
2019-11-29 17:47:11 +08:00
public Dictionary < MetaHash , Dictionary < MetaHash , RpfFileEntry > > PedClothDicts { get ; set ; }
2019-01-11 11:24:50 +08:00
2022-01-13 02:07:07 +08:00
public List < RelFile > AudioDatRelFiles = new List < RelFile > ( ) ;
public Dictionary < MetaHash , RelData > AudioConfigDict = new Dictionary < MetaHash , RelData > ( ) ;
public Dictionary < MetaHash , RelData > AudioSpeechDict = new Dictionary < MetaHash , RelData > ( ) ;
public Dictionary < MetaHash , RelData > AudioSynthsDict = new Dictionary < MetaHash , RelData > ( ) ;
public Dictionary < MetaHash , RelData > AudioMixersDict = new Dictionary < MetaHash , RelData > ( ) ;
public Dictionary < MetaHash , RelData > AudioCurvesDict = new Dictionary < MetaHash , RelData > ( ) ;
public Dictionary < MetaHash , RelData > AudioCategsDict = new Dictionary < MetaHash , RelData > ( ) ;
public Dictionary < MetaHash , RelData > AudioSoundsDict = new Dictionary < MetaHash , RelData > ( ) ;
public Dictionary < MetaHash , RelData > AudioGameDict = new Dictionary < MetaHash , RelData > ( ) ;
2017-09-21 18:33:05 +08:00
public List < RpfFile > BaseRpfs { get ; private set ; }
public List < RpfFile > AllRpfs { get ; private set ; }
public List < RpfFile > DlcRpfs { get ; private set ; }
public bool DoFullStringIndex = false ;
2019-01-11 11:24:50 +08:00
public bool BuildExtendedJenkIndex = true ;
public bool LoadArchetypes = true ;
2019-11-26 17:47:47 +08:00
public bool LoadVehicles = true ;
2019-11-25 22:26:28 +08:00
public bool LoadPeds = true ;
2022-01-13 02:07:07 +08:00
public bool LoadAudio = true ;
2023-10-28 03:31:09 +08:00
private bool PreloadedMode = true ;
2017-09-21 18:33:05 +08:00
2018-02-24 21:59:00 +08:00
private string GTAFolder ;
private string ExcludeFolders ;
2018-12-05 13:23:34 +08:00
public int QueueLength
{
get
{
return requestQueue . Count ;
}
}
public int ItemCount
{
get
{
return mainCache . Count ;
}
}
public long MemoryUsage
{
get
{
return mainCache . CurrentMemoryUsage ;
}
}
2018-02-24 21:59:00 +08:00
public GameFileCache ( long size , double cacheTime , string folder , string dlc , bool mods , string excludeFolders )
{
mainCache = new Cache < GameFileCacheKey , GameFile > ( size , cacheTime ) ; //2GB is good as default
SelectedDlc = dlc ;
EnableDlc = ! string . IsNullOrEmpty ( SelectedDlc ) ;
EnableMods = mods ;
GTAFolder = folder ;
ExcludeFolders = excludeFolders ;
}
2017-09-21 18:33:05 +08:00
public void Clear ( )
{
IsInited = false ;
mainCache . Clear ( ) ;
textureLookup . Clear ( ) ;
2019-01-06 02:04:33 +08:00
2023-10-28 03:31:09 +08:00
while ( requestQueue . TryDequeue ( out _ ) )
2017-09-21 18:33:05 +08:00
{ } //empty the old queue out...
}
2023-10-28 03:31:09 +08:00
public void SetGtaFolder ( string folder )
2017-09-21 18:33:05 +08:00
{
2023-10-28 03:31:09 +08:00
Clear ( ) ;
GTAFolder = folder ;
}
public void Init ( Action < string > updateStatus = null , Action < string > errorLog = null )
{
using var _ = new DisposableTimer ( "GameFileCache.Init" ) ;
if ( updateStatus ! = null ) UpdateStatus + = updateStatus ;
if ( errorLog ! = null ) ErrorLog + = errorLog ;
2017-09-21 18:33:05 +08:00
Clear ( ) ;
if ( RpfMan = = null )
{
2019-01-11 11:24:50 +08:00
//EnableDlc = !string.IsNullOrEmpty(SelectedDlc);
2017-09-21 18:33:05 +08:00
2023-10-28 03:31:09 +08:00
RpfMan = RpfManager . GetInstance ( ) ;
2017-09-21 18:33:05 +08:00
RpfMan . ExcludePaths = GetExcludePaths ( ) ;
RpfMan . EnableMods = EnableMods ;
2019-01-11 11:24:50 +08:00
RpfMan . BuildExtendedJenkIndex = BuildExtendedJenkIndex ;
2018-02-24 21:59:00 +08:00
RpfMan . Init ( GTAFolder , UpdateStatus , ErrorLog ) ; //, true);
2017-09-21 18:33:05 +08:00
InitGlobal ( ) ;
InitDlc ( ) ;
2019-01-27 14:14:10 +08:00
//RE test area!
//TestAudioRels();
2018-12-05 08:47:15 +08:00
//TestAudioYmts();
2020-02-06 02:33:12 +08:00
//TestAudioAwcs();
2018-03-05 17:37:51 +08:00
//TestMetas();
2018-12-13 23:14:14 +08:00
//TestPsos();
2019-12-30 13:37:29 +08:00
//TestRbfs();
2019-11-22 20:29:09 +08:00
//TestCuts();
2019-11-29 17:47:11 +08:00
//TestYlds();
2020-03-02 04:48:30 +08:00
//TestYeds();
2017-10-01 14:29:31 +08:00
//TestYcds();
2020-01-17 01:35:20 +08:00
//TestYtds();
2019-01-27 18:50:24 +08:00
//TestYbns();
2019-01-28 10:13:45 +08:00
//TestYdrs();
//TestYdds();
2019-01-28 15:10:25 +08:00
//TestYfts();
2019-01-28 21:29:59 +08:00
//TestYpts();
2021-04-17 04:33:23 +08:00
//TestYnvs();
2022-01-31 23:46:36 +08:00
//TestYvrs();
//TestYwrs();
2017-09-21 18:33:05 +08:00
//TestYmaps();
2022-02-24 06:28:47 +08:00
//TestYpdbs();
2023-06-16 22:50:22 +08:00
//TestYfds();
2021-06-12 06:23:15 +08:00
//TestMrfs();
2022-05-20 10:11:25 +08:00
//TestFxcs();
2017-09-21 18:33:05 +08:00
//TestPlacements();
//TestDrawables();
2022-03-29 20:32:29 +08:00
//TestCacheFiles();
2021-04-17 22:30:32 +08:00
//TestHeightmaps();
2021-04-21 04:26:32 +08:00
//TestWatermaps();
2021-04-07 14:52:32 +08:00
//GetShadersXml();
2017-09-21 18:33:05 +08:00
//GetArchetypeTimesList();
//string typestr = PsoTypes.GetTypesString();
}
else
{
GC . Collect ( ) ; //try free up some of the previously used memory..
}
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Scan complete" ) ;
2017-09-21 18:33:05 +08:00
IsInited = true ;
}
public void Init ( Action < string > updateStatus , Action < string > errorLog , List < RpfFile > allRpfs )
{
2023-10-28 03:31:09 +08:00
using var _ = new DisposableTimer ( "GameFileCache.Init" ) ;
if ( updateStatus ! = null )
{
UpdateStatus + = updateStatus ;
}
if ( errorLog ! = null )
{
ErrorLog + = errorLog ;
}
2017-09-21 18:33:05 +08:00
Clear ( ) ;
PreloadedMode = true ;
2019-01-09 09:47:03 +08:00
EnableDlc = true ; //just so everything (mainly archetypes) will load..
2017-09-21 18:33:05 +08:00
EnableMods = false ;
2023-10-28 03:31:09 +08:00
RpfMan ? ? = RpfManager . GetInstance ( ) ;
2017-09-21 18:33:05 +08:00
RpfMan . Init ( allRpfs ) ;
2023-10-28 03:31:09 +08:00
2017-09-21 18:33:05 +08:00
AllRpfs = allRpfs ;
BaseRpfs = allRpfs ;
DlcRpfs = new List < RpfFile > ( ) ;
2023-10-28 03:31:09 +08:00
Task . WhenAll (
Task . Run ( InitGlobalDicts ) ,
Task . Run ( InitManifestDicts ) ,
Task . Run ( InitGtxds ) ,
Task . Run ( InitArchetypeDicts ) ,
Task . Run ( InitStringDicts ) ,
Task . Run ( InitAudio )
) . GetAwaiter ( ) . GetResult ( ) ;
2022-01-13 02:07:07 +08:00
2017-09-21 18:33:05 +08:00
IsInited = true ;
}
private void InitGlobal ( )
{
2023-10-28 03:31:09 +08:00
using var _ = new DisposableTimer ( "InitGlobal" ) ;
2017-09-21 18:33:05 +08:00
BaseRpfs = GetModdedRpfList ( RpfMan . BaseRpfs ) ;
AllRpfs = GetModdedRpfList ( RpfMan . AllRpfs ) ;
DlcRpfs = GetModdedRpfList ( RpfMan . DlcRpfs ) ;
InitGlobalDicts ( ) ;
}
private void InitDlc ( )
{
InitDlcList ( ) ;
InitActiveMapRpfFiles ( ) ;
2023-10-28 03:31:09 +08:00
Task . WhenAll (
Task . Run ( InitMapDicts ) ,
Task . Run ( InitManifestDicts ) ,
Task . Run ( InitGtxds ) ,
Task . Run ( InitMapCaches ) ,
Task . Run ( InitArchetypeDicts ) ,
Task . Run ( InitStringDicts ) ,
Task . Run ( InitVehicles ) ,
Task . Run ( InitPeds ) ,
Task . Run ( InitAudio )
) . GetAwaiter ( ) . GetResult ( ) ;
2017-09-21 18:33:05 +08:00
}
private void InitDlcList ( )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Building DLC List..." ) ;
using var _ = new DisposableTimer ( "InitDlcList" ) ;
2017-09-21 18:33:05 +08:00
//if (!EnableDlc) return;
string dlclistpath = "update\\update.rpf\\common\\data\\dlclist.xml" ;
//if (!EnableDlc)
//{
// dlclistpath = "common.rpf\\data\\dlclist.xml";
//}
var dlclistxml = RpfMan . GetFileXml ( dlclistpath ) ;
DlcPaths . Clear ( ) ;
2018-03-03 21:03:08 +08:00
if ( ( dlclistxml = = null ) | | ( dlclistxml . DocumentElement = = null ) )
2017-09-21 18:33:05 +08:00
{
ErrorLog ( "InitDlcList: Couldn't load " + dlclistpath + "." ) ;
}
else
{
foreach ( XmlNode pathsnode in dlclistxml . DocumentElement )
{
foreach ( XmlNode itemnode in pathsnode . ChildNodes )
{
2017-12-20 07:52:50 +08:00
DlcPaths . Add ( itemnode . InnerText . ToLowerInvariant ( ) . Replace ( '\\' , '/' ) . Replace ( "platform:" , "x64" ) ) ;
2017-09-21 18:33:05 +08:00
}
}
}
//get dlc path names in the appropriate format for reference by the dlclist paths
2023-10-28 03:31:09 +08:00
Dictionary < string , RpfFile > dlcDict = new Dictionary < string , RpfFile > ( StringComparer . OrdinalIgnoreCase ) ;
Dictionary < string , RpfFile > dlcDict2 = new Dictionary < string , RpfFile > ( StringComparer . OrdinalIgnoreCase ) ;
2017-09-21 18:33:05 +08:00
foreach ( RpfFile dlcrpf in DlcRpfs )
{
if ( dlcrpf = = null ) continue ;
2023-10-28 03:31:09 +08:00
if ( dlcrpf . Name . Equals ( "dlc.rpf" , StringComparison . OrdinalIgnoreCase ) )
2017-09-21 18:33:05 +08:00
{
string path = GetDlcRpfVirtualPath ( dlcrpf . Path ) ;
string name = GetDlcNameFromPath ( dlcrpf . Path ) ;
dlcDict [ path ] = dlcrpf ;
dlcDict2 [ name ] = dlcrpf ;
}
}
//find all the paths for patched files in update.rpf and build the dict
DlcPatchedPaths . Clear ( ) ;
string updrpfpath = "update\\update.rpf" ;
var updrpffile = RpfMan . FindRpfFile ( updrpfpath ) ;
if ( updrpffile ! = null )
{
XmlDocument updsetupdoc = RpfMan . GetFileXml ( updrpfpath + "\\setup2.xml" ) ;
DlcSetupFile updsetupfile = new DlcSetupFile ( ) ;
updsetupfile . Load ( updsetupdoc ) ;
XmlDocument updcontentdoc = RpfMan . GetFileXml ( updrpfpath + "\\" + updsetupfile . datFile ) ;
DlcContentFile updcontentfile = new DlcContentFile ( ) ;
updcontentfile . Load ( updcontentdoc ) ;
updsetupfile . DlcFile = updrpffile ;
updsetupfile . ContentFile = updcontentfile ;
updcontentfile . DlcFile = updrpffile ;
updsetupfile . deviceName = "update" ;
updcontentfile . LoadDicts ( updsetupfile , RpfMan , this ) ;
if ( updcontentfile . ExtraTitleUpdates ! = null )
{
foreach ( var tumount in updcontentfile . ExtraTitleUpdates . Mounts )
{
2017-12-20 07:52:50 +08:00
var lpath = tumount . path . ToLowerInvariant ( ) ;
2017-09-21 18:33:05 +08:00
var relpath = lpath . Replace ( '/' , '\\' ) . Replace ( "update:\\" , "" ) ;
var dlcname = GetDlcNameFromPath ( relpath ) ;
RpfFile dlcfile ;
dlcDict2 . TryGetValue ( dlcname , out dlcfile ) ;
if ( dlcfile = = null )
{ continue ; }
var dlcpath = dlcfile . Path + "\\" ;
var files = updrpffile . GetFiles ( relpath , true ) ;
foreach ( var file in files )
{
if ( file = = null ) continue ;
var fpath = file . Path ;
var frelpath = fpath . Replace ( updrpfpath , "update:" ) . Replace ( '\\' , '/' ) . Replace ( lpath , dlcpath ) . Replace ( '/' , '\\' ) ;
2023-10-28 03:31:09 +08:00
if ( frelpath . StartsWith ( "mods\\" , StringComparison . OrdinalIgnoreCase ) )
2017-09-21 18:33:05 +08:00
{
frelpath = frelpath . Substring ( 5 ) ;
}
DlcPatchedPaths [ frelpath ] = fpath ;
}
}
}
}
else
{
ErrorLog ( "InitDlcList: update.rpf not found!" ) ;
}
DlcSetupFiles . Clear ( ) ;
DlcExtraFolderMounts . Clear ( ) ;
foreach ( string path in DlcPaths )
{
RpfFile dlcfile ;
if ( dlcDict . TryGetValue ( path , out dlcfile ) )
{
try
{
string setuppath = GetDlcPatchedPath ( dlcfile . Path + "\\setup2.xml" ) ;
XmlDocument setupdoc = RpfMan . GetFileXml ( setuppath ) ;
DlcSetupFile setupfile = new DlcSetupFile ( ) ;
setupfile . Load ( setupdoc ) ;
string contentpath = GetDlcPatchedPath ( dlcfile . Path + "\\" + setupfile . datFile ) ;
XmlDocument contentdoc = RpfMan . GetFileXml ( contentpath ) ;
DlcContentFile contentfile = new DlcContentFile ( ) ;
contentfile . Load ( contentdoc ) ;
setupfile . DlcFile = dlcfile ;
setupfile . ContentFile = contentfile ;
contentfile . DlcFile = dlcfile ;
contentfile . LoadDicts ( setupfile , RpfMan , this ) ;
foreach ( var extramount in contentfile . ExtraMounts . Values )
{
DlcExtraFolderMounts . Add ( extramount ) ;
}
DlcSetupFiles . Add ( setupfile ) ;
}
catch ( Exception ex )
{
ErrorLog ( "InitDlcList: Error processing DLC " + path + "\n" + ex . ToString ( ) ) ;
}
}
}
//load the DLC in the correct order....
DlcSetupFiles = DlcSetupFiles . OrderBy ( o = > o . order ) . ToList ( ) ;
DlcNameList . Clear ( ) ;
foreach ( var sfile in DlcSetupFiles )
{
if ( ( sfile = = null ) | | ( sfile . DlcFile = = null ) ) continue ;
2023-10-28 03:31:09 +08:00
DlcNameList . Add ( GetDlcNameFromPath ( sfile . DlcFile . Path ) . ToLowerInvariant ( ) ) ;
2017-09-21 18:33:05 +08:00
}
2019-01-11 11:24:50 +08:00
if ( DlcNameList . Count > 0 )
{
if ( string . IsNullOrEmpty ( SelectedDlc ) )
{
SelectedDlc = DlcNameList [ DlcNameList . Count - 1 ] ;
}
}
2017-09-21 18:33:05 +08:00
}
private void InitImagesMetas ( )
{
//currently not used..
////parse images.meta
//string imagesmetapath = "common.rpf\\data\\levels\\gta5\\images.meta";
//if (EnableDlc)
//{
// imagesmetapath = "update\\update.rpf\\common\\data\\levels\\gta5\\images.meta";
//}
//var imagesmetaxml = RpfMan.GetFileXml(imagesmetapath);
//var imagesnodes = imagesmetaxml.DocumentElement.ChildNodes;
//List<DlcContentDataFile> imagedatafilelist = new List<DlcContentDataFile>();
//Dictionary<string, DlcContentDataFile> imagedatafiles = new Dictionary<string, DlcContentDataFile>();
//foreach (XmlNode node in imagesnodes)
//{
// DlcContentDataFile datafile = new DlcContentDataFile(node);
// string fname = datafile.filename.ToLower();
// fname = fname.Replace('\\', '/');
// imagedatafiles[fname] = datafile;
// imagedatafilelist.Add(datafile);
//}
//filter ActiveMapFiles based on images.meta?
2019-12-30 13:37:29 +08:00
//DlcContentDataFile imagesdata;
//if (imagedatafiles.TryGetValue(path, out imagesdata))
//{
// ActiveMapRpfFiles[path] = baserpf;
//}
2017-09-21 18:33:05 +08:00
}
private void InitActiveMapRpfFiles ( )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Building active RPF dictionary..." ) ;
using var _ = new DisposableTimer ( "InitActiveMapRpfFiles" ) ;
2017-09-21 18:33:05 +08:00
ActiveMapRpfFiles . Clear ( ) ;
foreach ( RpfFile baserpf in BaseRpfs ) //start with all the base rpf's (eg x64a.rpf)
{
string path = baserpf . Path . Replace ( '\\' , '/' ) ;
if ( path = = "common.rpf" )
{
ActiveMapRpfFiles [ "common" ] = baserpf ;
}
else
{
int bsind = path . IndexOf ( '/' ) ;
if ( ( bsind > 0 ) & & ( bsind < path . Length ) )
{
path = "x64" + path . Substring ( bsind ) ;
//if (ActiveMapRpfFiles.ContainsKey(path))
//{ } //x64d.rpf\levels\gta5\generic\cutsobjects.rpf // x64g.rpf\levels\gta5\generic\cutsobjects.rpf - identical?
ActiveMapRpfFiles [ path ] = baserpf ;
}
else
{
//do we need to include root rpf files? generally don't seem to contain map data?
2019-01-11 15:15:25 +08:00
ActiveMapRpfFiles [ path ] = baserpf ;
2017-09-21 18:33:05 +08:00
}
}
}
if ( ! EnableDlc ) return ; //don't continue for base title only
2019-01-11 15:15:25 +08:00
foreach ( var rpf in DlcRpfs )
{
if ( rpf . NameLower = = "update.rpf" ) //include this so that files not in child rpf's can be used..
{
string path = rpf . Path . Replace ( '\\' , '/' ) ;
ActiveMapRpfFiles [ path ] = rpf ;
break ;
}
}
2017-09-21 18:33:05 +08:00
DlcActiveRpfs . Clear ( ) ;
DlcCacheFileList . Clear ( ) ;
//int maxdlcorder = 10000000;
Dictionary < string , List < string > > overlays = new Dictionary < string , List < string > > ( ) ;
2019-12-30 13:37:29 +08:00
foreach ( var setupfile in DlcSetupFiles )
{
if ( setupfile . DlcFile ! = null )
2017-09-21 18:33:05 +08:00
{
//if (setupfile.order > maxdlcorder)
// break;
var contentfile = setupfile . ContentFile ;
var dlcfile = setupfile . DlcFile ;
DlcActiveRpfs . Add ( dlcfile ) ;
2018-12-20 19:35:19 +08:00
for ( int i = 1 ; i < = setupfile . subPackCount ; i + + )
{
var subpackPath = dlcfile . Path . Replace ( "\\dlc.rpf" , "\\dlc" + i . ToString ( ) + ".rpf" ) ;
var subpack = RpfMan . FindRpfFile ( subpackPath ) ;
if ( subpack ! = null )
{
DlcActiveRpfs . Add ( subpack ) ;
if ( setupfile . DlcSubpacks = = null ) setupfile . DlcSubpacks = new List < RpfFile > ( ) ;
setupfile . DlcSubpacks . Add ( subpack ) ;
}
}
2017-09-21 18:33:05 +08:00
string dlcname = GetDlcNameFromPath ( dlcfile . Path ) ;
2023-10-28 03:31:09 +08:00
if ( ( dlcname = = "patchday27ng" ) & & ( ! SelectedDlc . Equals ( dlcname , StringComparison . OrdinalIgnoreCase ) ) )
2022-07-29 20:46:48 +08:00
{
continue ; //hack to fix map getting completely broken by this DLC.. but why? need to investigate further!
}
2017-09-21 18:33:05 +08:00
foreach ( var rpfkvp in contentfile . RpfDataFiles )
{
string umpath = GetDlcUnmountedPath ( rpfkvp . Value . filename ) ;
string phpath = GetDlcRpfPhysicalPath ( umpath , setupfile ) ;
//if (rpfkvp.Value.overlay)
AddDlcOverlayRpf ( rpfkvp . Key , umpath , setupfile , overlays ) ;
2018-12-20 19:35:19 +08:00
AddDlcActiveMapRpfFile ( rpfkvp . Key , phpath , setupfile ) ;
2017-09-21 18:33:05 +08:00
}
DlcExtraFolderMountFile extramount ;
DlcContentDataFile rpfdatafile ;
foreach ( var changeset in contentfile . contentChangeSets )
{
if ( changeset . useCacheLoader )
{
2017-12-20 07:52:50 +08:00
uint cachehash = JenkHash . GenHash ( changeset . changeSetName . ToLowerInvariant ( ) ) ;
2017-09-21 18:33:05 +08:00
string cachefilename = dlcname + "_" + cachehash . ToString ( ) + "_cache_y.dat" ;
string cachefilepath = dlcfile . Path + "\\x64\\data\\cacheloaderdata_dlc\\" + cachefilename ;
string cachefilepathpatched = GetDlcPatchedPath ( cachefilepath ) ;
DlcCacheFileList . Add ( cachefilepathpatched ) ;
//if ((changeset.mapChangeSetData != null) && (changeset.mapChangeSetData.Count > 0))
//{ }
//else
//{ }
}
else
{
//if ((changeset.mapChangeSetData != null) && (changeset.mapChangeSetData.Count > 0))
//{ }
//if (changeset.executionConditions != null)
//{ }
}
//if (changeset.filesToInvalidate != null)
//{ }//not used
//if (changeset.filesToDisable != null)
//{ }//not used
if ( changeset . filesToEnable ! = null )
{
foreach ( string file in changeset . filesToEnable )
{
2017-12-20 07:52:50 +08:00
string dfn = GetDlcPlatformPath ( file ) . ToLowerInvariant ( ) ;
2017-09-21 18:33:05 +08:00
if ( contentfile . ExtraMounts . TryGetValue ( dfn , out extramount ) )
{
//foreach (var rpfkvp in contentfile.RpfDataFiles)
//{
// string umpath = GetDlcUnmountedPath(rpfkvp.Value.filename);
// string phpath = GetDlcRpfPhysicalPath(umpath, setupfile);
// //if (rpfkvp.Value.overlay)
// AddDlcOverlayRpf(rpfkvp.Key, umpath, setupfile, overlays);
// AddDlcActiveMapRpfFile(rpfkvp.Key, phpath);
//}
}
else if ( contentfile . RpfDataFiles . TryGetValue ( dfn , out rpfdatafile ) )
{
string phpath = GetDlcRpfPhysicalPath ( rpfdatafile . filename , setupfile ) ;
2019-12-30 13:37:29 +08:00
2017-09-21 18:33:05 +08:00
//if (rpfdatafile.overlay)
AddDlcOverlayRpf ( dfn , rpfdatafile . filename , setupfile , overlays ) ;
2018-12-20 19:35:19 +08:00
AddDlcActiveMapRpfFile ( dfn , phpath , setupfile ) ;
2017-09-21 18:33:05 +08:00
}
else
{
if ( dfn . EndsWith ( ".rpf" ) )
{ }
}
}
}
if ( changeset . executionConditions ! = null )
{ }
if ( changeset . mapChangeSetData ! = null )
{
foreach ( var mapcs in changeset . mapChangeSetData )
{
//if (mapcs.mapChangeSetData != null)
//{ }//not used
if ( mapcs . filesToInvalidate ! = null )
{
foreach ( string file in mapcs . filesToInvalidate )
{
string upath = GetDlcMountedPath ( file ) ;
string fpath = GetDlcPlatformPath ( upath ) ;
if ( fpath . EndsWith ( ".rpf" ) )
{
RemoveDlcActiveMapRpfFile ( fpath , overlays ) ;
}
else
{ } //how to deal with individual files? milo_.interior
}
}
if ( mapcs . filesToDisable ! = null )
{ }
if ( mapcs . filesToEnable ! = null )
{
foreach ( string file in mapcs . filesToEnable )
{
string fpath = GetDlcPlatformPath ( file ) ;
string umpath = GetDlcUnmountedPath ( fpath ) ;
string phpath = GetDlcRpfPhysicalPath ( umpath , setupfile ) ;
if ( fpath ! = umpath )
{ }
AddDlcOverlayRpf ( fpath , umpath , setupfile , overlays ) ;
2018-12-20 19:35:19 +08:00
AddDlcActiveMapRpfFile ( fpath , phpath , setupfile ) ;
2017-09-21 18:33:05 +08:00
}
}
}
}
}
2023-10-28 03:31:09 +08:00
if ( dlcname . Equals ( SelectedDlc , StringComparison . OrdinalIgnoreCase ) )
2017-09-21 18:33:05 +08:00
{
break ; //everything's loaded up to the selected DLC.
}
}
}
}
2018-12-20 19:35:19 +08:00
private void AddDlcActiveMapRpfFile ( string vpath , string phpath , DlcSetupFile setupfile )
2017-09-21 18:33:05 +08:00
{
2017-12-20 07:52:50 +08:00
vpath = vpath . ToLowerInvariant ( ) ;
phpath = phpath . ToLowerInvariant ( ) ;
2017-09-21 18:33:05 +08:00
if ( phpath . EndsWith ( ".rpf" ) )
{
RpfFile rpffile = RpfMan . FindRpfFile ( phpath ) ;
if ( rpffile ! = null )
{
ActiveMapRpfFiles [ vpath ] = rpffile ;
}
else
{ }
}
else
{ } //how to handle individual files? eg interiorProxies.meta
}
2019-12-30 13:37:29 +08:00
private void AddDlcOverlayRpf ( string path , string umpath , DlcSetupFile setupfile , Dictionary < string , List < string > > overlays )
2017-09-21 18:33:05 +08:00
{
string opath = GetDlcOverlayPath ( umpath , setupfile ) ;
if ( opath = = path ) return ;
List < string > overlayList ;
if ( ! overlays . TryGetValue ( opath , out overlayList ) )
{
overlayList = new List < string > ( ) ;
overlays [ opath ] = overlayList ;
}
overlayList . Add ( path ) ;
}
private void RemoveDlcActiveMapRpfFile ( string vpath , Dictionary < string , List < string > > overlays )
{
List < string > overlayList ;
if ( overlays . TryGetValue ( vpath , out overlayList ) )
{
foreach ( string overlayPath in overlayList )
{
if ( ActiveMapRpfFiles . ContainsKey ( overlayPath ) )
{
ActiveMapRpfFiles . Remove ( overlayPath ) ;
}
else
{ }
}
overlays . Remove ( vpath ) ;
}
if ( ActiveMapRpfFiles . ContainsKey ( vpath ) )
{
ActiveMapRpfFiles . Remove ( vpath ) ;
}
else
{ } //nothing to remove?
}
private string GetDlcRpfPhysicalPath ( string path , DlcSetupFile setupfile )
{
2017-12-20 07:52:50 +08:00
string devname = setupfile . deviceName . ToLowerInvariant ( ) ;
string fpath = GetDlcPlatformPath ( path ) . ToLowerInvariant ( ) ;
2018-12-20 19:35:19 +08:00
string kpath = fpath ; //.Replace(devname + ":\\", "");
2017-09-21 18:33:05 +08:00
string dlcpath = setupfile . DlcFile . Path ;
fpath = fpath . Replace ( devname + ":" , dlcpath ) ;
fpath = fpath . Replace ( "x64:" , dlcpath + "\\x64" ) . Replace ( '/' , '\\' ) ;
2018-12-20 19:35:19 +08:00
if ( setupfile . DlcSubpacks ! = null )
{
if ( RpfMan . FindRpfFile ( fpath ) = = null )
{
foreach ( var subpack in setupfile . DlcSubpacks )
{
dlcpath = subpack . Path ;
var tpath = kpath . Replace ( devname + ":" , dlcpath ) ;
tpath = tpath . Replace ( "x64:" , dlcpath + "\\x64" ) . Replace ( '/' , '\\' ) ;
if ( RpfMan . FindRpfFile ( tpath ) ! = null )
{
return GetDlcPatchedPath ( tpath ) ;
}
}
}
}
2017-09-21 18:33:05 +08:00
return GetDlcPatchedPath ( fpath ) ;
}
private string GetDlcOverlayPath ( string path , DlcSetupFile setupfile )
{
2017-12-20 07:52:50 +08:00
string devname = setupfile . deviceName . ToLowerInvariant ( ) ;
string fpath = path . Replace ( "%PLATFORM%" , "x64" ) . Replace ( '\\' , '/' ) . ToLowerInvariant ( ) ;
2017-09-21 18:33:05 +08:00
string opath = fpath . Replace ( devname + ":/" , "" ) ;
return opath ;
}
private string GetDlcRpfVirtualPath ( string path )
{
path = path . Replace ( '\\' , '/' ) ;
2023-10-28 03:31:09 +08:00
if ( path . StartsWith ( "mods/" , StringComparison . OrdinalIgnoreCase ) )
2017-09-21 18:33:05 +08:00
{
path = path . Substring ( 5 ) ;
}
if ( path . Length > 7 )
{
path = path . Substring ( 0 , path . Length - 7 ) ; //trim off "dlc.rpf"
}
2023-10-28 03:31:09 +08:00
if ( path . StartsWith ( "x64" , StringComparison . OrdinalIgnoreCase ) )
2017-09-21 18:33:05 +08:00
{
int bsind = path . IndexOf ( '/' ) ; //replace x64*.rpf
if ( ( bsind > 0 ) & & ( bsind < path . Length ) )
{
path = "x64" + path . Substring ( bsind ) ;
}
else
{ } //no hits here
}
2023-10-28 03:31:09 +08:00
else if ( path . StartsWith ( "update/x64/dlcpacks" , StringComparison . OrdinalIgnoreCase ) )
2017-09-21 18:33:05 +08:00
{
path = path . Replace ( "update/x64/dlcpacks" , "dlcpacks:" ) ;
}
else
{ } //no hits here
return path ;
}
private string GetDlcNameFromPath ( string path )
{
2023-10-28 03:31:09 +08:00
string [ ] parts = path . Split ( '\\' ) ;
2017-09-21 18:33:05 +08:00
if ( parts . Length > 1 )
{
2023-10-28 03:31:09 +08:00
return parts [ parts . Length - 2 ] ;
2017-09-21 18:33:05 +08:00
}
return path ;
}
public static string GetDlcPlatformPath ( string path )
{
2017-12-20 07:52:50 +08:00
return path . Replace ( "%PLATFORM%" , "x64" ) . Replace ( '\\' , '/' ) . Replace ( "platform:" , "x64" ) . ToLowerInvariant ( ) ;
2017-09-21 18:33:05 +08:00
}
private string GetDlcMountedPath ( string path )
{
foreach ( var efm in DlcExtraFolderMounts )
{
foreach ( var fm in efm . FolderMounts )
{
if ( ( fm . platform = = null ) | | ( fm . platform = = "x64" ) )
{
if ( path . StartsWith ( fm . path ) )
{
path = path . Replace ( fm . path , fm . mountAs ) ;
}
}
}
}
return path ;
}
private string GetDlcUnmountedPath ( string path )
{
foreach ( var efm in DlcExtraFolderMounts )
{
foreach ( var fm in efm . FolderMounts )
{
if ( ( fm . platform = = null ) | | ( fm . platform = = "x64" ) )
{
if ( path . StartsWith ( fm . mountAs ) )
{
path = path . Replace ( fm . mountAs , fm . path ) ;
}
}
}
}
return path ;
}
public string GetDlcPatchedPath ( string path )
{
string p ;
if ( DlcPatchedPaths . TryGetValue ( path , out p ) )
{
return p ;
}
return path ;
}
private List < RpfFile > GetModdedRpfList ( List < RpfFile > list )
{
//if (!EnableMods) return new List<RpfFile>(list);
List < RpfFile > rlist = new List < RpfFile > ( ) ;
RpfFile f ;
if ( ! EnableMods )
{
foreach ( var file in list )
{
if ( ! file . Path . StartsWith ( "mods" ) )
{
rlist . Add ( file ) ;
}
}
}
else
{
foreach ( var file in list )
{
if ( RpfMan . ModRpfDict . TryGetValue ( file . Path , out f ) )
{
rlist . Add ( f ) ;
}
else
{
if ( file . Path . StartsWith ( "mods" ) )
{
var basepath = file . Path . Substring ( 5 ) ;
if ( ! RpfMan . RpfDict . ContainsKey ( basepath ) ) //this file isn't overriding anything
{
rlist . Add ( file ) ;
}
}
else
{
rlist . Add ( file ) ;
}
}
}
}
return rlist ;
}
private void InitGlobalDicts ( )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Building global dictionaries..." ) ;
using var timer = new DisposableTimer ( "InitGlobalDicts" ) ;
YdrDict = new Dictionary < uint , RpfFileEntry > ( 80000 ) ;
YddDict = new Dictionary < uint , RpfFileEntry > ( 11000 ) ;
YtdDict = new Dictionary < uint , RpfFileEntry > ( 40000 ) ;
YftDict = new Dictionary < uint , RpfFileEntry > ( 40000 ) ;
YcdDict = new Dictionary < uint , RpfFileEntry > ( 20000 ) ;
YedDict = new Dictionary < uint , RpfFileEntry > ( 300 ) ;
2017-09-21 18:33:05 +08:00
foreach ( var rpffile in AllRpfs )
{
if ( rpffile . AllEntries = = null ) continue ;
foreach ( var entry in rpffile . AllEntries )
{
if ( entry is RpfFileEntry )
{
RpfFileEntry fentry = entry as RpfFileEntry ;
if ( entry . NameLower . EndsWith ( ".ydr" ) )
{
YdrDict [ entry . ShortNameHash ] = fentry ;
}
else if ( entry . NameLower . EndsWith ( ".ydd" ) )
{
YddDict [ entry . ShortNameHash ] = fentry ;
}
else if ( entry . NameLower . EndsWith ( ".ytd" ) )
{
YtdDict [ entry . ShortNameHash ] = fentry ;
}
else if ( entry . NameLower . EndsWith ( ".yft" ) )
{
YftDict [ entry . ShortNameHash ] = fentry ;
}
else if ( entry . NameLower . EndsWith ( ".ycd" ) )
{
YcdDict [ entry . ShortNameHash ] = fentry ;
}
2020-03-06 00:02:40 +08:00
else if ( entry . NameLower . EndsWith ( ".yed" ) )
{
YedDict [ entry . ShortNameHash ] = fentry ;
}
2017-09-21 18:33:05 +08:00
}
}
}
2023-10-28 03:31:09 +08:00
Console . WriteLine ( $"YdrDict: {YdrDict.Count}; YddDict: {YddDict.Count}; YtdDict: {YtdDict.Count}; YftDict: {YftDict.Count}; YcdDict: {YcdDict.Count}; YedDict: {YedDict.Count}" ) ;
2017-09-21 18:33:05 +08:00
}
private void InitMapDicts ( )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Building map dictionaries..." ) ;
using var _ = new DisposableTimer ( "InitMapDicts" ) ;
2017-09-21 18:33:05 +08:00
YmapDict = new Dictionary < uint , RpfFileEntry > ( ) ;
YbnDict = new Dictionary < uint , RpfFileEntry > ( ) ;
YnvDict = new Dictionary < uint , RpfFileEntry > ( ) ;
foreach ( var rpffile in ActiveMapRpfFiles . Values ) //RpfMan.BaseRpfs)
{
if ( rpffile . AllEntries = = null ) continue ;
foreach ( var entry in rpffile . AllEntries )
{
if ( entry is RpfFileEntry )
{
RpfFileEntry fentry = entry as RpfFileEntry ;
if ( entry . NameLower . EndsWith ( ".ymap" ) )
{
//YmapDict[entry.NameHash] = fentry;
YmapDict [ entry . ShortNameHash ] = fentry ;
}
else if ( entry . NameLower . EndsWith ( ".ybn" ) )
{
//YbnDict[entry.NameHash] = fentry;
YbnDict [ entry . ShortNameHash ] = fentry ;
}
else if ( entry . NameLower . EndsWith ( ".ynv" ) )
{
YnvDict [ entry . ShortNameHash ] = fentry ;
}
}
}
}
AllYmapsDict = new Dictionary < uint , RpfFileEntry > ( ) ;
foreach ( var rpffile in AllRpfs )
{
if ( rpffile . AllEntries = = null ) continue ;
foreach ( var entry in rpffile . AllEntries )
{
if ( entry is RpfFileEntry )
{
RpfFileEntry fentry = entry as RpfFileEntry ;
if ( entry . NameLower . EndsWith ( ".ymap" ) )
{
AllYmapsDict [ entry . ShortNameHash ] = fentry ;
}
}
}
}
}
private void InitManifestDicts ( )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Loading manifests..." ) ;
using var _ = new DisposableTimer ( "InitManifestDicts" ) ;
2017-09-21 18:33:05 +08:00
AllManifests = new List < YmfFile > ( ) ;
2019-01-06 02:04:33 +08:00
hdtexturelookup = new Dictionary < MetaHash , MetaHash > ( ) ;
2023-10-28 03:31:09 +08:00
IEnumerable < RpfFile > rpfs = PreloadedMode ? AllRpfs : ActiveMapRpfFiles . Values ;
2019-01-09 09:15:38 +08:00
foreach ( RpfFile file in rpfs )
2017-09-21 18:33:05 +08:00
{
if ( file . AllEntries = = null ) continue ;
//manifest and meta parsing..
foreach ( RpfEntry entry in file . AllEntries )
{
//sp_manifest.ymt
//if (entry.NameLower.EndsWith("zonebind.ymt")/* || entry.Name.EndsWith("vinewood.ymt")*/)
//{
// YmtFile ymt = GetFile<YmtFile>(entry);
//}
if ( entry . Name . EndsWith ( ".ymf" ) ) // || entry.Name.EndsWith(".ymt"))
{
2019-03-20 18:21:47 +08:00
try
2017-09-21 18:33:05 +08:00
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( string . Format ( entry . Path ) ) ;
2019-03-20 18:21:47 +08:00
YmfFile ymffile = RpfMan . GetFile < YmfFile > ( entry ) ;
if ( ymffile ! = null )
{
AllManifests . Add ( ymffile ) ;
2017-09-21 18:33:05 +08:00
2019-03-20 18:21:47 +08:00
if ( ymffile . Pso ! = null )
{ }
else if ( ymffile . Rbf ! = null )
{ }
else if ( ymffile . Meta ! = null )
{ }
else
{ }
2019-01-06 02:04:33 +08:00
2019-03-20 18:21:47 +08:00
if ( ymffile . HDTxdAssetBindings ! = null )
2019-01-06 02:04:33 +08:00
{
2019-03-20 18:21:47 +08:00
for ( int i = 0 ; i < ymffile . HDTxdAssetBindings . Length ; i + + )
{
var b = ymffile . HDTxdAssetBindings [ i ] ;
var targetasset = JenkHash . GenHash ( b . targetAsset . ToString ( ) . ToLowerInvariant ( ) ) ;
var hdtxd = JenkHash . GenHash ( b . HDTxd . ToString ( ) . ToLowerInvariant ( ) ) ;
hdtexturelookup [ targetasset ] = hdtxd ;
}
2019-01-06 02:04:33 +08:00
}
2019-03-20 18:21:47 +08:00
}
}
catch ( Exception ex )
{
string errstr = entry . Path + "\n" + ex . ToString ( ) ;
ErrorLog ( errstr ) ;
2017-09-21 18:33:05 +08:00
}
}
}
}
}
private void InitGtxds ( )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Loading global texture list..." ) ;
using var timer = new DisposableTimer ( "InitGtxds" ) ;
2019-01-06 02:04:33 +08:00
var parentTxds = new Dictionary < MetaHash , MetaHash > ( ) ;
2017-09-21 18:33:05 +08:00
IEnumerable < RpfFile > rpfs = PreloadedMode ? AllRpfs : ( IEnumerable < RpfFile > ) ActiveMapRpfFiles . Values ;
2019-12-30 13:37:29 +08:00
var addTxdRelationships = new Action < Dictionary < string , string > > ( ( from ) = >
2017-09-21 18:33:05 +08:00
{
2019-01-06 02:04:33 +08:00
foreach ( var kvp in from )
2017-09-21 18:33:05 +08:00
{
2019-01-06 02:04:33 +08:00
uint chash = JenkHash . GenHash ( kvp . Key . ToLowerInvariant ( ) ) ;
uint phash = JenkHash . GenHash ( kvp . Value . ToLowerInvariant ( ) ) ;
if ( ! parentTxds . ContainsKey ( chash ) )
2017-09-21 18:33:05 +08:00
{
2019-01-06 02:04:33 +08:00
parentTxds . Add ( chash , phash ) ;
2017-09-21 18:33:05 +08:00
}
2019-01-06 02:04:33 +08:00
else
2017-09-21 18:33:05 +08:00
{
}
}
2019-01-06 02:04:33 +08:00
} ) ;
2017-09-21 18:33:05 +08:00
2019-01-06 02:04:33 +08:00
var addRpfTxdRelationships = new Action < IEnumerable < RpfFile > > ( ( from ) = >
2017-09-21 18:33:05 +08:00
{
2019-01-06 02:04:33 +08:00
foreach ( RpfFile file in from )
2018-01-04 01:29:35 +08:00
{
2019-01-06 02:04:33 +08:00
if ( file . AllEntries = = null ) continue ;
foreach ( RpfEntry entry in file . AllEntries )
2018-01-04 01:29:35 +08:00
{
try
{
2020-12-29 20:08:21 +08:00
if ( ( entry . NameLower = = "gtxd.ymt" ) | | ( entry . NameLower = = "gtxd.meta" ) | | ( entry . NameLower = = "mph4_gtxd.ymt" ) )
2018-01-04 01:29:35 +08:00
{
GtxdFile ymt = RpfMan . GetFile < GtxdFile > ( entry ) ;
2019-01-06 02:04:33 +08:00
if ( ymt . TxdRelationships ! = null )
2018-01-04 01:29:35 +08:00
{
2019-01-06 02:04:33 +08:00
addTxdRelationships ( ymt . TxdRelationships ) ;
}
}
else if ( entry . NameLower = = "vehicles.meta" )
{
2019-01-11 11:24:50 +08:00
VehiclesFile vf = RpfMan . GetFile < VehiclesFile > ( entry ) ; //could also get loaded in InitVehicles...
2019-01-06 02:04:33 +08:00
if ( vf . TxdRelationships ! = null )
{
addTxdRelationships ( vf . TxdRelationships ) ;
2018-01-04 01:29:35 +08:00
}
}
}
catch ( Exception ex )
{
string errstr = entry . Path + "\n" + ex . ToString ( ) ;
ErrorLog ( errstr ) ;
}
}
}
2019-01-06 02:04:33 +08:00
} ) ;
addRpfTxdRelationships ( rpfs ) ;
if ( EnableDlc )
{
addRpfTxdRelationships ( DlcActiveRpfs ) ;
2017-09-21 18:33:05 +08:00
}
textureParents = parentTxds ;
2019-01-06 02:04:33 +08:00
//ensure resident global texture dicts:
2017-09-21 18:33:05 +08:00
YtdFile ytd1 = new YtdFile ( GetYtdEntry ( JenkHash . GenHash ( "mapdetail" ) ) ) ;
LoadFile ( ytd1 ) ;
AddTextureLookups ( ytd1 ) ;
YtdFile ytd2 = new YtdFile ( GetYtdEntry ( JenkHash . GenHash ( "vehshare" ) ) ) ;
LoadFile ( ytd2 ) ;
AddTextureLookups ( ytd2 ) ;
}
private void InitMapCaches ( )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Loading cache..." ) ;
using var _ = new DisposableTimer ( "InitMapCaches" ) ;
2017-09-21 18:33:05 +08:00
AllCacheFiles = new List < CacheDatFile > ( ) ;
YmapHierarchyDict = new Dictionary < uint , MapDataStoreNode > ( ) ;
2022-04-27 06:37:34 +08:00
CacheDatFile loadCacheFile ( string path , bool finalAttempt )
2017-09-21 18:33:05 +08:00
{
2022-04-27 06:37:34 +08:00
try
2017-09-21 18:33:05 +08:00
{
2022-04-27 06:37:34 +08:00
var cache = RpfMan . GetFile < CacheDatFile > ( path ) ;
if ( cache ! = null )
2017-09-21 18:33:05 +08:00
{
2022-04-27 06:37:34 +08:00
AllCacheFiles . Add ( cache ) ;
foreach ( var node in cache . AllMapNodes )
2017-09-21 18:33:05 +08:00
{
if ( YmapDict . ContainsKey ( node . Name ) )
{
YmapHierarchyDict [ node . Name ] = node ;
}
else
{ } //ymap not found...
}
}
2022-04-27 06:37:34 +08:00
else if ( finalAttempt )
2017-09-21 18:33:05 +08:00
{
2022-04-27 06:37:34 +08:00
ErrorLog ( path + ": main cachefile not loaded! Possibly an unsupported GTAV installation version." ) ;
2017-09-21 18:33:05 +08:00
}
2022-04-27 06:37:34 +08:00
else //update\x64\dlcpacks\mpspecialraces\dlc.rpf\x64\data\cacheloaderdata_dlc\mpspecialraces_3336915258_cache_y.dat (hash of: mpspecialraces_interior_additions)
{ }
return cache ;
}
catch ( Exception ex )
{
ErrorLog ( path + ": " + ex . ToString ( ) ) ;
2017-09-21 18:33:05 +08:00
}
2022-04-27 06:37:34 +08:00
return null ;
}
2017-09-21 18:33:05 +08:00
2022-04-27 06:37:34 +08:00
CacheDatFile maincache = null ;
if ( EnableDlc )
{
maincache = loadCacheFile ( "update\\update.rpf\\common\\data\\gta5_cache_y.dat" , false ) ;
if ( maincache = = null )
{
maincache = loadCacheFile ( "update\\update2.rpf\\common\\data\\gta5_cache_y.dat" , true ) ;
}
}
else
{
maincache = loadCacheFile ( "common.rpf\\data\\gta5_cache_y.dat" , true ) ;
2017-09-21 18:33:05 +08:00
}
2022-04-27 06:37:34 +08:00
if ( EnableDlc )
{
foreach ( string dlccachefile in DlcCacheFileList )
{
loadCacheFile ( dlccachefile , false ) ;
}
}
2017-09-21 18:33:05 +08:00
}
private void InitArchetypeDicts ( )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Loading archetypes..." ) ;
YtypDict = new ConcurrentDictionary < uint , YtypFile > ( ) ;
2017-09-21 18:33:05 +08:00
archetypesLoaded = false ;
archetypeDict . Clear ( ) ;
2019-01-11 11:24:50 +08:00
if ( ! LoadArchetypes ) return ;
2023-10-28 03:31:09 +08:00
using var timer = new DisposableTimer ( "InitArchetypeDicts" ) ;
2017-09-21 18:33:05 +08:00
var rpfs = EnableDlc ? AllRpfs : BaseRpfs ;
2023-10-28 03:31:09 +08:00
var allYtypes = rpfs
. Where ( p = > p . AllEntries ! = null & & ( EnableDlc | | ! p . Path . StartsWith ( "update" ) ) )
. SelectMany ( p = > p . AllEntries . Where ( p = > p . NameLower . EndsWith ( ".ytyp" ) ) ) ;
2017-09-21 18:33:05 +08:00
2023-10-28 03:31:09 +08:00
Parallel . ForEach ( allYtypes , new ParallelOptions { MaxDegreeOfParallelism = 4 } , ( entry ) = >
{
try
2017-09-21 18:33:05 +08:00
{
2023-10-28 03:31:09 +08:00
AddYtypToDictionary ( entry ) ;
2017-09-21 18:33:05 +08:00
}
2023-10-28 03:31:09 +08:00
catch ( Exception ex )
{
ErrorLog ( entry . Path + ": " + ex . ToString ( ) ) ;
}
} ) ;
2017-09-21 18:33:05 +08:00
archetypesLoaded = true ;
}
private void AddYtypToDictionary ( RpfEntry entry )
{
2023-10-28 03:31:09 +08:00
//UpdateStatus?.Invoke(string.Format(entry.Path));
2017-09-21 18:33:05 +08:00
YtypFile ytypfile = RpfMan . GetFile < YtypFile > ( entry ) ;
if ( ytypfile = = null )
{
throw new Exception ( "Couldn't load ytyp file." ) ; //couldn't load the file for some reason... shouldn't happen..
}
if ( ytypfile . Meta = = null )
{
2023-10-28 03:31:09 +08:00
if ( ytypfile . Pso = = null & & ytypfile . Rbf = = null )
{
throw new Exception ( "ytyp file was not in meta format." ) ;
}
return ;
2017-09-21 18:33:05 +08:00
}
2023-10-28 03:31:09 +08:00
YtypDict [ ytypfile . NameHash ] = ytypfile ;
//if (YtypDict.ContainsKey(ytypfile.NameHash))
//{
// //throw new Exception("ytyp " + JenkIndex.GetString(ytypfile.NameHash) + " already loaded.");
// //errorAction(entry.Path + ": ytyp " + JenkIndex.GetString(ytypfile.NameHash) + " already loaded.");
// YtypDict[ytypfile.NameHash] = ytypfile; //override ytyp and continue anyway, could be unique archetypes in here still...
//}
//else
//{
// YtypDict.Add(ytypfile.NameHash, ytypfile);
//}
2017-09-21 18:33:05 +08:00
if ( ( ytypfile . AllArchetypes = = null ) | | ( ytypfile . AllArchetypes . Length = = 0 ) )
{
ErrorLog ( entry . Path + ": no archetypes found" ) ;
}
else
{
foreach ( var arch in ytypfile . AllArchetypes )
{
uint hash = arch . Hash ;
if ( hash = = 0 ) continue ;
archetypeDict [ hash ] = arch ;
}
}
////if (ytypfile.AudioEmitters != null)
////{
//// foreach (CExtensionDefAudioEmitter emitter in ytypfile.AudioEmitters)
//// {
//// //audioind++;
//// //uint hash = emitter.name;
//// //if (hash == 0) hash = archetype.name;
//// //if (hash == 0)
//// // continue;
//// //if (AudioArchetypes.ContainsKey(hash))
//// //{
//// // var oldval = AudioArchetypes[hash];
//// // //errorAction(entry.Path + ": " + emitter.ToString() + ": (CTimeArchetypeDef) Already in archetype dict. Was in: " + oldval.ToString());
//// // //overwrite with new definition? how to tell?
//// // AudioArchetypes[hash] = new Tuple<YtypFile, int>(ytypfile, audioind);
//// //}
//// //else
//// //{
//// // AudioArchetypes.Add(hash, new Tuple<YtypFile, int>(ytypfile, audioind));
//// //}
//// }
////}
}
public void InitStringDicts ( )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Loading strings..." ) ;
using var timer = new DisposableTimer ( "InitStringDicts" ) ;
2017-09-21 18:33:05 +08:00
string langstr = "american_rel" ; //todo: make this variable?
2019-01-13 14:04:32 +08:00
string langstr2 = "americandlc.rpf" ;
string langstr3 = "american.rpf" ;
2017-09-21 18:33:05 +08:00
2019-11-25 17:44:16 +08:00
Gxt2Dict = new Dictionary < uint , RpfFileEntry > ( ) ;
2019-11-26 17:47:47 +08:00
var gxt2files = new List < Gxt2File > ( ) ;
2019-11-25 17:44:16 +08:00
foreach ( var rpf in AllRpfs )
{
foreach ( var entry in rpf . AllEntries )
{
if ( entry is RpfFileEntry fentry )
{
var p = entry . Path ;
if ( entry . NameLower . EndsWith ( ".gxt2" ) & & ( p . Contains ( langstr ) | | p . Contains ( langstr2 ) | | p . Contains ( langstr3 ) ) )
{
Gxt2Dict [ entry . ShortNameHash ] = fentry ;
2019-11-26 17:47:47 +08:00
if ( DoFullStringIndex )
{
var gxt2 = RpfMan . GetFile < Gxt2File > ( entry ) ;
if ( gxt2 ! = null )
{
for ( int i = 0 ; i < gxt2 . TextEntries . Length ; i + + )
{
var e = gxt2 . TextEntries [ i ] ;
GlobalText . Ensure ( e . Text , e . Hash ) ;
}
gxt2files . Add ( gxt2 ) ;
}
}
2019-11-25 17:44:16 +08:00
}
}
}
}
2017-09-21 18:33:05 +08:00
if ( ! DoFullStringIndex )
{
string globalgxt2path = "x64b.rpf\\data\\lang\\" + langstr + ".rpf\\global.gxt2" ;
var globalgxt2 = RpfMan . GetFile < Gxt2File > ( globalgxt2path ) ;
if ( globalgxt2 ! = null )
{
for ( int i = 0 ; i < globalgxt2 . TextEntries . Length ; i + + )
{
var e = globalgxt2 . TextEntries [ i ] ;
GlobalText . Ensure ( e . Text , e . Hash ) ;
}
}
return ;
}
GlobalText . FullIndexBuilt = true ;
foreach ( var rpf in AllRpfs )
{
foreach ( var entry in rpf . AllEntries )
{
if ( entry . NameLower . EndsWith ( "statssetup.xml" ) )
{
var xml = RpfMan . GetFileXml ( entry . Path ) ;
if ( xml = = null )
{ continue ; }
var statnodes = xml . SelectNodes ( "StatsSetup/stats/stat" ) ;
foreach ( XmlNode statnode in statnodes )
{
if ( statnode = = null )
{ continue ; }
var statname = Xml . GetStringAttribute ( statnode , "Name" ) ;
if ( string . IsNullOrEmpty ( statname ) )
{ continue ; }
2017-12-20 07:52:50 +08:00
var statnamel = statname . ToLowerInvariant ( ) ;
2017-09-21 18:33:05 +08:00
StatsNames . Ensure ( statname ) ;
StatsNames . Ensure ( statnamel ) ;
StatsNames . Ensure ( "sp_" + statnamel ) ;
StatsNames . Ensure ( "mp0_" + statnamel ) ;
StatsNames . Ensure ( "mp1_" + statnamel ) ;
}
}
}
}
StatsNames . FullIndexBuilt = true ;
}
2019-01-11 11:24:50 +08:00
public void InitVehicles ( )
{
if ( ! LoadVehicles ) return ;
//Neos7
//Involved files(at least for rendering purpose )
//Vehicles.meta
//Carcols.meta
//Carvariations.meta
//Vehiclelayouts.meta
//The other metas shouldn't be important for rendering
//Then the global carcols.ymt is required too
//As it contains the general shared tuning options
//Carcols for modkits and lights kits definitions
//Carvariations links such modkits and lights kits to each vehicle plus defines colours combinations of spawned vehicles
//Vehiclelayouts mostly to handle ped interactions with the vehicle
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Loading vehicles..." ) ;
using var _ = new DisposableTimer ( "InitVehicles" ) ;
2019-01-11 11:24:50 +08:00
2019-12-30 13:37:29 +08:00
IEnumerable < RpfFile > rpfs = PreloadedMode ? AllRpfs : ( IEnumerable < RpfFile > ) ActiveMapRpfFiles . Values ;
2019-01-11 11:24:50 +08:00
var allVehicles = new Dictionary < MetaHash , VehicleInitData > ( ) ;
2019-01-11 15:15:25 +08:00
var allCarCols = new List < CarColsFile > ( ) ;
var allCarModCols = new List < CarModColsFile > ( ) ;
var allCarVariations = new List < CarVariationsFile > ( ) ;
2019-01-12 10:49:31 +08:00
var allCarVariationsDict = new Dictionary < MetaHash , CVehicleModelInfoVariation_418053801 > ( ) ;
2019-01-11 15:15:25 +08:00
var allVehicleLayouts = new List < VehicleLayoutsFile > ( ) ;
2019-01-11 11:24:50 +08:00
var addVehicleFiles = new Action < IEnumerable < RpfFile > > ( ( from ) = >
{
foreach ( RpfFile file in from )
{
if ( file . AllEntries = = null ) continue ;
foreach ( RpfEntry entry in file . AllEntries )
{
#if ! DEBUG
try
#endif
{
if ( entry . NameLower = = "vehicles.meta" )
{
VehiclesFile vf = RpfMan . GetFile < VehiclesFile > ( entry ) ;
if ( vf . InitDatas ! = null )
{
foreach ( var initData in vf . InitDatas )
{
var name = initData . modelName . ToLowerInvariant ( ) ;
var hash = JenkHash . GenHash ( name ) ;
if ( allVehicles . ContainsKey ( hash ) )
{ }
allVehicles [ hash ] = initData ;
}
}
}
if ( ( entry . NameLower = = "carcols.ymt" ) | | ( entry . NameLower = = "carcols.meta" ) )
{
var cf = RpfMan . GetFile < CarColsFile > ( entry ) ;
2019-01-11 15:15:25 +08:00
if ( cf . VehicleModelInfo ! = null )
2019-01-11 16:56:57 +08:00
{ }
2019-01-11 15:15:25 +08:00
allCarCols . Add ( cf ) ;
2019-01-11 11:24:50 +08:00
}
if ( entry . NameLower = = "carmodcols.ymt" )
{
var cf = RpfMan . GetFile < CarModColsFile > ( entry ) ;
2019-01-11 16:56:57 +08:00
if ( cf . VehicleModColours ! = null )
{ }
2019-01-11 15:15:25 +08:00
allCarModCols . Add ( cf ) ;
2019-01-11 11:24:50 +08:00
}
if ( ( entry . NameLower = = "carvariations.ymt" ) | | ( entry . NameLower = = "carvariations.meta" ) )
{
var cf = RpfMan . GetFile < CarVariationsFile > ( entry ) ;
2019-01-12 10:49:31 +08:00
if ( cf . VehicleModelInfo ? . variationData ! = null )
{
foreach ( var variation in cf . VehicleModelInfo . variationData )
{
var name = variation . modelName . ToLowerInvariant ( ) ;
var hash = JenkHash . GenHash ( name ) ;
allCarVariationsDict [ hash ] = variation ;
}
}
2019-01-11 15:15:25 +08:00
allCarVariations . Add ( cf ) ;
2019-01-11 11:24:50 +08:00
}
if ( entry . NameLower . StartsWith ( "vehiclelayouts" ) & & entry . NameLower . EndsWith ( ".meta" ) )
{
var lf = RpfMan . GetFile < VehicleLayoutsFile > ( entry ) ;
2019-01-11 17:40:13 +08:00
if ( lf . Xml ! = null )
{ }
2019-01-11 15:15:25 +08:00
allVehicleLayouts . Add ( lf ) ;
2019-01-11 11:24:50 +08:00
}
}
#if ! DEBUG
catch ( Exception ex )
{
string errstr = entry . Path + "\n" + ex . ToString ( ) ;
ErrorLog ( errstr ) ;
}
#endif
}
}
} ) ;
addVehicleFiles ( rpfs ) ;
if ( EnableDlc )
{
addVehicleFiles ( DlcActiveRpfs ) ;
}
2023-10-28 03:31:09 +08:00
Console . WriteLine ( $"allVehicles: {allVehicles.Count()}" ) ;
2019-01-11 11:24:50 +08:00
VehiclesInitDict = allVehicles ;
}
2017-09-21 18:33:05 +08:00
2019-11-06 01:53:20 +08:00
public void InitPeds ( )
{
if ( ! LoadPeds ) return ;
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Loading peds..." ) ;
using var _ = new DisposableTimer ( "InitPeds" ) ;
2019-11-06 01:53:20 +08:00
IEnumerable < RpfFile > rpfs = PreloadedMode ? AllRpfs : ( IEnumerable < RpfFile > ) ActiveMapRpfFiles . Values ;
2019-11-07 00:51:35 +08:00
List < RpfFile > dlcrpfs = new List < RpfFile > ( ) ;
if ( EnableDlc )
{
foreach ( var rpf in DlcActiveRpfs )
{
dlcrpfs . Add ( rpf ) ;
if ( rpf . Children = = null ) continue ;
foreach ( var crpf in rpf . Children )
{
dlcrpfs . Add ( crpf ) ;
if ( crpf . Children ? . Count > 0 )
{ }
}
}
}
2019-11-06 01:53:20 +08:00
var allPeds = new Dictionary < MetaHash , CPedModelInfo__InitData > ( ) ;
var allPedsFiles = new List < PedsFile > ( ) ;
2019-11-07 00:51:35 +08:00
var allPedYmts = new Dictionary < MetaHash , PedFile > ( ) ;
var allPedDrwDicts = new Dictionary < MetaHash , Dictionary < MetaHash , RpfFileEntry > > ( ) ;
var allPedTexDicts = new Dictionary < MetaHash , Dictionary < MetaHash , RpfFileEntry > > ( ) ;
2019-11-29 17:47:11 +08:00
var allPedClothDicts = new Dictionary < MetaHash , Dictionary < MetaHash , RpfFileEntry > > ( ) ;
2019-11-07 00:51:35 +08:00
2019-11-29 17:47:11 +08:00
Dictionary < MetaHash , RpfFileEntry > ensureDict ( Dictionary < MetaHash , Dictionary < MetaHash , RpfFileEntry > > coll , MetaHash hash )
{
Dictionary < MetaHash , RpfFileEntry > dict ;
if ( ! coll . TryGetValue ( hash , out dict ) )
{
dict = new Dictionary < MetaHash , RpfFileEntry > ( ) ;
coll [ hash ] = dict ;
}
return dict ;
}
2019-12-30 13:37:29 +08:00
var addPedDicts = new Action < string , MetaHash , RpfDirectoryEntry > ( ( namel , hash , dir ) = >
2019-11-07 00:51:35 +08:00
{
2019-11-29 17:47:11 +08:00
Dictionary < MetaHash , RpfFileEntry > dict = null ;
var files = dir ? . Files ;
if ( files ! = null )
{
foreach ( var file in files )
{
if ( file . NameLower = = namel + ".yld" )
{
dict = ensureDict ( allPedClothDicts , hash ) ;
dict [ file . ShortNameHash ] = file ;
}
}
}
2019-11-07 00:51:35 +08:00
if ( dir ? . Directories ! = null )
{
foreach ( var cdir in dir . Directories )
{
if ( cdir . NameLower = = namel )
{
dir = cdir ;
break ;
}
}
2019-11-29 17:47:11 +08:00
files = dir ? . Files ;
2019-11-07 00:51:35 +08:00
if ( files ! = null )
{
foreach ( var file in files )
{
if ( file ? . NameLower = = null ) continue ;
if ( file . NameLower . EndsWith ( ".ydd" ) )
{
2019-11-29 17:47:11 +08:00
dict = ensureDict ( allPedDrwDicts , hash ) ;
2019-11-07 00:51:35 +08:00
dict [ file . ShortNameHash ] = file ;
}
else if ( file . NameLower . EndsWith ( ".ytd" ) )
{
2019-11-29 17:47:11 +08:00
dict = ensureDict ( allPedTexDicts , hash ) ;
dict [ file . ShortNameHash ] = file ;
}
else if ( file . NameLower . EndsWith ( ".yld" ) )
{
dict = ensureDict ( allPedClothDicts , hash ) ;
2019-11-07 00:51:35 +08:00
dict [ file . ShortNameHash ] = file ;
}
}
}
}
} ) ;
2019-11-06 01:53:20 +08:00
var addPedsFiles = new Action < IEnumerable < RpfFile > > ( ( from ) = >
{
foreach ( RpfFile file in from )
{
if ( file . AllEntries = = null ) continue ;
foreach ( RpfEntry entry in file . AllEntries )
{
try
{
if ( ( entry . NameLower = = "peds.ymt" ) | | ( entry . NameLower = = "peds.meta" ) )
{
var pf = RpfMan . GetFile < PedsFile > ( entry ) ;
if ( pf . InitDataList ? . InitDatas ! = null )
{
foreach ( var initData in pf . InitDataList . InitDatas )
{
var name = initData . Name . ToLowerInvariant ( ) ;
var hash = JenkHash . GenHash ( name ) ;
if ( allPeds . ContainsKey ( hash ) )
{ }
allPeds [ hash ] = initData ;
}
}
allPedsFiles . Add ( pf ) ;
}
}
catch ( Exception ex )
{
string errstr = entry . Path + "\n" + ex . ToString ( ) ;
2023-10-28 03:31:09 +08:00
ErrorLog ? . Invoke ( errstr ) ;
Console . WriteLine ( errstr ) ;
2019-11-06 01:53:20 +08:00
}
}
}
2019-11-07 00:51:35 +08:00
} ) ;
2019-11-06 01:53:20 +08:00
2019-11-07 00:51:35 +08:00
var addPedFiles = new Action < IEnumerable < RpfFile > > ( ( from ) = >
{
foreach ( RpfFile file in from )
{
if ( file . AllEntries = = null ) continue ;
foreach ( RpfEntry entry in file . AllEntries )
{
try
{
2023-10-28 03:31:09 +08:00
if ( entry . Name . EndsWith ( ".ymt" , StringComparison . OrdinalIgnoreCase ) )
2019-11-07 00:51:35 +08:00
{
2023-10-28 03:31:09 +08:00
var testname = entry . ShortName ;
var testhash = JenkHash . GenHashLower ( testname ) ;
2019-11-07 00:51:35 +08:00
if ( allPeds . ContainsKey ( testhash ) )
{
var pf = RpfMan . GetFile < PedFile > ( entry ) ;
if ( pf ! = null )
{
allPedYmts [ testhash ] = pf ;
addPedDicts ( testname , testhash , entry . Parent ) ;
}
}
}
}
catch ( Exception ex )
{
string errstr = entry . Path + "\n" + ex . ToString ( ) ;
2023-10-28 03:31:09 +08:00
ErrorLog ? . Invoke ( errstr ) ;
Console . WriteLine ( errstr ) ;
2019-11-07 00:51:35 +08:00
}
}
}
2019-11-06 01:53:20 +08:00
} ) ;
2019-11-07 00:51:35 +08:00
2019-11-06 01:53:20 +08:00
addPedsFiles ( rpfs ) ;
2019-11-07 00:51:35 +08:00
addPedsFiles ( dlcrpfs ) ;
addPedFiles ( rpfs ) ;
addPedFiles ( dlcrpfs ) ;
2019-11-06 01:53:20 +08:00
PedsInitDict = allPeds ;
2019-11-07 00:51:35 +08:00
PedVariationsDict = allPedYmts ;
PedDrawableDicts = allPedDrwDicts ;
PedTextureDicts = allPedTexDicts ;
2019-11-29 17:47:11 +08:00
PedClothDicts = allPedClothDicts ;
2019-11-07 00:51:35 +08:00
foreach ( var kvp in PedsInitDict )
{
if ( ! PedVariationsDict . ContainsKey ( kvp . Key ) )
{ } //checking we found them all!
}
2019-11-06 01:53:20 +08:00
}
2022-01-13 02:07:07 +08:00
public void InitAudio ( )
{
if ( ! LoadAudio ) return ;
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( "Loading audio..." ) ;
using var timer = new DisposableTimer ( "InitAudio" ) ;
2022-01-13 02:07:07 +08:00
Dictionary < uint , RpfFileEntry > datrelentries = new Dictionary < uint , RpfFileEntry > ( ) ;
void addRpfDatRelEntries ( RpfFile rpffile )
{
if ( rpffile . AllEntries = = null ) return ;
foreach ( var entry in rpffile . AllEntries )
{
if ( entry is RpfFileEntry )
{
RpfFileEntry fentry = entry as RpfFileEntry ;
if ( entry . NameLower . EndsWith ( ".rel" ) )
{
datrelentries [ entry . NameHash ] = fentry ;
}
}
}
}
var audrpf = RpfMan . FindRpfFile ( "x64\\audio\\audio_rel.rpf" ) ;
if ( audrpf ! = null )
{
addRpfDatRelEntries ( audrpf ) ;
}
if ( EnableDlc )
{
var updrpf = RpfMan . FindRpfFile ( "update\\update.rpf" ) ;
if ( updrpf ! = null )
{
addRpfDatRelEntries ( updrpf ) ;
}
foreach ( var dlcrpf in DlcActiveRpfs ) //load from current dlc rpfs
{
addRpfDatRelEntries ( dlcrpf ) ;
}
if ( DlcActiveRpfs . Count = = 0 ) //when activated from RPF explorer... DLCs aren't initialised fully
{
foreach ( var rpf in AllRpfs ) //this is a bit of a hack - DLC orders won't be correct so likely will select wrong versions of things
{
if ( rpf . NameLower . StartsWith ( "dlc" ) )
{
addRpfDatRelEntries ( rpf ) ;
}
}
}
}
var audioDatRelFiles = new List < RelFile > ( ) ;
var audioConfigDict = new Dictionary < MetaHash , RelData > ( ) ;
var audioSpeechDict = new Dictionary < MetaHash , RelData > ( ) ;
var audioSynthsDict = new Dictionary < MetaHash , RelData > ( ) ;
var audioMixersDict = new Dictionary < MetaHash , RelData > ( ) ;
var audioCurvesDict = new Dictionary < MetaHash , RelData > ( ) ;
var audioCategsDict = new Dictionary < MetaHash , RelData > ( ) ;
var audioSoundsDict = new Dictionary < MetaHash , RelData > ( ) ;
var audioGameDict = new Dictionary < MetaHash , RelData > ( ) ;
foreach ( var datrelentry in datrelentries . Values )
{
var relfile = RpfMan . GetFile < RelFile > ( datrelentry ) ;
if ( relfile = = null ) continue ;
audioDatRelFiles . Add ( relfile ) ;
var d = audioGameDict ;
var t = relfile . RelType ;
switch ( t )
{
case RelDatFileType . Dat4 :
d = relfile . IsAudioConfig ? audioConfigDict : audioSpeechDict ;
break ;
case RelDatFileType . Dat10ModularSynth :
d = audioSynthsDict ;
break ;
case RelDatFileType . Dat15DynamicMixer :
d = audioMixersDict ;
break ;
case RelDatFileType . Dat16Curves :
d = audioCurvesDict ;
break ;
case RelDatFileType . Dat22Categories :
d = audioCategsDict ;
break ;
case RelDatFileType . Dat54DataEntries :
d = audioSoundsDict ;
break ;
case RelDatFileType . Dat149 :
case RelDatFileType . Dat150 :
case RelDatFileType . Dat151 :
default :
d = audioGameDict ;
break ;
}
foreach ( var reldata in relfile . RelDatas )
{
if ( reldata . NameHash = = 0 ) continue ;
//if (d.TryGetValue(reldata.NameHash, out var exdata) && (exdata.TypeID != reldata.TypeID))
//{ }//sanity check
d [ reldata . NameHash ] = reldata ;
}
}
AudioDatRelFiles = audioDatRelFiles ;
AudioConfigDict = audioConfigDict ;
AudioSpeechDict = audioSpeechDict ;
AudioSynthsDict = audioSynthsDict ;
AudioMixersDict = audioMixersDict ;
AudioCurvesDict = audioCurvesDict ;
AudioCategsDict = audioCategsDict ;
AudioSoundsDict = audioSoundsDict ;
AudioGameDict = audioGameDict ;
}
2017-09-21 18:33:05 +08:00
public bool SetDlcLevel ( string dlc , bool enable )
{
2023-10-28 03:31:09 +08:00
bool dlcchange = ( ! dlc . Equals ( SelectedDlc , StringComparison . OrdinalIgnoreCase ) ) ;
2017-09-21 18:33:05 +08:00
bool enablechange = ( enable ! = EnableDlc ) ;
bool change = ( dlcchange & & enable ) | | enablechange ;
if ( change )
{
lock ( updateSyncRoot )
{
2019-01-06 02:04:33 +08:00
//lock (textureSyncRoot)
2017-09-21 18:33:05 +08:00
{
SelectedDlc = dlc ;
EnableDlc = enable ;
//mainCache.Clear();
ClearCachedMaps ( ) ;
InitDlc ( ) ;
}
}
}
return change ;
}
public bool SetModsEnabled ( bool enable )
{
bool change = ( enable ! = EnableMods ) ;
if ( change )
{
lock ( updateSyncRoot )
{
2019-01-06 02:04:33 +08:00
//lock (textureSyncRoot)
2017-09-21 18:33:05 +08:00
{
EnableMods = enable ;
RpfMan . EnableMods = enable ;
mainCache . Clear ( ) ;
InitGlobal ( ) ;
InitDlc ( ) ;
}
}
}
return change ;
}
private void ClearCachedMaps ( )
{
if ( AllYmapsDict ! = null )
{
foreach ( var ymap in AllYmapsDict . Values )
{
GameFileCacheKey k = new GameFileCacheKey ( ymap . ShortNameHash , GameFileType . Ymap ) ;
mainCache . Remove ( k ) ;
}
}
}
2022-01-10 01:03:57 +08:00
public void AddProjectFile ( GameFile f )
{
if ( f = = null ) return ;
if ( f . RpfFileEntry = = null ) return ;
2023-10-28 03:31:09 +08:00
if ( f . RpfFileEntry . ShortNameHash = = 0 ) return ;
2022-01-10 01:03:57 +08:00
var key = new GameFileCacheKey ( f . RpfFileEntry . ShortNameHash , f . Type ) ;
2023-10-28 03:31:09 +08:00
projectFiles [ key ] = f ;
2022-01-10 01:03:57 +08:00
}
public void RemoveProjectFile ( GameFile f )
{
if ( f = = null ) return ;
if ( f . RpfFileEntry = = null ) return ;
if ( f . RpfFileEntry . ShortNameHash = = 0 ) return ;
var key = new GameFileCacheKey ( f . RpfFileEntry . ShortNameHash , f . Type ) ;
2023-10-28 03:31:09 +08:00
projectFiles . TryRemove ( key , out _ ) ;
2022-01-10 01:03:57 +08:00
}
public void ClearProjectFiles ( )
{
2023-10-28 03:31:09 +08:00
projectFiles . Clear ( ) ;
2022-01-10 01:03:57 +08:00
}
public void AddProjectArchetype ( Archetype a )
{
if ( ( a ? . Hash ? ? 0 ) = = 0 ) return ;
2023-10-28 03:31:09 +08:00
projectArchetypes [ a . Hash ] = a ;
2022-01-10 01:03:57 +08:00
}
public void RemoveProjectArchetype ( Archetype a )
{
if ( ( a ? . Hash ? ? 0 ) = = 0 ) return ;
Archetype tarch = null ;
2023-10-28 03:31:09 +08:00
projectArchetypes . TryGetValue ( a . Hash , out tarch ) ;
if ( tarch = = a )
2022-01-10 01:03:57 +08:00
{
2023-10-28 03:31:09 +08:00
projectArchetypes . TryRemove ( a . Hash , out _ ) ;
2022-01-10 01:03:57 +08:00
}
}
public void ClearProjectArchetypes ( )
{
2023-10-28 03:31:09 +08:00
projectArchetypes . Clear ( ) ;
2022-01-10 01:03:57 +08:00
}
2019-11-07 00:51:35 +08:00
public void TryLoadEnqueue ( GameFile gf )
2017-09-21 18:33:05 +08:00
{
2023-10-28 03:31:09 +08:00
if ( gf . Loaded | | gf . LoadQueued )
{
return ;
}
if ( requestQueue . Count < 20 ) // && (!gf.LoadQueued)
2017-09-21 18:33:05 +08:00
{
gf . LoadQueued = true ;
2023-10-28 03:31:09 +08:00
requestQueue . Enqueue ( gf ) ;
2017-09-21 18:33:05 +08:00
}
}
public Archetype GetArchetype ( uint hash )
{
if ( ! archetypesLoaded ) return null ;
2023-10-28 03:31:09 +08:00
if ( projectArchetypes . TryGetValue ( hash , out var arch ) & & arch ! = null )
{
return arch ;
}
2017-09-21 18:33:05 +08:00
archetypeDict . TryGetValue ( hash , out arch ) ;
return arch ;
}
public MapDataStoreNode GetMapNode ( uint hash )
{
if ( ! IsInited ) return null ;
2023-10-28 03:31:09 +08:00
YmapHierarchyDict . TryGetValue ( hash , out var node ) ;
2017-09-21 18:33:05 +08:00
return node ;
}
public YdrFile GetYdr ( uint hash )
{
if ( ! IsInited ) return null ;
lock ( requestSyncRoot )
{
var key = new GameFileCacheKey ( hash , GameFileType . Ydr ) ;
2022-01-10 01:03:57 +08:00
if ( projectFiles . TryGetValue ( key , out GameFile pgf ) )
{
return pgf as YdrFile ;
}
2017-09-21 18:33:05 +08:00
YdrFile ydr = mainCache . TryGet ( key ) as YdrFile ;
if ( ydr = = null )
{
var e = GetYdrEntry ( hash ) ;
2023-10-28 03:31:09 +08:00
if ( e = = null )
2017-09-21 18:33:05 +08:00
{
2023-10-28 03:31:09 +08:00
return null ;
2017-09-21 18:33:05 +08:00
}
2023-10-28 03:31:09 +08:00
ydr = new YdrFile ( e ) ;
if ( ! mainCache . TryAdd ( key , ydr ) )
2017-09-21 18:33:05 +08:00
{
2023-10-28 03:31:09 +08:00
//ErrorLog("Out of cache space - couldn't load drawable: " + JenkIndex.GetString(hash)); //too spammy...
ydr . LoadQueued = false ;
return null ;
2017-09-21 18:33:05 +08:00
}
}
2023-10-28 03:31:09 +08:00
if ( ! ydr . Loaded & & ! ydr . LoadQueued )
2017-09-21 18:33:05 +08:00
{
TryLoadEnqueue ( ydr ) ;
}
return ydr ;
}
}
public YddFile GetYdd ( uint hash )
{
if ( ! IsInited ) return null ;
lock ( requestSyncRoot )
{
var key = new GameFileCacheKey ( hash , GameFileType . Ydd ) ;
2022-01-10 01:03:57 +08:00
if ( projectFiles . TryGetValue ( key , out GameFile pgf ) )
{
return pgf as YddFile ;
}
2017-09-21 18:33:05 +08:00
YddFile ydd = mainCache . TryGet ( key ) as YddFile ;
if ( ydd = = null )
{
var e = GetYddEntry ( hash ) ;
if ( e ! = null )
{
ydd = new YddFile ( e ) ;
if ( mainCache . TryAdd ( key , ydd ) )
{
TryLoadEnqueue ( ydd ) ;
}
else
{
ydd . LoadQueued = false ;
//ErrorLog("Out of cache space - couldn't load drawable dictionary: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else
{
//ErrorLog("Drawable dictionary not found: " + JenkIndex.GetString(hash)); //too spammy...
}
}
2019-12-30 13:37:29 +08:00
else if ( ! ydd . Loaded )
2017-09-21 18:33:05 +08:00
{
TryLoadEnqueue ( ydd ) ;
}
return ydd ;
}
}
public YtdFile GetYtd ( uint hash )
{
if ( ! IsInited ) return null ;
lock ( requestSyncRoot )
{
var key = new GameFileCacheKey ( hash , GameFileType . Ytd ) ;
2022-01-10 01:03:57 +08:00
if ( projectFiles . TryGetValue ( key , out GameFile pgf ) )
{
return pgf as YtdFile ;
}
2017-09-21 18:33:05 +08:00
YtdFile ytd = mainCache . TryGet ( key ) as YtdFile ;
if ( ytd = = null )
{
var e = GetYtdEntry ( hash ) ;
if ( e ! = null )
{
ytd = new YtdFile ( e ) ;
if ( mainCache . TryAdd ( key , ytd ) )
{
TryLoadEnqueue ( ytd ) ;
}
else
{
ytd . LoadQueued = false ;
//ErrorLog("Out of cache space - couldn't load texture dictionary: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else
{
//ErrorLog("Texture dictionary not found: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else if ( ! ytd . Loaded )
{
TryLoadEnqueue ( ytd ) ;
}
return ytd ;
}
}
public YmapFile GetYmap ( uint hash )
{
if ( ! IsInited ) return null ;
lock ( requestSyncRoot )
{
var key = new GameFileCacheKey ( hash , GameFileType . Ymap ) ;
YmapFile ymap = mainCache . TryGet ( key ) as YmapFile ;
if ( ymap = = null )
{
var e = GetYmapEntry ( hash ) ;
if ( e ! = null )
{
ymap = new YmapFile ( e ) ;
if ( mainCache . TryAdd ( key , ymap ) )
{
TryLoadEnqueue ( ymap ) ;
}
else
{
ymap . LoadQueued = false ;
//ErrorLog("Out of cache space - couldn't load ymap: " + JenkIndex.GetString(hash));
}
}
else
{
//ErrorLog("Ymap not found: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else if ( ! ymap . Loaded )
{
TryLoadEnqueue ( ymap ) ;
}
return ymap ;
}
}
public YftFile GetYft ( uint hash )
{
if ( ! IsInited ) return null ;
lock ( requestSyncRoot )
{
var key = new GameFileCacheKey ( hash , GameFileType . Yft ) ;
YftFile yft = mainCache . TryGet ( key ) as YftFile ;
2022-01-10 01:03:57 +08:00
if ( projectFiles . TryGetValue ( key , out GameFile pgf ) )
{
return pgf as YftFile ;
}
2017-09-21 18:33:05 +08:00
if ( yft = = null )
{
var e = GetYftEntry ( hash ) ;
if ( e ! = null )
{
yft = new YftFile ( e ) ;
if ( mainCache . TryAdd ( key , yft ) )
{
TryLoadEnqueue ( yft ) ;
}
else
{
yft . LoadQueued = false ;
//ErrorLog("Out of cache space - couldn't load yft: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else
{
//ErrorLog("Yft not found: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else if ( ! yft . Loaded )
{
TryLoadEnqueue ( yft ) ;
}
return yft ;
}
}
public YbnFile GetYbn ( uint hash )
{
if ( ! IsInited ) return null ;
lock ( requestSyncRoot )
{
var key = new GameFileCacheKey ( hash , GameFileType . Ybn ) ;
YbnFile ybn = mainCache . TryGet ( key ) as YbnFile ;
if ( ybn = = null )
{
var e = GetYbnEntry ( hash ) ;
if ( e ! = null )
{
ybn = new YbnFile ( e ) ;
if ( mainCache . TryAdd ( key , ybn ) )
{
TryLoadEnqueue ( ybn ) ;
}
else
{
ybn . LoadQueued = false ;
//ErrorLog("Out of cache space - couldn't load ybn: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else
{
//ErrorLog("Ybn not found: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else if ( ! ybn . Loaded )
{
TryLoadEnqueue ( ybn ) ;
}
return ybn ;
}
}
public YcdFile GetYcd ( uint hash )
{
if ( ! IsInited ) return null ;
lock ( requestSyncRoot )
{
var key = new GameFileCacheKey ( hash , GameFileType . Ycd ) ;
YcdFile ycd = mainCache . TryGet ( key ) as YcdFile ;
if ( ycd = = null )
{
var e = GetYcdEntry ( hash ) ;
if ( e ! = null )
{
ycd = new YcdFile ( e ) ;
if ( mainCache . TryAdd ( key , ycd ) )
{
TryLoadEnqueue ( ycd ) ;
}
else
{
ycd . LoadQueued = false ;
//ErrorLog("Out of cache space - couldn't load ycd: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else
{
//ErrorLog("Ycd not found: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else if ( ! ycd . Loaded )
{
TryLoadEnqueue ( ycd ) ;
}
return ycd ;
}
}
2020-03-06 00:02:40 +08:00
public YedFile GetYed ( uint hash )
{
if ( ! IsInited ) return null ;
lock ( requestSyncRoot )
{
var key = new GameFileCacheKey ( hash , GameFileType . Yed ) ;
YedFile yed = mainCache . TryGet ( key ) as YedFile ;
if ( yed = = null )
{
var e = GetYedEntry ( hash ) ;
if ( e ! = null )
{
yed = new YedFile ( e ) ;
if ( mainCache . TryAdd ( key , yed ) )
{
TryLoadEnqueue ( yed ) ;
}
else
{
yed . LoadQueued = false ;
//ErrorLog("Out of cache space - couldn't load yed: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else
{
//ErrorLog("Yed not found: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else if ( ! yed . Loaded )
{
TryLoadEnqueue ( yed ) ;
}
return yed ;
}
}
2017-09-21 18:33:05 +08:00
public YnvFile GetYnv ( uint hash )
{
if ( ! IsInited ) return null ;
lock ( requestSyncRoot )
{
var key = new GameFileCacheKey ( hash , GameFileType . Ynv ) ;
YnvFile ynv = mainCache . TryGet ( key ) as YnvFile ;
if ( ynv = = null )
{
var e = GetYnvEntry ( hash ) ;
if ( e ! = null )
{
ynv = new YnvFile ( e ) ;
if ( mainCache . TryAdd ( key , ynv ) )
{
TryLoadEnqueue ( ynv ) ;
}
else
{
ynv . LoadQueued = false ;
//ErrorLog("Out of cache space - couldn't load ycd: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else
{
//ErrorLog("Ycd not found: " + JenkIndex.GetString(hash)); //too spammy...
}
}
else if ( ! ynv . Loaded )
{
TryLoadEnqueue ( ynv ) ;
}
return ynv ;
}
}
public RpfFileEntry GetYdrEntry ( uint hash )
{
RpfFileEntry entry ;
YdrDict . TryGetValue ( hash , out entry ) ;
return entry ;
}
public RpfFileEntry GetYddEntry ( uint hash )
{
RpfFileEntry entry ;
YddDict . TryGetValue ( hash , out entry ) ;
return entry ;
}
public RpfFileEntry GetYtdEntry ( uint hash )
{
RpfFileEntry entry ;
YtdDict . TryGetValue ( hash , out entry ) ;
return entry ;
}
public RpfFileEntry GetYmapEntry ( uint hash )
{
RpfFileEntry entry ;
if ( ! YmapDict . TryGetValue ( hash , out entry ) )
{
AllYmapsDict . TryGetValue ( hash , out entry ) ;
}
return entry ;
}
public RpfFileEntry GetYftEntry ( uint hash )
{
RpfFileEntry entry ;
YftDict . TryGetValue ( hash , out entry ) ;
return entry ;
}
public RpfFileEntry GetYbnEntry ( uint hash )
{
RpfFileEntry entry ;
YbnDict . TryGetValue ( hash , out entry ) ;
return entry ;
}
public RpfFileEntry GetYcdEntry ( uint hash )
{
RpfFileEntry entry ;
YcdDict . TryGetValue ( hash , out entry ) ;
return entry ;
}
2020-03-06 00:02:40 +08:00
public RpfFileEntry GetYedEntry ( uint hash )
{
RpfFileEntry entry ;
YedDict . TryGetValue ( hash , out entry ) ;
return entry ;
}
2017-09-21 18:33:05 +08:00
public RpfFileEntry GetYnvEntry ( uint hash )
{
RpfFileEntry entry ;
YnvDict . TryGetValue ( hash , out entry ) ;
return entry ;
}
2019-12-30 13:37:29 +08:00
public bool LoadFile < T > ( T file ) where T : GameFile , PackedFile
2017-09-21 18:33:05 +08:00
{
if ( file = = null ) return false ;
RpfFileEntry entry = file . RpfFileEntry ;
if ( entry ! = null )
{
return RpfMan . LoadFile ( file , entry ) ;
}
return false ;
}
2019-11-07 00:51:35 +08:00
public T GetFileUncached < T > ( RpfFileEntry e ) where T : GameFile , new ( )
{
var f = new T ( ) ;
f . RpfFileEntry = e ;
TryLoadEnqueue ( f ) ;
return f ;
}
2017-09-21 18:33:05 +08:00
2019-12-10 21:31:56 +08:00
public void BeginFrame ( )
{
lock ( requestSyncRoot )
{
mainCache . BeginFrame ( ) ;
}
}
2017-09-21 18:33:05 +08:00
2023-10-28 03:31:09 +08:00
private void LoadFile ( GameFile req )
2017-09-21 18:33:05 +08:00
{
2023-10-28 03:31:09 +08:00
try
2017-09-21 18:33:05 +08:00
{
//process content requests.
if ( req . Loaded )
2023-10-28 03:31:09 +08:00
return ; //it's already loaded... (somehow)
2017-09-21 18:33:05 +08:00
2023-10-28 03:31:09 +08:00
if ( ( req . LastUseTime - DateTime . Now ) . TotalSeconds > 3.0 )
return ; //hasn't been requested lately..! ignore, will try again later if necessary
2017-09-21 18:33:05 +08:00
//if (!loadedsomething)
//{
2023-10-28 03:31:09 +08:00
//UpdateStatus?.Invoke("Loading " + req.RpfFileEntry.Name + "...");
2017-09-21 18:33:05 +08:00
//}
switch ( req . Type )
{
case GameFileType . Ydr :
req . Loaded = LoadFile ( req as YdrFile ) ;
break ;
case GameFileType . Ydd :
req . Loaded = LoadFile ( req as YddFile ) ;
break ;
case GameFileType . Ytd :
req . Loaded = LoadFile ( req as YtdFile ) ;
2019-01-06 02:04:33 +08:00
//if (req.Loaded) AddTextureLookups(req as YtdFile);
2017-09-21 18:33:05 +08:00
break ;
case GameFileType . Ymap :
2018-12-03 16:54:04 +08:00
YmapFile y = req as YmapFile ;
req . Loaded = LoadFile ( y ) ;
if ( req . Loaded ) y . InitYmapEntityArchetypes ( this ) ;
2017-09-21 18:33:05 +08:00
break ;
case GameFileType . Yft :
req . Loaded = LoadFile ( req as YftFile ) ;
break ;
case GameFileType . Ybn :
req . Loaded = LoadFile ( req as YbnFile ) ;
break ;
case GameFileType . Ycd :
req . Loaded = LoadFile ( req as YcdFile ) ;
break ;
2020-03-06 00:02:40 +08:00
case GameFileType . Yed :
req . Loaded = LoadFile ( req as YedFile ) ;
break ;
2017-09-21 18:33:05 +08:00
case GameFileType . Ynv :
req . Loaded = LoadFile ( req as YnvFile ) ;
break ;
2019-11-29 17:47:11 +08:00
case GameFileType . Yld :
req . Loaded = LoadFile ( req as YldFile ) ;
break ;
2017-09-21 18:33:05 +08:00
default :
break ;
}
string str = ( req . Loaded ? "Loaded " : "Error loading " ) + req . ToString ( ) ;
//string str = string.Format("{0}: {1}: {2}", requestQueue.Count, (req.Loaded ? "Loaded" : "Error loading"), req);
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( str ) ;
2017-09-21 18:33:05 +08:00
//ErrorLog(str);
if ( ! req . Loaded )
{
ErrorLog ( "Error loading " + req . ToString ( ) ) ;
}
}
2023-10-28 03:31:09 +08:00
catch ( Exception e )
{
req . LoadQueued = false ;
req . Loaded = false ;
Console . WriteLine ( e ) ;
}
finally
{
req . LoadQueued = false ;
}
}
2017-09-21 18:33:05 +08:00
2023-10-28 03:31:09 +08:00
public bool ContentThreadProc ( )
{
lock ( requestSyncRoot )
{
mainCache . BeginFrame ( ) ;
}
int itemcount = 0 ;
lock ( updateSyncRoot )
{
GameFile req ;
2017-09-21 18:33:05 +08:00
2023-10-28 03:31:09 +08:00
while ( ( itemcount < MaxItemsPerLoop ) & & requestQueue . TryDequeue ( out req ) )
{
LoadFile ( req ) ;
2018-01-02 04:52:54 +08:00
2023-10-28 03:31:09 +08:00
itemcount + + ;
}
}
2018-01-02 04:52:54 +08:00
2023-10-28 03:31:09 +08:00
return itemcount > = 1 ;
2017-09-21 18:33:05 +08:00
}
private void AddTextureLookups ( YtdFile ytd )
{
2019-01-27 14:14:10 +08:00
if ( ytd ? . TextureDict ? . TextureNameHashes ? . data_items = = null ) return ;
2017-09-21 18:33:05 +08:00
2023-10-28 03:31:09 +08:00
foreach ( uint hash in ytd . TextureDict . TextureNameHashes . data_items )
2017-09-21 18:33:05 +08:00
{
2023-10-28 03:31:09 +08:00
textureLookup [ hash ] = ytd . RpfFileEntry ;
2017-09-21 18:33:05 +08:00
}
}
public YtdFile TryGetTextureDictForTexture ( uint hash )
{
2023-10-28 03:31:09 +08:00
if ( textureLookup . TryGetValue ( hash , out var e ) )
2017-09-21 18:33:05 +08:00
{
2023-10-28 03:31:09 +08:00
return GetYtd ( e . ShortNameHash ) ;
2017-09-21 18:33:05 +08:00
}
2023-10-28 03:31:09 +08:00
2017-09-21 18:33:05 +08:00
return null ;
}
public YtdFile TryGetParentYtd ( uint hash )
{
2019-01-06 02:04:33 +08:00
MetaHash phash ;
2023-10-28 03:31:09 +08:00
if ( textureParents is not null & & textureParents . TryGetValue ( hash , out phash ) )
2017-09-21 18:33:05 +08:00
{
return GetYtd ( phash ) ;
}
return null ;
}
public uint TryGetParentYtdHash ( uint hash )
{
2023-10-28 03:31:09 +08:00
if ( textureParents is null )
{
return 0 u ;
}
textureParents . TryGetValue ( hash , out MetaHash phash ) ;
2017-09-21 18:33:05 +08:00
return phash ;
}
2019-01-06 02:04:33 +08:00
public uint TryGetHDTextureHash ( uint txdhash )
{
MetaHash hdhash = 0 ;
if ( hdtexturelookup ? . TryGetValue ( txdhash , out hdhash ) ? ? false )
{
return hdhash ;
}
return txdhash ;
}
2017-09-21 18:33:05 +08:00
public Texture TryFindTextureInParent ( uint texhash , uint txdhash )
{
Texture tex = null ;
var ytd = TryGetParentYtd ( txdhash ) ;
2019-01-06 02:04:33 +08:00
while ( ( ytd ! = null ) & & ( tex = = null ) )
2017-09-21 18:33:05 +08:00
{
2019-01-06 02:04:33 +08:00
if ( ytd . Loaded & & ( ytd . TextureDict ! = null ) )
{
tex = ytd . TextureDict . Lookup ( texhash ) ;
}
2017-09-21 18:33:05 +08:00
if ( tex = = null )
{
ytd = TryGetParentYtd ( ytd . Key . Hash ) ;
}
}
return tex ;
}
2018-01-02 04:52:54 +08:00
public DrawableBase TryGetDrawable ( Archetype arche )
{
if ( arche = = null ) return null ;
uint drawhash = arche . Hash ;
DrawableBase drawable = null ;
if ( ( arche . DrawableDict ! = 0 ) ) // && (arche.DrawableDict != arche.Hash))
{
//try get drawable from ydd...
YddFile ydd = GetYdd ( arche . DrawableDict ) ;
if ( ydd ! = null )
{
if ( ydd . Loaded & & ( ydd . Dict ! = null ) )
{
Drawable d ;
ydd . Dict . TryGetValue ( drawhash , out d ) ; //can't out to base class?
drawable = d ;
if ( drawable = = null )
{
return null ; //drawable wasn't in dict!!
}
}
else
{
return null ; //ydd not loaded yet, or has no dict
}
}
else
{
//return null; //couldn't find drawable dict... quit now?
}
}
if ( drawable = = null )
{
//try get drawable from ydr.
YdrFile ydr = GetYdr ( drawhash ) ;
if ( ydr ! = null )
{
if ( ydr . Loaded )
{
drawable = ydr . Drawable ;
}
}
else
{
YftFile yft = GetYft ( drawhash ) ;
if ( yft ! = null )
{
if ( yft . Loaded )
{
if ( yft . Fragment ! = null )
{
drawable = yft . Fragment . Drawable ;
}
}
}
}
}
return drawable ;
}
2019-01-21 14:30:43 +08:00
public DrawableBase TryGetDrawable ( Archetype arche , out bool waitingForLoad )
{
waitingForLoad = false ;
if ( arche = = null ) return null ;
uint drawhash = arche . Hash ;
DrawableBase drawable = null ;
if ( ( arche . DrawableDict ! = 0 ) ) // && (arche.DrawableDict != arche.Hash))
{
//try get drawable from ydd...
YddFile ydd = GetYdd ( arche . DrawableDict ) ;
if ( ydd ! = null )
{
if ( ydd . Loaded )
{
if ( ydd . Dict ! = null )
{
Drawable d ;
ydd . Dict . TryGetValue ( drawhash , out d ) ; //can't out to base class?
drawable = d ;
if ( drawable = = null )
{
return null ; //drawable wasn't in dict!!
}
}
else
{
return null ; //ydd has no dict
}
}
else
{
waitingForLoad = true ;
return null ; //ydd not loaded yet
}
}
else
{
//return null; //couldn't find drawable dict... quit now?
}
}
if ( drawable = = null )
{
//try get drawable from ydr.
YdrFile ydr = GetYdr ( drawhash ) ;
if ( ydr ! = null )
{
if ( ydr . Loaded )
{
drawable = ydr . Drawable ;
}
else
{
waitingForLoad = true ;
}
}
else
{
YftFile yft = GetYft ( drawhash ) ;
if ( yft ! = null )
{
if ( yft . Loaded )
{
if ( yft . Fragment ! = null )
{
drawable = yft . Fragment . Drawable ;
}
}
else
{
waitingForLoad = true ;
}
}
}
}
return drawable ;
}
2018-01-02 04:52:54 +08:00
2017-09-21 18:33:05 +08:00
private string [ ] GetExcludePaths ( )
{
2018-02-24 21:59:00 +08:00
string [ ] exclpaths = ExcludeFolders . Split ( new [ ] { ';' } , StringSplitOptions . RemoveEmptyEntries ) ;
2017-09-21 18:33:05 +08:00
if ( exclpaths . Length > 0 )
{
for ( int i = 0 ; i < exclpaths . Length ; i + + )
{
2017-12-20 07:52:50 +08:00
exclpaths [ i ] = exclpaths [ i ] . ToLowerInvariant ( ) ;
2017-09-21 18:33:05 +08:00
}
}
else
{
exclpaths = null ;
}
return exclpaths ;
}
2021-04-07 14:52:32 +08:00
public void GetShadersXml ( )
{
bool doydr = true ;
bool doydd = true ;
bool doyft = true ;
bool doypt = true ;
var data = new Dictionary < MetaHash , ShaderXmlDataCollection > ( ) ;
void collectDrawable ( DrawableBase d )
{
if ( d ? . AllModels = = null ) return ;
foreach ( var model in d . AllModels )
{
if ( model ? . Geometries = = null ) continue ;
foreach ( var geom in model . Geometries )
{
var s = geom ? . Shader ;
if ( s = = null ) continue ;
ShaderXmlDataCollection dc = null ;
if ( ! data . TryGetValue ( s . Name , out dc ) )
{
dc = new ShaderXmlDataCollection ( ) ;
dc . Name = s . Name ;
data . Add ( s . Name , dc ) ;
}
dc . AddShaderUse ( s , geom ) ;
}
}
}
foreach ( RpfFile file in AllRpfs )
{
foreach ( RpfEntry entry in file . AllEntries )
{
try
{
if ( doydr & & entry . NameLower . EndsWith ( ".ydr" ) )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( entry . Path ) ;
2021-04-07 14:52:32 +08:00
YdrFile ydr = RpfMan . GetFile < YdrFile > ( entry ) ;
if ( ydr = = null ) { continue ; }
if ( ydr . Drawable = = null ) { continue ; }
collectDrawable ( ydr . Drawable ) ;
}
else if ( doydd & entry . NameLower . EndsWith ( ".ydd" ) )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( entry . Path ) ;
2021-04-07 14:52:32 +08:00
YddFile ydd = RpfMan . GetFile < YddFile > ( entry ) ;
if ( ydd = = null ) { continue ; }
if ( ydd . Dict = = null ) { continue ; }
foreach ( var drawable in ydd . Dict . Values )
{
collectDrawable ( drawable ) ;
}
}
else if ( doyft & & entry . NameLower . EndsWith ( ".yft" ) )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( entry . Path ) ;
2021-04-07 14:52:32 +08:00
YftFile yft = RpfMan . GetFile < YftFile > ( entry ) ;
if ( yft = = null ) { continue ; }
if ( yft . Fragment = = null ) { continue ; }
if ( yft . Fragment . Drawable ! = null )
{
collectDrawable ( yft . Fragment . Drawable ) ;
}
if ( ( yft . Fragment . Cloths ! = null ) & & ( yft . Fragment . Cloths . data_items ! = null ) )
{
foreach ( var cloth in yft . Fragment . Cloths . data_items )
{
collectDrawable ( cloth . Drawable ) ;
}
}
if ( ( yft . Fragment . DrawableArray ! = null ) & & ( yft . Fragment . DrawableArray . data_items ! = null ) )
{
foreach ( var drawable in yft . Fragment . DrawableArray . data_items )
{
collectDrawable ( drawable ) ;
}
}
}
else if ( doypt & & entry . NameLower . EndsWith ( ".ypt" ) )
{
2023-10-28 03:31:09 +08:00
UpdateStatus ? . Invoke ( entry . Path ) ;
2021-04-07 14:52:32 +08:00
YptFile ypt = RpfMan . GetFile < YptFile > ( entry ) ;
if ( ypt = = null ) { continue ; }
if ( ypt . DrawableDict = = null ) { continue ; }
foreach ( var drawable in ypt . DrawableDict . Values )
{
collectDrawable ( drawable ) ;
}
}
}
catch //(Exception ex)
{ }
}
}
var shaders = data . Values . ToList ( ) ;
shaders . Sort ( ( a , b ) = > { return b . GeomCount . CompareTo ( a . GeomCount ) ; } ) ;
StringBuilder sb = new StringBuilder ( ) ;
sb . AppendLine ( MetaXml . XmlHeader ) ;
MetaXml . OpenTag ( sb , 0 , "Shaders" ) ;
foreach ( var s in shaders )
{
MetaXml . OpenTag ( sb , 1 , "Item" ) ;
MetaXml . StringTag ( sb , 2 , "Name" , MetaXml . HashString ( s . Name ) ) ;
MetaXml . WriteHashItemArray ( sb , s . GetSortedList ( s . FileNames ) . ToArray ( ) , 2 , "FileName" ) ;
MetaXml . WriteRawArray ( sb , s . GetSortedList ( s . RenderBuckets ) . ToArray ( ) , 2 , "RenderBucket" , "" ) ;
MetaXml . OpenTag ( sb , 2 , "Layout" ) ;
var layouts = s . GetSortedList ( s . VertexLayouts ) ;
foreach ( var l in layouts )
{
var vd = new VertexDeclaration ( ) ;
vd . Types = l . Types ;
vd . Flags = l . Flags ;
vd . WriteXml ( sb , 3 , "Item" ) ;
}
MetaXml . CloseTag ( sb , 2 , "Layout" ) ;
MetaXml . OpenTag ( sb , 2 , "Parameters" ) ;
var otstr = "Item name=\"{0}\" type=\"{1}\"" ;
var texparams = s . GetSortedList ( s . TexParams ) ;
var valparams = s . ValParams ;
var arrparams = s . ArrParams ;
foreach ( var tp in texparams )
{
MetaXml . SelfClosingTag ( sb , 3 , string . Format ( otstr , ( ( ShaderParamNames ) tp ) . ToString ( ) , "Texture" ) ) ;
}
foreach ( var vp in valparams )
{
var svp = s . GetSortedList ( vp . Value ) ;
var defval = svp . FirstOrDefault ( ) ;
MetaXml . SelfClosingTag ( sb , 3 , string . Format ( otstr , ( ( ShaderParamNames ) vp . Key ) . ToString ( ) , "Vector" ) + " " + FloatUtil . GetVector4XmlString ( defval ) ) ;
}
foreach ( var ap in arrparams )
{
var defval = ap . Value . FirstOrDefault ( ) ;
MetaXml . OpenTag ( sb , 3 , string . Format ( otstr , ( ( ShaderParamNames ) ap . Key ) . ToString ( ) , "Array" ) ) ;
foreach ( var vec in defval )
{
MetaXml . SelfClosingTag ( sb , 4 , "Value " + FloatUtil . GetVector4XmlString ( vec ) ) ;
}
MetaXml . CloseTag ( sb , 3 , "Item" ) ;
}
MetaXml . CloseTag ( sb , 2 , "Parameters" ) ;
MetaXml . CloseTag ( sb , 1 , "Item" ) ;
}
MetaXml . CloseTag ( sb , 0 , "Shaders" ) ;
var xml = sb . ToString ( ) ;
File . WriteAllText ( "C:\\Shaders.xml" , xml ) ;
2017-09-21 18:33:05 +08:00
}
public void GetArchetypeTimesList ( )
{
StringBuilder sb = new StringBuilder ( ) ;
sb . AppendLine ( "Name,AssetName,12am,1am,2am,3am,4am,5am,6am,7am,8am,9am,10am,11am,12pm,1pm,2pm,3pm,4pm,5pm,6pm,7pm,8pm,9pm,10pm,11pm,+12am,+1am,+2am,+3am,+4am,+5am,+6am,+7am" ) ;
foreach ( var ytyp in YtypDict . Values )
{
foreach ( var arch in ytyp . AllArchetypes )
{
2017-09-28 12:28:09 +08:00
if ( arch . Type = = MetaName . CTimeArchetypeDef )
2017-09-21 18:33:05 +08:00
{
2017-09-28 12:28:09 +08:00
var ta = arch as TimeArchetype ;
var t = ta . TimeFlags ;
sb . Append ( arch . Name ) ;
2017-09-21 18:33:05 +08:00
sb . Append ( "," ) ;
2017-09-28 12:28:09 +08:00
sb . Append ( arch . AssetName ) ;
2017-09-21 18:33:05 +08:00
sb . Append ( "," ) ;
for ( int i = 0 ; i < 32 ; i + + )
{
bool v = ( ( t > > i ) & 1 ) = = 1 ;
sb . Append ( v ? "1" : "0" ) ;
sb . Append ( "," ) ;
}
sb . AppendLine ( ) ;
}
}
}
var csv = sb . ToString ( ) ;
}
2021-04-07 14:52:32 +08:00
private class ShaderXmlDataCollection
{
public MetaHash Name { get ; set ; }
public Dictionary < MetaHash , int > FileNames { get ; set ; } = new Dictionary < MetaHash , int > ( ) ;
public Dictionary < byte , int > RenderBuckets { get ; set ; } = new Dictionary < byte , int > ( ) ;
public Dictionary < ShaderXmlVertexLayout , int > VertexLayouts { get ; set ; } = new Dictionary < ShaderXmlVertexLayout , int > ( ) ;
public Dictionary < MetaName , int > TexParams { get ; set ; } = new Dictionary < MetaName , int > ( ) ;
public Dictionary < MetaName , Dictionary < Vector4 , int > > ValParams { get ; set ; } = new Dictionary < MetaName , Dictionary < Vector4 , int > > ( ) ;
public Dictionary < MetaName , List < Vector4 [ ] > > ArrParams { get ; set ; } = new Dictionary < MetaName , List < Vector4 [ ] > > ( ) ;
public int GeomCount { get ; set ; } = 0 ;
public void AddShaderUse ( ShaderFX s , DrawableGeometry g )
{
GeomCount + + ;
AddItem ( s . FileName , FileNames ) ;
AddItem ( s . RenderBucket , RenderBuckets ) ;
var info = g . VertexBuffer ? . Info ;
if ( info ! = null )
{
AddItem ( new ShaderXmlVertexLayout ( ) { Flags = info . Flags , Types = info . Types } , VertexLayouts ) ;
}
if ( s . ParametersList ? . Parameters = = null ) return ;
if ( s . ParametersList ? . Hashes = = null ) return ;
for ( int i = 0 ; i < s . ParametersList . Count ; i + + )
{
var h = s . ParametersList . Hashes [ i ] ;
var p = s . ParametersList . Parameters [ i ] ;
if ( p . DataType = = 0 ) //texture
{
AddItem ( h , TexParams ) ;
}
else if ( p . DataType = = 1 ) //vector
{
var vp = GetItem ( h , ValParams ) ;
if ( p . Data is Vector4 vec )
{
AddItem ( vec , vp ) ;
}
}
else if ( p . DataType > 1 ) //array
{
var ap = GetItem ( h , ArrParams ) ;
if ( p . Data is Vector4 [ ] arr )
{
bool found = false ;
foreach ( var exarr in ap )
{
if ( exarr . Length ! = arr . Length ) continue ;
bool match = true ;
for ( int j = 0 ; j < exarr . Length ; j + + )
{
if ( exarr [ j ] ! = arr [ j ] )
{
match = false ;
break ;
}
}
if ( match )
{
found = true ;
break ;
}
}
if ( ! found )
{
ap . Add ( arr ) ;
}
}
}
}
}
public void AddItem < T > ( T t , Dictionary < T , int > d )
{
if ( d . ContainsKey ( t ) )
{
d [ t ] + + ;
}
else
{
d [ t ] = 1 ;
}
}
public U GetItem < T , U > ( T t , Dictionary < T , U > d ) where U : new ( )
{
U r = default ( U ) ;
if ( ! d . TryGetValue ( t , out r ) )
{
r = new U ( ) ;
d [ t ] = r ;
}
return r ;
}
public List < T > GetSortedList < T > ( Dictionary < T , int > d )
{
var kvps = d . ToList ( ) ;
kvps . Sort ( ( a , b ) = > { return b . Value . CompareTo ( a . Value ) ; } ) ;
return kvps . Select ( ( a ) = > { return a . Key ; } ) . ToList ( ) ;
}
}
private struct ShaderXmlVertexLayout
{
public VertexDeclarationTypes Types { get ; set ; }
public uint Flags { get ; set ; }
public VertexType VertexType { get { return ( VertexType ) Flags ; } }
public override string ToString ( )
{
return Types . ToString ( ) + ", " + VertexType . ToString ( ) ;
}
}
2017-09-21 18:33:05 +08:00
}
}