mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-17 04:22:54 +08:00
Update to .NET 6
Added Span support in some places already, and changed Nullable to annotations to declare intent to enable nullable at some point in the future
This commit is contained in:
parent
ba72dadd16
commit
8c2e444049
@ -2,27 +2,25 @@
|
|||||||
using BenchmarkDotNet.Configs;
|
using BenchmarkDotNet.Configs;
|
||||||
using BenchmarkDotNet.Environments;
|
using BenchmarkDotNet.Environments;
|
||||||
using BenchmarkDotNet.Jobs;
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using CodeWalker.Core.Utils;
|
||||||
using CodeWalker.GameFiles;
|
using CodeWalker.GameFiles;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers.Binary;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace CodeWalker.Benchmarks
|
namespace CodeWalker.Benchmarks
|
||||||
{
|
{
|
||||||
[MemoryDiagnoser]
|
[MemoryDiagnoser]
|
||||||
[Config(typeof(JitsConfig))]
|
|
||||||
public class Benchmarks
|
public class Benchmarks
|
||||||
{
|
{
|
||||||
private class JitsConfig : ManualConfig
|
public const string markup = @"<CVehicleModelInfo__InitDataList>
|
||||||
{
|
|
||||||
public JitsConfig()
|
|
||||||
{
|
|
||||||
AddJob(Job.Default.WithJit(Jit.RyuJit).WithPlatform(Platform.X64));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static string markup = @"<CVehicleModelInfo__InitDataList>
|
|
||||||
<residentTxd>vehshare</residentTxd>
|
<residentTxd>vehshare</residentTxd>
|
||||||
<residentAnims />
|
<residentAnims />
|
||||||
<InitDatas>
|
<InitDatas>
|
||||||
@ -179,22 +177,39 @@ namespace CodeWalker.Benchmarks
|
|||||||
[GlobalSetup]
|
[GlobalSetup]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
{
|
||||||
data = Encoding.UTF8.GetBytes(markup);
|
data = new byte[2048];
|
||||||
fileEntry = RpfFile.CreateFileEntry("kaas.meta", "saak.meta", ref data);
|
var random = new Random(42);
|
||||||
|
for (int i = 0; i < data.Length; i++)
|
||||||
|
{
|
||||||
|
data[i] = (byte)random.Next(byte.MinValue, byte.MaxValue);
|
||||||
|
}
|
||||||
|
GTA5Keys.LoadFromPath("C:\\Program Files\\Rockstar Games\\Grand Theft Auto V", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark(Baseline = true)]
|
//[Benchmark(Baseline = true)]
|
||||||
public void RunLoad()
|
//public void RunLoad()
|
||||||
|
//{
|
||||||
|
// var vehiclesFileExpected = new VehiclesFile();
|
||||||
|
// vehiclesFileExpected.LoadOld(data, fileEntry);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//[Benchmark]
|
||||||
|
//public void RunLoadNew()
|
||||||
|
//{
|
||||||
|
// var vehiclesFile = new VehiclesFile();
|
||||||
|
// vehiclesFile.Load(data, fileEntry);
|
||||||
|
//}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public void DecryptNGSpan()
|
||||||
{
|
{
|
||||||
var vehiclesFileExpected = new VehiclesFile();
|
GTACrypto.DecryptNG(data.AsSpan(), "kaas", 2048);
|
||||||
vehiclesFileExpected.LoadOld(data, fileEntry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Benchmark]
|
[Benchmark]
|
||||||
public void RunLoadNew()
|
public void DecryptNG()
|
||||||
{
|
{
|
||||||
var vehiclesFile = new VehiclesFile();
|
GTACrypto.DecryptNG(data, "kaas", 2048);
|
||||||
vehiclesFile.Load(data, fileEntry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,201 +1,55 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.3.0.2\build\Microsoft.Diagnostics.Tracing.TraceEvent.props" Condition="Exists('..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.3.0.2\build\Microsoft.Diagnostics.Tracing.TraceEvent.props')" />
|
|
||||||
<Import Project="..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\build\Microsoft.CodeAnalysis.Analyzers.props" Condition="Exists('..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\build\Microsoft.CodeAnalysis.Analyzers.props')" />
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}</ProjectGuid>
|
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RootNamespace>CodeWalker.Benchmarks</RootNamespace>
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
<AssemblyName>CodeWalker.Benchmarks</AssemblyName>
|
<AssemblyTitle>CodeWalker.Benchmarks</AssemblyTitle>
|
||||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
<Product>CodeWalker.Benchmarks</Product>
|
||||||
<FileAlignment>512</FileAlignment>
|
<Copyright>Copyright © 2023</Copyright>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||||
<Deterministic>true</Deterministic>
|
<FileVersion>1.0.0.0</FileVersion>
|
||||||
<NuGetPackageImportStamp>
|
<LangVersion>latest</LangVersion>
|
||||||
</NuGetPackageImportStamp>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="BenchmarkDotNet, Version=0.13.10.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\BenchmarkDotNet.0.13.10\lib\netstandard2.0\BenchmarkDotNet.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="BenchmarkDotNet.Annotations, Version=0.13.10.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\BenchmarkDotNet.Annotations.0.13.10\lib\netstandard2.0\BenchmarkDotNet.Annotations.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="CommandLine, Version=2.9.1.0, Culture=neutral, PublicKeyToken=5a870481e358d379, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\CommandLineParser.2.9.1\lib\net461\CommandLine.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Dia2Lib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.3.0.2\lib\net462\Dia2Lib.dll</HintPath>
|
|
||||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Gee.External.Capstone, Version=2.3.0.0, Culture=neutral, PublicKeyToken=b117d7a2dc33ffa6, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Gee.External.Capstone.2.3.0\lib\netstandard2.0\Gee.External.Capstone.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Iced, Version=1.17.0.0, Culture=neutral, PublicKeyToken=5baba79f4264913b, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Iced.1.17.0\lib\net45\Iced.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.CodeAnalysis, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.4.1.0\lib\netstandard2.0\Microsoft.CodeAnalysis.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.4.1.0\lib\netstandard2.0\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Diagnostics.FastSerialization, Version=3.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.3.0.2\lib\net462\Microsoft.Diagnostics.FastSerialization.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Diagnostics.NETCore.Client, Version=0.2.5.1802, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Diagnostics.NETCore.Client.0.2.251802\lib\netstandard2.0\Microsoft.Diagnostics.NETCore.Client.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Diagnostics.Runtime, Version=2.2.6.32302, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Diagnostics.Runtime.2.2.332302\lib\netstandard2.0\Microsoft.Diagnostics.Runtime.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Diagnostics.Tracing.TraceEvent, Version=3.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.3.0.2\lib\net462\Microsoft.Diagnostics.Tracing.TraceEvent.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.DotNet.PlatformAbstractions, Version=3.1.6.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.DotNet.PlatformAbstractions.3.1.6\lib\net45\Microsoft.DotNet.PlatformAbstractions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Extensions.Configuration, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Configuration.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Extensions.Configuration.Binder, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Extensions.Logging, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Logging.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Extensions.Options, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Options.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Extensions.Primitives, Version=2.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Extensions.Primitives.2.1.1\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.Win32.Registry, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Win32.Registry.5.0.0\lib\net461\Microsoft.Win32.Registry.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="OSExtensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.3.0.2\lib\net462\OSExtensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Perfolizer, Version=0.2.1.0, Culture=neutral, PublicKeyToken=e864f2ec9c0b6d4c, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Perfolizer.0.2.1\lib\netstandard2.0\Perfolizer.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="SharpDX, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\SharpDX.4.2.0\lib\net45\SharpDX.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="SharpDX.Mathematics, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\SharpDX.Mathematics.4.2.0\lib\net45\SharpDX.Mathematics.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System" />
|
|
||||||
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Collections.Immutable, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Collections.Immutable.5.0.0\lib\net461\System.Collections.Immutable.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Management" />
|
|
||||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Numerics" />
|
|
||||||
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Reflection.Metadata, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Reflection.Metadata.5.0.0\lib\net461\System.Reflection.Metadata.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.5.0.0\lib\net45\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.0.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
|
|
||||||
<Private>True</Private>
|
|
||||||
<Private>True</Private>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.AccessControl, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Security.AccessControl.5.0.0\lib\net461\System.Security.AccessControl.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Security.Principal.Windows, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Security.Principal.Windows.5.0.0\lib\net461\System.Security.Principal.Windows.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Text.Encoding.CodePages, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Text.Encoding.CodePages.4.5.1\lib\net461\System.Text.Encoding.CodePages.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Net.Http" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
<Reference Include="TraceReloggerLib, Version=0.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
|
||||||
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.3.0.2\lib\net462\TraceReloggerLib.dll</HintPath>
|
|
||||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Benchmarks.cs" />
|
|
||||||
<Compile Include="Program.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="App.config" />
|
|
||||||
<None Include="packages.config" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" />
|
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" />
|
||||||
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
|
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj">
|
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj" />
|
||||||
<Project>{FF6B9F41-14BE-474E-9ED0-549C3BEB7E00}</Project>
|
</ItemGroup>
|
||||||
<Name>CodeWalker.Core</Name>
|
<ItemGroup>
|
||||||
</ProjectReference>
|
<PackageReference Include="BenchmarkDotNet" Version="0.13.10" />
|
||||||
|
<PackageReference Include="BenchmarkDotNet.Annotations" Version="0.13.10" />
|
||||||
|
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||||
|
<PackageReference Include="Gee.External.Capstone" Version="2.3.0" />
|
||||||
|
<PackageReference Include="Iced" Version="1.17.0" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.1.0" />
|
||||||
|
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||||
|
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.251802" />
|
||||||
|
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.2.332302" />
|
||||||
|
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.DotNet.PlatformAbstractions" Version="3.1.6" />
|
||||||
|
<PackageReference Include="Perfolizer" Version="0.2.1" />
|
||||||
|
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||||
|
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
|
||||||
|
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.4" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options" Version="6.0.0" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Primitives" Version="6.0.0" />
|
||||||
|
<PackageReference Include="System.Collections.Immutable" Version="6.0.0" />
|
||||||
|
<PackageReference Include="System.Management" Version="6.0.2" />
|
||||||
|
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||||
|
<PackageReference Include="System.Reflection.Metadata" Version="6.0.1" />
|
||||||
|
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||||
|
<PackageReference Include="System.Security.AccessControl" Version="6.0.0" />
|
||||||
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
|
|
||||||
<PropertyGroup>
|
|
||||||
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
|
|
||||||
</PropertyGroup>
|
|
||||||
<Error Condition="!Exists('..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\build\Microsoft.CodeAnalysis.Analyzers.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\build\Microsoft.CodeAnalysis.Analyzers.props'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\build\Microsoft.CodeAnalysis.Analyzers.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\build\Microsoft.CodeAnalysis.Analyzers.targets'))" />
|
|
||||||
<Error Condition="!Exists('..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.3.0.2\build\Microsoft.Diagnostics.Tracing.TraceEvent.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.3.0.2\build\Microsoft.Diagnostics.Tracing.TraceEvent.props'))" />
|
|
||||||
</Target>
|
|
||||||
<Import Project="..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\build\Microsoft.CodeAnalysis.Analyzers.targets" Condition="Exists('..\packages\Microsoft.CodeAnalysis.Analyzers.3.3.3\build\Microsoft.CodeAnalysis.Analyzers.targets')" />
|
|
||||||
</Project>
|
</Project>
|
@ -2,15 +2,33 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using static System.Reflection.Metadata.BlobBuilder;
|
||||||
|
|
||||||
namespace CodeWalker.Benchmarks
|
namespace CodeWalker.Benchmarks
|
||||||
{
|
{
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
|
//var benchmarks = new Benchmarks();
|
||||||
|
|
||||||
|
//benchmarks.Setup();
|
||||||
|
//benchmarks.ToUInt64();
|
||||||
|
//benchmarks.ReadUInt64LittleEndian();
|
||||||
|
//benchmarks.ReadUInt64BigEndian();
|
||||||
|
//benchmarks.ToUIntBigEndian();
|
||||||
|
//benchmarks.HtmlEncode();
|
||||||
|
|
||||||
|
//benchmarks.GlobalCleanup();
|
||||||
|
|
||||||
|
//ParseBuffer();
|
||||||
|
|
||||||
BenchmarkRunner.Run<Benchmarks>();
|
BenchmarkRunner.Run<Benchmarks>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,6 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("CodeWalker.Benchmarks")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("CodeWalker.Benchmarks")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2023")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
[assembly: AssemblyTrademark("")]
|
||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
@ -21,16 +11,3 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
[assembly: Guid("edda8a8e-5333-4e28-8221-a31e3b70eb7a")]
|
[assembly: Guid("edda8a8e-5333-4e28-8221-a31e3b70eb7a")]
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
|
||||||
[assembly: AssemblyVersion("1.0.0.0")]
|
|
||||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
||||||
|
@ -1,42 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<packages>
|
|
||||||
<package id="BenchmarkDotNet" version="0.13.10" targetFramework="net48" />
|
|
||||||
<package id="BenchmarkDotNet.Annotations" version="0.13.10" targetFramework="net48" />
|
|
||||||
<package id="CommandLineParser" version="2.9.1" targetFramework="net48" />
|
|
||||||
<package id="Gee.External.Capstone" version="2.3.0" targetFramework="net48" />
|
|
||||||
<package id="Iced" version="1.17.0" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.1.0" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.CodeAnalysis.Analyzers" version="3.3.3" targetFramework="net48" developmentDependency="true" />
|
|
||||||
<package id="Microsoft.CodeAnalysis.Common" version="4.1.0" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.CodeAnalysis.CSharp" version="4.1.0" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Diagnostics.NETCore.Client" version="0.2.251802" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Diagnostics.Runtime" version="2.2.332302" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Diagnostics.Tracing.TraceEvent" version="3.0.2" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.DotNet.PlatformAbstractions" version="3.1.6" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Extensions.Configuration" version="2.1.1" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Extensions.Configuration.Abstractions" version="2.1.1" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Extensions.Configuration.Binder" version="2.1.1" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.1.1" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Extensions.Logging" version="2.1.1" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Extensions.Logging.Abstractions" version="2.1.1" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Extensions.Options" version="2.1.1" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Extensions.Primitives" version="2.1.1" targetFramework="net48" />
|
|
||||||
<package id="Microsoft.Win32.Registry" version="5.0.0" targetFramework="net48" />
|
|
||||||
<package id="Perfolizer" version="0.2.1" targetFramework="net48" />
|
|
||||||
<package id="SharpDX" version="4.2.0" targetFramework="net48" />
|
|
||||||
<package id="SharpDX.Mathematics" version="4.2.0" targetFramework="net48" />
|
|
||||||
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
|
|
||||||
<package id="System.Collections.Immutable" version="5.0.0" targetFramework="net48" />
|
|
||||||
<package id="System.Management" version="5.0.0" targetFramework="net48" />
|
|
||||||
<package id="System.Memory" version="4.5.4" targetFramework="net48" />
|
|
||||||
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net48" />
|
|
||||||
<package id="System.Reflection.Emit" version="4.7.0" targetFramework="net48" />
|
|
||||||
<package id="System.Reflection.Emit.Lightweight" version="4.7.0" targetFramework="net48" />
|
|
||||||
<package id="System.Reflection.Metadata" version="5.0.0" targetFramework="net48" />
|
|
||||||
<package id="System.Runtime.CompilerServices.Unsafe" version="5.0.0" targetFramework="net48" />
|
|
||||||
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.0.0" targetFramework="net48" />
|
|
||||||
<package id="System.Security.AccessControl" version="5.0.0" targetFramework="net48" />
|
|
||||||
<package id="System.Security.Principal.Windows" version="5.0.0" targetFramework="net48" />
|
|
||||||
<package id="System.Text.Encoding.CodePages" version="4.5.1" targetFramework="net48" />
|
|
||||||
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
|
|
||||||
</packages>
|
|
@ -1,30 +1,27 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<Nullable>annotations</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
|
<PackageReference Include="DirectXTexNet" Version="1.0.3" />
|
||||||
<PackageReference Include="DirectXTexNet" Version="1.0.1" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
<PackageReference Include="directxtex_desktop_win10" Version="2023.3.30.1" />
|
|
||||||
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
|
|
||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="RequiredMemberAttribute" Version="1.0.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="SharpDX" Version="4.2.0" />
|
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||||
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
|
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
<PackageReference Include="System.Diagnostics.Tracing" Version="4.3.0" />
|
||||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Properties\" />
|
<Folder Include="Properties\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="Resources\magic.dat" />
|
<Resource Include="Resources\magic.dat" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
|||||||
using TC = System.ComponentModel.TypeConverterAttribute;
|
using TC = System.ComponentModel.TypeConverterAttribute;
|
||||||
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
{
|
{
|
||||||
@ -39,12 +40,12 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public Dictionary<uint, AwcStream> StreamDict { get; set; }
|
public Dictionary<uint, AwcStream> StreamDict { get; set; }
|
||||||
|
|
||||||
|
static public void Decrypt_RSXXTEA(Span<byte> data, uint[] key)
|
||||||
static public void Decrypt_RSXXTEA(byte[] data, uint[] key)
|
|
||||||
{
|
{
|
||||||
// Rockstar's modified version of XXTEA
|
// Rockstar's modified version of XXTEA
|
||||||
uint[] blocks = new uint[data.Length / 4];
|
var blocks = MemoryMarshal.Cast<byte, uint>(data);
|
||||||
Buffer.BlockCopy(data, 0, blocks, 0, data.Length);
|
//[] blocks = new uint[data.Length / 4];
|
||||||
|
//Buffer.BlockCopy(data, 0, blocks, 0, data.Length);
|
||||||
|
|
||||||
int block_count = blocks.Length;
|
int block_count = blocks.Length;
|
||||||
uint a, b = blocks[0], i;
|
uint a, b = blocks[0], i;
|
||||||
@ -60,7 +61,7 @@ namespace CodeWalker.GameFiles
|
|||||||
i -= 0x9E3779B9;
|
i -= 0x9E3779B9;
|
||||||
} while (i != 0);
|
} while (i != 0);
|
||||||
|
|
||||||
Buffer.BlockCopy(blocks, 0, data, 0, data.Length);
|
//Buffer.BlockCopy(blocks, 0, data, 0, data.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Load(byte[] data, RpfFileEntry entry)
|
public void Load(byte[] data, RpfFileEntry entry)
|
||||||
@ -1171,15 +1172,13 @@ namespace CodeWalker.GameFiles
|
|||||||
for (int b = 0; b < bcount; b++)
|
for (int b = 0; b < bcount; b++)
|
||||||
{
|
{
|
||||||
int srcoff = b * bsize;
|
int srcoff = b * bsize;
|
||||||
int mcsoff = (b < ocount) ? (int)SeekTableChunk.SeekTable[b] : 0;
|
int sampleOffset = (b < ocount) ? (int)SeekTableChunk.SeekTable[b] : 0;
|
||||||
int blen = Math.Max(Math.Min(bsize, DataChunk.Data.Length - srcoff), 0);
|
int dataBlockLength = Math.Max(Math.Min(bsize, DataChunk.Data.Length - srcoff), 0);
|
||||||
var bdat = new byte[blen];
|
|
||||||
Buffer.BlockCopy(DataChunk.Data, srcoff, bdat, 0, blen);
|
|
||||||
if (Awc.MultiChannelEncryptFlag && !Awc.WholeFileEncrypted)
|
if (Awc.MultiChannelEncryptFlag && !Awc.WholeFileEncrypted)
|
||||||
{
|
{
|
||||||
AwcFile.Decrypt_RSXXTEA(bdat, GTA5Keys.PC_AWC_KEY);
|
AwcFile.Decrypt_RSXXTEA(DataChunk.Data.AsSpan(srcoff, dataBlockLength), GTA5Keys.PC_AWC_KEY);
|
||||||
}
|
}
|
||||||
var blk = new AwcStreamDataBlock(bdat, StreamFormatChunk, endianess, mcsoff);
|
var blk = new AwcStreamDataBlock(DataChunk.Data, StreamFormatChunk, endianess, sampleOffset, srcoff, dataBlockLength);
|
||||||
blist.Add(blk);
|
blist.Add(blk);
|
||||||
}
|
}
|
||||||
StreamBlocks = blist.ToArray();
|
StreamBlocks = blist.ToArray();
|
||||||
@ -2712,21 +2711,22 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public AwcStreamDataBlock()
|
public AwcStreamDataBlock()
|
||||||
{ }
|
{ }
|
||||||
public AwcStreamDataBlock(byte[] data, AwcStreamFormatChunk channelInfo, Endianess endianess, int sampleOffset)
|
public AwcStreamDataBlock(byte[] data, AwcStreamFormatChunk channelInfo, Endianess endianess, int sampleOffset) : this(data, channelInfo, endianess, sampleOffset, 0, data?.Length ?? 0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public AwcStreamDataBlock(byte[] data, AwcStreamFormatChunk channelInfo, Endianess endianess, int sampleOffset, int offset, int dataLength)
|
||||||
{
|
{
|
||||||
DataLength = data?.Length ?? 0;
|
DataLength = dataLength;
|
||||||
SampleOffset = sampleOffset;
|
SampleOffset = sampleOffset;
|
||||||
ChannelCount = channelInfo?.ChannelCount ?? 0;
|
ChannelCount = channelInfo?.ChannelCount ?? 0;
|
||||||
ChannelInfo = channelInfo;
|
ChannelInfo = channelInfo;
|
||||||
|
|
||||||
using (var ms = new MemoryStream(data))
|
using var ms = new MemoryStream(data, offset, dataLength);
|
||||||
{
|
|
||||||
var r = new DataReader(ms, endianess);
|
var r = new DataReader(ms, endianess);
|
||||||
Read(r);
|
Read(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Read(DataReader r)
|
public void Read(DataReader r)
|
||||||
{
|
{
|
||||||
var ilist = new List<AwcStreamDataChannel>();
|
var ilist = new List<AwcStreamDataChannel>();
|
||||||
@ -2744,7 +2744,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
var padc = (0x800 - (r.Position % 0x800)) % 0x800;
|
var padc = (0x800 - (r.Position % 0x800)) % 0x800;
|
||||||
var padb = r.ReadBytes((int)padc);
|
r.Position += padc;
|
||||||
|
|
||||||
foreach (var channel in Channels)
|
foreach (var channel in Channels)
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,7 @@ using System.ComponentModel;
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
@ -31,25 +32,30 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
FileEntry = entry;
|
FileEntry = entry;
|
||||||
|
|
||||||
MemoryStream ms = new MemoryStream(data);
|
using MemoryStream ms = new MemoryStream(data);
|
||||||
BinaryReader br = new BinaryReader(ms);
|
using BinaryReader br = new BinaryReader(ms);
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
Span<char> charArr = stackalloc char[100];
|
||||||
|
var length = 0;
|
||||||
for (int i = 0; (i < 100) && (i < data.Length); i++)
|
for (int i = 0; (i < 100) && (i < data.Length); i++)
|
||||||
{
|
{
|
||||||
//read version string.
|
//read version string.
|
||||||
byte b = data[i];
|
byte b = data[i];
|
||||||
if (b == 0) break;
|
if (b == 0)
|
||||||
sb.Append((char)b);
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Version = sb.ToString().Replace("[VERSION]", "").Replace("\r", "").Replace("\n", "");
|
|
||||||
sb.Clear();
|
charArr[i] = (char)b;
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
Version = new string(charArr.Slice(0, length)).Replace("[VERSION]", "").Replace("\r", "").Replace("\n", "");
|
||||||
|
length = 0;
|
||||||
int lastn = 0;
|
int lastn = 0;
|
||||||
int lspos = 0;
|
int lspos = 0;
|
||||||
uint structcount = 0;
|
uint structcount = 0;
|
||||||
uint modlen;
|
uint modlen;
|
||||||
bool indates = false;
|
bool indates = false;
|
||||||
List<string> lines = new List<string>();
|
|
||||||
var dates = new List<CacheFileDate>();
|
var dates = new List<CacheFileDate>();
|
||||||
var allMapNodes = new List<MapDataStoreNode>();
|
var allMapNodes = new List<MapDataStoreNode>();
|
||||||
var allCInteriorProxies = new List<CInteriorProxy>();
|
var allCInteriorProxies = new List<CInteriorProxy>();
|
||||||
@ -62,9 +68,8 @@ namespace CodeWalker.GameFiles
|
|||||||
if (b == 0xA)
|
if (b == 0xA)
|
||||||
{
|
{
|
||||||
lastn = i;
|
lastn = i;
|
||||||
string line = sb.ToString();
|
string line = new string(charArr.Slice(0, length));
|
||||||
lines.Add(line);
|
switch (charArr.Slice(0, length))
|
||||||
switch (line)
|
|
||||||
{
|
{
|
||||||
case "<fileDates>":
|
case "<fileDates>":
|
||||||
indates = true;
|
indates = true;
|
||||||
@ -125,11 +130,12 @@ namespace CodeWalker.GameFiles
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
sb.Clear();
|
length = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sb.Append((char)b);
|
charArr[length] = (char)b;
|
||||||
|
length++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FileDates = dates.ToArray();
|
FileDates = dates.ToArray();
|
||||||
|
@ -55,7 +55,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
using (MemoryStream ms = new MemoryStream(data))
|
using (MemoryStream ms = new MemoryStream(data))
|
||||||
{
|
{
|
||||||
DataReader r = new DataReader(ms, Endianess.LittleEndian);
|
DataReader r = new DataReader(ms);
|
||||||
|
|
||||||
Read(r);
|
Read(r);
|
||||||
};
|
};
|
||||||
|
@ -16,6 +16,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
[TC(typeof(EXP))] public class PedsFile : GameFile, PackedFile
|
[TC(typeof(EXP))] public class PedsFile : GameFile, PackedFile
|
||||||
{
|
{
|
||||||
|
private static XmlNameTable cachedNameTable = new System.Xml.NameTable();
|
||||||
public PsoFile Pso { get; set; }
|
public PsoFile Pso { get; set; }
|
||||||
public string Xml { get; set; }
|
public string Xml { get; set; }
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ namespace CodeWalker.GameFiles
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
using var xmlReader = XmlReader.Create(textReader);
|
using var xmlReader = XmlReader.Create(textReader, new XmlReaderSettings { NameTable = cachedNameTable, });
|
||||||
|
|
||||||
|
|
||||||
//if (xdoc.DocumentElement != null)
|
//if (xdoc.DocumentElement != null)
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@ using System.Collections;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -15,7 +16,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
public class VehiclesFile : GameFile, PackedFile
|
public class VehiclesFile : GameFile, PackedFile
|
||||||
{
|
{
|
||||||
|
private static XmlNameTable cachedNameTable = new NameTable();
|
||||||
|
|
||||||
public string ResidentTxd { get; set; }
|
public string ResidentTxd { get; set; }
|
||||||
public List<VehicleInitData> InitDatas { get; set; }
|
public List<VehicleInitData> InitDatas { get; set; }
|
||||||
@ -69,7 +70,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
using var textReader = new StreamReader(new MemoryStream(data), Encoding.UTF8);
|
using var textReader = new StreamReader(new MemoryStream(data), Encoding.UTF8);
|
||||||
|
|
||||||
using var xmlReader = XmlReader.Create(textReader);
|
using var xmlReader = XmlReader.Create(textReader, new XmlReaderSettings { NameTable = cachedNameTable });
|
||||||
|
|
||||||
while (xmlReader.Read())
|
while (xmlReader.Read())
|
||||||
{
|
{
|
||||||
@ -838,30 +839,27 @@ namespace CodeWalker.GameFiles
|
|||||||
return GetStringArray(ldastr, delimiter);
|
return GetStringArray(ldastr, delimiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe float[] GetFloatArray(string ldastr, char delimiter)
|
[SkipLocalsInit]
|
||||||
|
private float[] GetFloatArray(string ldastr, char delimiter)
|
||||||
{
|
{
|
||||||
var ldarr = ldastr?.Split(delimiter);
|
var ldarr = ldastr?.Split(delimiter);
|
||||||
if (ldarr == null) return null;
|
if (ldarr == null) return null;
|
||||||
var floats = stackalloc float[ldarr.Length];
|
Span<float> floats = stackalloc float[ldarr.Length];
|
||||||
var i = 0;
|
var i = 0;
|
||||||
foreach (var ldstr in ldarr)
|
foreach (var ldstr in ldarr)
|
||||||
{
|
{
|
||||||
var ldt = ldstr?.Trim();
|
var ldt = ldstr?.Trim();
|
||||||
if (!string.IsNullOrEmpty(ldt))
|
if (!string.IsNullOrEmpty(ldt) && FloatUtil.TryParse(ldt, out var f))
|
||||||
{
|
|
||||||
float f;
|
|
||||||
if (FloatUtil.TryParse(ldt, out f))
|
|
||||||
{
|
{
|
||||||
floats[i] = f;
|
floats[i] = f;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (i == 0) return null;
|
if (i == 0) return null;
|
||||||
|
|
||||||
var result = new float[i];
|
var result = new float[i];
|
||||||
|
|
||||||
Marshal.Copy((IntPtr)floats, result, 0, i);
|
floats.Slice(0, i).CopyTo(result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -3285,13 +3285,16 @@ namespace CodeWalker.GameFiles
|
|||||||
public class YmapOccludeModel : BasePathData
|
public class YmapOccludeModel : BasePathData
|
||||||
{
|
{
|
||||||
public OccludeModel _OccludeModel;
|
public OccludeModel _OccludeModel;
|
||||||
|
|
||||||
public OccludeModel OccludeModel { get { return _OccludeModel; } set { _OccludeModel = value; } }
|
public OccludeModel OccludeModel { get { return _OccludeModel; } set { _OccludeModel = value; } }
|
||||||
|
|
||||||
public YmapFile Ymap { get; set; }
|
public YmapFile Ymap { get; set; }
|
||||||
|
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
public Vector3[] Vertices { get; set; }
|
private int vertexCount;
|
||||||
public byte[] Indices { get; set; }
|
private int indicesOffset { get => vertexCount * 12; }
|
||||||
|
public Span<Vector3> Vertices { get => MetaTypes.ConvertDataArray<Vector3>(Data, 0, vertexCount); }
|
||||||
|
public Span<byte> Indices { get => Data.AsSpan(indicesOffset); }
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
|
|
||||||
public YmapOccludeModelTriangle[] Triangles { get; set; }
|
public YmapOccludeModelTriangle[] Triangles { get; set; }
|
||||||
@ -3321,12 +3324,12 @@ namespace CodeWalker.GameFiles
|
|||||||
var vptr = _OccludeModel.verts;
|
var vptr = _OccludeModel.verts;
|
||||||
var dataSize = _OccludeModel.dataSize;
|
var dataSize = _OccludeModel.dataSize;
|
||||||
var indicesOffset = _OccludeModel.numVertsInBytes;
|
var indicesOffset = _OccludeModel.numVertsInBytes;
|
||||||
var vertexCount = indicesOffset / 12;
|
vertexCount = indicesOffset / 12;
|
||||||
var indexCount = (int)(dataSize - indicesOffset);// / 4;
|
var indexCount = (int)(dataSize - indicesOffset);// / 4;
|
||||||
Data = MetaTypes.GetByteArray(meta, vptr, dataSize);
|
Data = MetaTypes.GetByteArray(meta, vptr, dataSize);
|
||||||
Vertices = MetaTypes.ConvertDataArray<Vector3>(Data, 0, vertexCount).ToArray();
|
//Vertices = MetaTypes.ConvertDataArray<Vector3>(Data, 0, vertexCount).ToArray();
|
||||||
Indices = new byte[indexCount];
|
//Indices = new byte[indexCount];
|
||||||
Buffer.BlockCopy(Data, indicesOffset, Indices, 0, indexCount);
|
//Buffer.BlockCopy(Data, indicesOffset, Indices, 0, indexCount);
|
||||||
BuildTriangles();
|
BuildTriangles();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3362,10 +3365,11 @@ namespace CodeWalker.GameFiles
|
|||||||
//create vertices and indices arrays from Triangles
|
//create vertices and indices arrays from Triangles
|
||||||
if (Triangles == null)
|
if (Triangles == null)
|
||||||
{
|
{
|
||||||
Vertices = null;
|
|
||||||
Indices = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var vdict = new Dictionary<Vector3, byte>();
|
var vdict = new Dictionary<Vector3, byte>();
|
||||||
var verts = new List<Vector3>();
|
var verts = new List<Vector3>();
|
||||||
var inds = new List<byte>();
|
var inds = new List<byte>();
|
||||||
@ -3391,21 +3395,40 @@ namespace CodeWalker.GameFiles
|
|||||||
inds.Add(ensureVert(tri.Corner2));
|
inds.Add(ensureVert(tri.Corner2));
|
||||||
inds.Add(ensureVert(tri.Corner3));
|
inds.Add(ensureVert(tri.Corner3));
|
||||||
}
|
}
|
||||||
Vertices = verts.ToArray();
|
|
||||||
Indices = inds.ToArray();
|
var newVertsSize = Vector3.SizeInBytes * verts.Count;
|
||||||
|
var newIndicesSize = Marshal.SizeOf<byte>() * inds.Count;
|
||||||
|
|
||||||
|
if (newVertsSize + newIndicesSize != Data.Length)
|
||||||
|
{
|
||||||
|
Data = new byte[newVertsSize + newIndicesSize];
|
||||||
|
}
|
||||||
|
vertexCount = verts.Count;
|
||||||
|
for (int i = 0; i < verts.Count; i++)
|
||||||
|
{
|
||||||
|
Vertices[i] = verts[i];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < inds.Count; i++)
|
||||||
|
{
|
||||||
|
Indices[i] = inds[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
public void BuildData()
|
public void BuildData()
|
||||||
{
|
{
|
||||||
//create Data from vertices and indices arrays
|
//create Data from vertices and indices arrays
|
||||||
if (Vertices == null) return;
|
if (Vertices == null) return;
|
||||||
if (Indices == null) return;
|
if (Indices == null) return;
|
||||||
var dlen = (Vertices.Length * 12) + (Indices.Length * 1);
|
var dlen = (Vertices.Length * Vector3.SizeInBytes) + (Indices.Length * 1);
|
||||||
var d = new byte[dlen];
|
if (dlen != Data.Length)
|
||||||
var vbytes = MetaTypes.ConvertArrayToBytes(Vertices);
|
{
|
||||||
var ibytes = Indices;
|
throw new InvalidOperationException("Size mismatch in YmapOccludeModel BuildData");
|
||||||
Buffer.BlockCopy(vbytes, 0, d, 0, vbytes.Length);
|
}
|
||||||
Buffer.BlockCopy(ibytes, 0, d, vbytes.Length, ibytes.Length);
|
//var d = new byte[dlen];
|
||||||
Data = d;
|
//var vbytes = MetaTypes.ConvertArrayToBytes(Vertices);
|
||||||
|
//var ibytes = Indices;
|
||||||
|
//Buffer.BlockCopy(vbytes, 0, d, 0, vbytes.Length);
|
||||||
|
//Buffer.BlockCopy(ibytes, 0, d, vbytes.Length, ibytes.Length);
|
||||||
|
//Data = d;
|
||||||
var min = new Vector3(float.MaxValue);
|
var min = new Vector3(float.MaxValue);
|
||||||
var max = new Vector3(float.MinValue);
|
var max = new Vector3(float.MinValue);
|
||||||
for (int i = 0; i < Vertices.Length; i++)
|
for (int i = 0; i < Vertices.Length; i++)
|
||||||
@ -3418,8 +3441,8 @@ namespace CodeWalker.GameFiles
|
|||||||
_OccludeModel.Unused0 = min.X;
|
_OccludeModel.Unused0 = min.X;
|
||||||
_OccludeModel.Unused1 = max.X;
|
_OccludeModel.Unused1 = max.X;
|
||||||
_OccludeModel.dataSize = (uint)dlen;
|
_OccludeModel.dataSize = (uint)dlen;
|
||||||
_OccludeModel.numVertsInBytes = (ushort)vbytes.Length;
|
_OccludeModel.numVertsInBytes = (ushort)(vertexCount * Vector3.SizeInBytes);
|
||||||
_OccludeModel.numTris = (ushort)((ibytes.Length / 3) + 32768);//is this actually a flag lurking..?
|
_OccludeModel.numTris = (ushort)((Indices.Length / 3) + 32768);//is this actually a flag lurking..?
|
||||||
//_OccludeModel.flags = ...
|
//_OccludeModel.flags = ...
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3462,7 +3485,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return Index.ToString() + ": " + (Vertices?.Length ?? 0).ToString() + " vertices, " + (Triangles?.Length ?? 0).ToString() + " triangles";
|
return Index.ToString() + ": " + Vertices.Length.ToString() + " vertices, " + (Triangles?.Length ?? 0).ToString() + " triangles";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
using (MemoryStream ms = new MemoryStream(data))
|
using (MemoryStream ms = new MemoryStream(data))
|
||||||
{
|
{
|
||||||
DataReader r = new DataReader(ms, Endianess.LittleEndian);
|
DataReader r = new DataReader(ms);
|
||||||
|
|
||||||
Read(r);
|
Read(r);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
using CodeWalker.Core.Utils;
|
using CodeWalker.Core.Utils;
|
||||||
using CodeWalker.World;
|
|
||||||
using Dasync.Collections;
|
|
||||||
using SharpDX;
|
using SharpDX;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@ -92,15 +90,15 @@ namespace CodeWalker.GameFiles
|
|||||||
public Dictionary<MetaHash, Dictionary<MetaHash, RpfFileEntry>> PedClothDicts { get; set; }
|
public Dictionary<MetaHash, Dictionary<MetaHash, RpfFileEntry>> PedClothDicts { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public List<RelFile> AudioDatRelFiles = new List<RelFile>();
|
public List<RelFile> AudioDatRelFiles;
|
||||||
public Dictionary<MetaHash, RelData> AudioConfigDict = new Dictionary<MetaHash, RelData>();
|
public Dictionary<MetaHash, RelData> AudioConfigDict;
|
||||||
public Dictionary<MetaHash, RelData> AudioSpeechDict = new Dictionary<MetaHash, RelData>();
|
public Dictionary<MetaHash, RelData> AudioSpeechDict;
|
||||||
public Dictionary<MetaHash, RelData> AudioSynthsDict = new Dictionary<MetaHash, RelData>();
|
public Dictionary<MetaHash, RelData> AudioSynthsDict;
|
||||||
public Dictionary<MetaHash, RelData> AudioMixersDict = new Dictionary<MetaHash, RelData>();
|
public Dictionary<MetaHash, RelData> AudioMixersDict;
|
||||||
public Dictionary<MetaHash, RelData> AudioCurvesDict = new Dictionary<MetaHash, RelData>();
|
public Dictionary<MetaHash, RelData> AudioCurvesDict;
|
||||||
public Dictionary<MetaHash, RelData> AudioCategsDict = new Dictionary<MetaHash, RelData>();
|
public Dictionary<MetaHash, RelData> AudioCategsDict;
|
||||||
public Dictionary<MetaHash, RelData> AudioSoundsDict = new Dictionary<MetaHash, RelData>();
|
public Dictionary<MetaHash, RelData> AudioSoundsDict;
|
||||||
public Dictionary<MetaHash, RelData> AudioGameDict = new Dictionary<MetaHash, RelData>();
|
public Dictionary<MetaHash, RelData> AudioGameDict;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -122,6 +120,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
private string GTAFolder;
|
private string GTAFolder;
|
||||||
private string ExcludeFolders;
|
private string ExcludeFolders;
|
||||||
|
private string Key;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -157,7 +156,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public GameFileCache(long size, double cacheTime, string folder, string dlc, bool mods, string excludeFolders)
|
public GameFileCache(long size, double cacheTime, string folder, string dlc, bool mods, string excludeFolders, string key)
|
||||||
{
|
{
|
||||||
mainCache = new Cache<GameFileCacheKey, GameFile>(size, cacheTime);//2GB is good as default
|
mainCache = new Cache<GameFileCacheKey, GameFile>(size, cacheTime);//2GB is good as default
|
||||||
SelectedDlc = dlc;
|
SelectedDlc = dlc;
|
||||||
@ -165,19 +164,19 @@ namespace CodeWalker.GameFiles
|
|||||||
EnableMods = mods;
|
EnableMods = mods;
|
||||||
GTAFolder = folder;
|
GTAFolder = folder;
|
||||||
ExcludeFolders = excludeFolders;
|
ExcludeFolders = excludeFolders;
|
||||||
|
Key = key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
IsInited = false;
|
//IsInited = false;
|
||||||
|
|
||||||
mainCache.Clear();
|
mainCache.Clear();
|
||||||
|
|
||||||
textureLookup.Clear();
|
//textureLookup.Clear();
|
||||||
|
|
||||||
while (requestQueue.TryDequeue(out _))
|
requestQueue.Clear();
|
||||||
{ } //empty the old queue out...
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetGtaFolder(string folder)
|
public void SetGtaFolder(string folder)
|
||||||
@ -204,6 +203,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (RpfMan == null)
|
if (RpfMan == null)
|
||||||
{
|
{
|
||||||
|
GTA5Keys.LoadFromPath(GTAFolder, Key);
|
||||||
//EnableDlc = !string.IsNullOrEmpty(SelectedDlc);
|
//EnableDlc = !string.IsNullOrEmpty(SelectedDlc);
|
||||||
|
|
||||||
RpfMan = RpfManager.GetInstance();
|
RpfMan = RpfManager.GetInstance();
|
||||||
@ -280,6 +280,8 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArgumentNullException.ThrowIfNull(allRpfs, nameof(allRpfs));
|
||||||
IsIniting = true;
|
IsIniting = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -378,7 +380,7 @@ namespace CodeWalker.GameFiles
|
|||||||
DlcPaths.Clear();
|
DlcPaths.Clear();
|
||||||
if ((dlclistxml == null) || (dlclistxml.DocumentElement == null))
|
if ((dlclistxml == null) || (dlclistxml.DocumentElement == null))
|
||||||
{
|
{
|
||||||
ErrorLog("InitDlcList: Couldn't load " + dlclistpath + ".");
|
ErrorLog?.Invoke("InitDlcList: Couldn't load " + dlclistpath + ".");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -442,7 +444,9 @@ namespace CodeWalker.GameFiles
|
|||||||
RpfFile dlcfile;
|
RpfFile dlcfile;
|
||||||
dlcDict2.TryGetValue(dlcname, out dlcfile);
|
dlcDict2.TryGetValue(dlcname, out dlcfile);
|
||||||
if (dlcfile == null)
|
if (dlcfile == null)
|
||||||
{ continue; }
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
var dlcpath = dlcfile.Path + "\\";
|
var dlcpath = dlcfile.Path + "\\";
|
||||||
var files = updrpffile.GetFiles(relpath, true);
|
var files = updrpffile.GetFiles(relpath, true);
|
||||||
foreach (var file in files)
|
foreach (var file in files)
|
||||||
@ -1052,7 +1056,11 @@ namespace CodeWalker.GameFiles
|
|||||||
YmapDict ??= new Dictionary<uint, RpfFileEntry>(4600);
|
YmapDict ??= new Dictionary<uint, RpfFileEntry>(4600);
|
||||||
YbnDict ??= new Dictionary<uint, RpfFileEntry>(8800);
|
YbnDict ??= new Dictionary<uint, RpfFileEntry>(8800);
|
||||||
YnvDict ??= new Dictionary<uint, RpfFileEntry>(4500);
|
YnvDict ??= new Dictionary<uint, RpfFileEntry>(4500);
|
||||||
AllYmapsDict = new Dictionary<uint, RpfFileEntry>(11000);
|
AllYmapsDict ??= new Dictionary<uint, RpfFileEntry>(11000);
|
||||||
|
YmapDict.Clear();
|
||||||
|
YbnDict.Clear();
|
||||||
|
YnvDict.Clear();
|
||||||
|
AllYmapsDict.Clear();
|
||||||
foreach (var rpffile in ActiveMapRpfFiles.Values) //RpfMan.BaseRpfs)
|
foreach (var rpffile in ActiveMapRpfFiles.Values) //RpfMan.BaseRpfs)
|
||||||
{
|
{
|
||||||
if (rpffile.AllEntries == null) continue;
|
if (rpffile.AllEntries == null) continue;
|
||||||
@ -1082,16 +1090,20 @@ namespace CodeWalker.GameFiles
|
|||||||
Console.WriteLine($"YmapDict: {YmapDict.Count}; YbnDict: {YbnDict.Count}; YnvDict: {YnvDict.Count}; AllYmapsDict: {AllYmapsDict.Count};");
|
Console.WriteLine($"YmapDict: {YmapDict.Count}; YbnDict: {YbnDict.Count}; YnvDict: {YnvDict.Count}; AllYmapsDict: {AllYmapsDict.Count};");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitManifestDicts(bool force = true)
|
private async ValueTask InitManifestDicts(bool force = true)
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke("Loading manifests...");
|
UpdateStatus?.Invoke("Loading manifests...");
|
||||||
using var _ = new DisposableTimer("InitManifestDicts");
|
using var _ = new DisposableTimer("InitManifestDicts");
|
||||||
AllManifests = new List<YmfFile>(2000);
|
AllManifests ??= new List<YmfFile>(2000);
|
||||||
hdtexturelookup = new Dictionary<MetaHash, MetaHash>(24000);
|
hdtexturelookup ??= new Dictionary<MetaHash, MetaHash>(24000);
|
||||||
|
AllManifests.Clear();
|
||||||
|
hdtexturelookup.Clear();
|
||||||
IEnumerable<RpfFile> rpfs = PreloadedMode ? AllRpfs : ActiveMapRpfFiles.Values;
|
IEnumerable<RpfFile> rpfs = PreloadedMode ? AllRpfs : ActiveMapRpfFiles.Values;
|
||||||
foreach (RpfFile file in rpfs)
|
await Parallel.ForEachAsync(rpfs, async (file, cancellationToken) =>
|
||||||
{
|
{
|
||||||
if (file.AllEntries == null) continue;
|
if (file.AllEntries == null)
|
||||||
|
return;
|
||||||
|
|
||||||
//manifest and meta parsing..
|
//manifest and meta parsing..
|
||||||
foreach (RpfEntry entry in file.AllEntries)
|
foreach (RpfEntry entry in file.AllEntries)
|
||||||
{
|
{
|
||||||
@ -1101,11 +1113,14 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(entry.Path);
|
||||||
YmfFile ymffile = RpfMan.GetFile<YmfFile>(entry);
|
YmfFile ymffile = await RpfMan.GetFileAsync<YmfFile>(entry).ConfigureAwait(false);
|
||||||
if (ymffile != null)
|
if (ymffile != null)
|
||||||
|
{
|
||||||
|
lock(AllManifests)
|
||||||
{
|
{
|
||||||
AllManifests.Add(ymffile);
|
AllManifests.Add(ymffile);
|
||||||
|
}
|
||||||
|
|
||||||
if (ymffile.HDTxdAssetBindings != null)
|
if (ymffile.HDTxdAssetBindings != null)
|
||||||
{
|
{
|
||||||
@ -1114,9 +1129,12 @@ namespace CodeWalker.GameFiles
|
|||||||
var b = ymffile.HDTxdAssetBindings[i];
|
var b = ymffile.HDTxdAssetBindings[i];
|
||||||
var targetasset = JenkHash.GenHashLower(b.targetAsset.ToString());
|
var targetasset = JenkHash.GenHashLower(b.targetAsset.ToString());
|
||||||
var hdtxd = JenkHash.GenHashLower(b.HDTxd.ToString());
|
var hdtxd = JenkHash.GenHashLower(b.HDTxd.ToString());
|
||||||
|
lock(hdtexturelookup)
|
||||||
|
{
|
||||||
hdtexturelookup[targetasset] = hdtxd;
|
hdtexturelookup[targetasset] = hdtxd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1127,7 +1145,7 @@ namespace CodeWalker.GameFiles
|
|||||||
Console.WriteLine(errstr);
|
Console.WriteLine(errstr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
Console.WriteLine($"hdtexturelookup: {hdtexturelookup.Count}; AllManifests: {AllManifests.Count};");
|
Console.WriteLine($"hdtexturelookup: {hdtexturelookup.Count}; AllManifests: {AllManifests.Count};");
|
||||||
}
|
}
|
||||||
@ -1159,7 +1177,7 @@ namespace CodeWalker.GameFiles
|
|||||||
allRpfs = allRpfs.Concat(DlcActiveRpfs);
|
allRpfs = allRpfs.Concat(DlcActiveRpfs);
|
||||||
}
|
}
|
||||||
|
|
||||||
await allRpfs.Where(p => p.AllEntries != null).ParallelForEachAsync(async (file) =>
|
await Parallel.ForEachAsync(allRpfs, async (file, cancellationToken) =>
|
||||||
{
|
{
|
||||||
foreach (RpfEntry entry in file.AllEntries)
|
foreach (RpfEntry entry in file.AllEntries)
|
||||||
{
|
{
|
||||||
@ -1228,7 +1246,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Couldn't find {node.Name} in YmapDict");
|
//Console.WriteLine($"Couldn't find {node.Name} in YmapDict");
|
||||||
} //ymap not found...
|
} //ymap not found...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1249,18 +1267,12 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
CacheDatFile maincache = null;
|
CacheDatFile maincache = null;
|
||||||
|
maincache = loadCacheFile("common.rpf\\data\\gta5_cache_y.dat", true);
|
||||||
if (EnableDlc)
|
if (EnableDlc)
|
||||||
{
|
{
|
||||||
maincache = loadCacheFile("update\\update.rpf\\common\\data\\gta5_cache_y.dat", false);
|
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);
|
maincache = loadCacheFile("update\\update2.rpf\\common\\data\\gta5_cache_y.dat", true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
maincache = loadCacheFile("common.rpf\\data\\gta5_cache_y.dat", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1311,7 +1323,8 @@ namespace CodeWalker.GameFiles
|
|||||||
// }
|
// }
|
||||||
//}, maxDegreeOfParallelism: 8);
|
//}, maxDegreeOfParallelism: 8);
|
||||||
|
|
||||||
await allYtypes.ParallelForEachAsync(async (file) =>
|
|
||||||
|
await Parallel.ForEachAsync(allYtypes, async (file, cancellationToken) =>
|
||||||
{
|
{
|
||||||
foreach (var entry in file.AllEntries)
|
foreach (var entry in file.AllEntries)
|
||||||
{
|
{
|
||||||
@ -1323,6 +1336,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine(ex.ToString());
|
||||||
ErrorLog(entry.Path + ": " + ex.ToString());
|
ErrorLog(entry.Path + ": " + ex.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1707,10 +1721,13 @@ namespace CodeWalker.GameFiles
|
|||||||
if (file.Name.Equals(name + ".yld", StringComparison.OrdinalIgnoreCase))
|
if (file.Name.Equals(name + ".yld", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
pedClotsDict ??= ensureDict(allPedClothDicts, hash);
|
pedClotsDict ??= ensureDict(allPedClothDicts, hash);
|
||||||
|
lock(pedClotsDict)
|
||||||
|
{
|
||||||
pedClotsDict[file.ShortNameHash] = file;
|
pedClotsDict[file.ShortNameHash] = file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (dir?.Directories != null)
|
if (dir?.Directories != null)
|
||||||
{
|
{
|
||||||
@ -1733,21 +1750,30 @@ namespace CodeWalker.GameFiles
|
|||||||
if (file.IsExtension(".ydd"))
|
if (file.IsExtension(".ydd"))
|
||||||
{
|
{
|
||||||
pedDrwDicts ??= ensureDict(allPedDrwDicts, hash);
|
pedDrwDicts ??= ensureDict(allPedDrwDicts, hash);
|
||||||
|
lock(pedDrwDicts)
|
||||||
|
{
|
||||||
pedDrwDicts[file.ShortNameHash] = file;
|
pedDrwDicts[file.ShortNameHash] = file;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (file.IsExtension(".ytd"))
|
else if (file.IsExtension(".ytd"))
|
||||||
{
|
{
|
||||||
pedTextDicts ??= ensureDict(allPedTexDicts, hash);
|
pedTextDicts ??= ensureDict(allPedTexDicts, hash);
|
||||||
|
lock(pedTextDicts)
|
||||||
|
{
|
||||||
pedTextDicts[file.ShortNameHash] = file;
|
pedTextDicts[file.ShortNameHash] = file;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (file.IsExtension(".yld"))
|
else if (file.IsExtension(".yld"))
|
||||||
{
|
{
|
||||||
pedClotsDict ??= ensureDict(allPedClothDicts, hash);
|
pedClotsDict ??= ensureDict(allPedClothDicts, hash);
|
||||||
|
lock(pedClotsDict)
|
||||||
|
{
|
||||||
pedClotsDict[file.ShortNameHash] = file;
|
pedClotsDict[file.ShortNameHash] = file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var numDlcs = dlcrpfs?.Count ?? 0;
|
var numDlcs = dlcrpfs?.Count ?? 0;
|
||||||
@ -1914,7 +1940,8 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
var relFiles = new ConcurrentBag<RelFile>();
|
var relFiles = new ConcurrentBag<RelFile>();
|
||||||
|
|
||||||
await datrelentries.Values.ParallelForEachAsync(async (datrelentry) =>
|
|
||||||
|
await Parallel.ForEachAsync(datrelentries.Values, async (datrelentry, cancellationToken) =>
|
||||||
{
|
{
|
||||||
var relfile = await RpfMan.GetFileAsync<RelFile>(datrelentry).ConfigureAwait(false);
|
var relfile = await RpfMan.GetFileAsync<RelFile>(datrelentry).ConfigureAwait(false);
|
||||||
if (relfile == null)
|
if (relfile == null)
|
||||||
@ -2134,7 +2161,7 @@ namespace CodeWalker.GameFiles
|
|||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex);
|
Console.WriteLine(ex);
|
||||||
throw ex;
|
throw;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@ -2201,7 +2228,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (!ydr.Loaded && !ydr.LoadQueued)
|
if (!ydr.Loaded && !ydr.LoadQueued)
|
||||||
{
|
{
|
||||||
TryLoadEnqueue(ydr);
|
_ = TryLoadEnqueue(ydr);
|
||||||
}
|
}
|
||||||
return ydr;
|
return ydr;
|
||||||
}
|
}
|
||||||
@ -2233,7 +2260,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (!ydd.Loaded && !ydd.LoadQueued)
|
if (!ydd.Loaded && !ydd.LoadQueued)
|
||||||
{
|
{
|
||||||
TryLoadEnqueue(ydd);
|
_ = TryLoadEnqueue(ydd);
|
||||||
}
|
}
|
||||||
return ydd;
|
return ydd;
|
||||||
}
|
}
|
||||||
@ -2298,7 +2325,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
if (!ymap.Loaded && !ymap.LoadQueued)
|
if (!ymap.Loaded && !ymap.LoadQueued)
|
||||||
{
|
{
|
||||||
TryLoadEnqueue(ymap);
|
_ = TryLoadEnqueue(ymap);
|
||||||
}
|
}
|
||||||
return ymap;
|
return ymap;
|
||||||
}
|
}
|
||||||
@ -2331,7 +2358,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
if (!yft.Loaded && !yft.LoadQueued)
|
if (!yft.Loaded && !yft.LoadQueued)
|
||||||
{
|
{
|
||||||
TryLoadEnqueue(yft);
|
_ = TryLoadEnqueue(yft);
|
||||||
}
|
}
|
||||||
return yft;
|
return yft;
|
||||||
}
|
}
|
||||||
@ -2360,7 +2387,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
if (!ybn.Loaded && !ybn.LoadQueued)
|
if (!ybn.Loaded && !ybn.LoadQueued)
|
||||||
{
|
{
|
||||||
TryLoadEnqueue(ybn);
|
_ = TryLoadEnqueue(ybn);
|
||||||
}
|
}
|
||||||
return ybn;
|
return ybn;
|
||||||
}
|
}
|
||||||
@ -2389,7 +2416,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
if (!ycd.Loaded && !ycd.LoadQueued)
|
if (!ycd.Loaded && !ycd.LoadQueued)
|
||||||
{
|
{
|
||||||
TryLoadEnqueue(ycd);
|
_ = TryLoadEnqueue(ycd);
|
||||||
}
|
}
|
||||||
return ycd;
|
return ycd;
|
||||||
}
|
}
|
||||||
@ -2418,7 +2445,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
if (!yed.Loaded && !yed.LoadQueued)
|
if (!yed.Loaded && !yed.LoadQueued)
|
||||||
{
|
{
|
||||||
TryLoadEnqueue(yed);
|
_ = TryLoadEnqueue(yed);
|
||||||
}
|
}
|
||||||
return yed;
|
return yed;
|
||||||
}
|
}
|
||||||
@ -2447,7 +2474,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
if (!ynv.Loaded && !ynv.LoadQueued)
|
if (!ynv.Loaded && !ynv.LoadQueued)
|
||||||
{
|
{
|
||||||
TryLoadEnqueue(ynv);
|
_ = TryLoadEnqueue(ynv);
|
||||||
}
|
}
|
||||||
return ynv;
|
return ynv;
|
||||||
}
|
}
|
||||||
@ -2539,12 +2566,19 @@ namespace CodeWalker.GameFiles
|
|||||||
return new ValueTask<bool>(false);
|
return new ValueTask<bool>(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async ValueTask<T> GetFileUncachedAsync<T>(RpfFileEntry e) where T : GameFile, new()
|
||||||
|
{
|
||||||
|
var f = new T();
|
||||||
|
f.RpfFileEntry = e;
|
||||||
|
await TryLoadEnqueue(f);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
public T GetFileUncached<T>(RpfFileEntry e) where T : GameFile, new()
|
public T GetFileUncached<T>(RpfFileEntry e) where T : GameFile, new()
|
||||||
{
|
{
|
||||||
var f = new T();
|
var f = new T();
|
||||||
f.RpfFileEntry = e;
|
f.RpfFileEntry = e;
|
||||||
TryLoadEnqueue(f);
|
_ = TryLoadEnqueue(f);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2623,7 +2657,7 @@ namespace CodeWalker.GameFiles
|
|||||||
req.LoadQueued = false;
|
req.LoadQueued = false;
|
||||||
req.Loaded = false;
|
req.Loaded = false;
|
||||||
Console.WriteLine(e);
|
Console.WriteLine(e);
|
||||||
TryLoadEnqueue(req);
|
_ = TryLoadEnqueue(req);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -114,9 +114,6 @@ namespace CodeWalker.GameFiles
|
|||||||
(ulong)this.NamePointer // offset
|
(ulong)this.NamePointer // offset
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Name))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
//Strings = MetaTypes.GetStrings(this);
|
//Strings = MetaTypes.GetStrings(this);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -11,6 +11,7 @@ using TC = System.ComponentModel.TypeConverterAttribute;
|
|||||||
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
||||||
using CodeWalker.World;
|
using CodeWalker.World;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
{
|
{
|
||||||
@ -1454,40 +1455,13 @@ namespace CodeWalker.GameFiles
|
|||||||
if (items == null) return null;
|
if (items == null) return null;
|
||||||
|
|
||||||
return MemoryMarshal.AsBytes(items.AsSpan()).ToArray();
|
return MemoryMarshal.AsBytes(items.AsSpan()).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
//var size = Marshal.SizeOf(typeof(T)) * items.Length;
|
public static Span<byte> ConvertArrayToBytes<T>(Span<T> items) where T : struct
|
||||||
//var b = new byte[size];
|
{
|
||||||
//GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
if (items == null) return null;
|
||||||
//var h = handle.AddrOfPinnedObject();
|
|
||||||
//Marshal.Copy(h, b, 0, size);
|
|
||||||
//handle.Free();
|
|
||||||
//return b;
|
|
||||||
|
|
||||||
//var size = Marshal.SizeOf(typeof(T)) * items.Length;
|
return MemoryMarshal.AsBytes(items);
|
||||||
//var b = new byte[size];
|
|
||||||
//return MemoryMarshal.AsBytes<T>(items).ToArray();
|
|
||||||
//GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
|
||||||
//var h = handle.AddrOfPinnedObject();
|
|
||||||
//Marshal.Copy(h, b, 0, size);
|
|
||||||
//handle.Free();
|
|
||||||
//return b;
|
|
||||||
|
|
||||||
|
|
||||||
//int size = Marshal.SizeOf(typeof(T));
|
|
||||||
//int sizetot = size * items.Length;
|
|
||||||
//byte[] arrout = new byte[sizetot];
|
|
||||||
//int offset = 0;
|
|
||||||
//for (int i = 0; i < items.Length; i++)
|
|
||||||
//{
|
|
||||||
// byte[] arr = new byte[size];
|
|
||||||
// IntPtr ptr = Marshal.AllocHGlobal(size);
|
|
||||||
// Marshal.StructureToPtr(items[i], ptr, true);
|
|
||||||
// Marshal.Copy(ptr, arr, 0, size);
|
|
||||||
// Marshal.FreeHGlobal(ptr);
|
|
||||||
// Buffer.BlockCopy(arr, 0, arrout, offset, size);
|
|
||||||
// offset += size;
|
|
||||||
//}
|
|
||||||
//return arrout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1561,7 +1535,10 @@ namespace CodeWalker.GameFiles
|
|||||||
var ptr = ptrs[i];
|
var ptr = ptrs[i];
|
||||||
var offset = ptr.Offset;
|
var offset = ptr.Offset;
|
||||||
var block = meta.GetBlock(ptr.BlockID);
|
var block = meta.GetBlock(ptr.BlockID);
|
||||||
if (block == null) continue;
|
if (block == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
//if (blocktype == 0)
|
//if (blocktype == 0)
|
||||||
//{ blocktype = block.StructureNameHash; }
|
//{ blocktype = block.StructureNameHash; }
|
||||||
@ -1569,9 +1546,13 @@ namespace CodeWalker.GameFiles
|
|||||||
//{ } //not all the same type..!
|
//{ } //not all the same type..!
|
||||||
|
|
||||||
if (block.StructureNameHash != name)
|
if (block.StructureNameHash != name)
|
||||||
{ return null; } //type mismatch - don't return anything...
|
{
|
||||||
|
return null;
|
||||||
|
} //type mismatch - don't return anything...
|
||||||
if ((offset < 0) || (block.Data == null) || (offset >= block.Data.Length))
|
if ((offset < 0) || (block.Data == null) || (offset >= block.Data.Length))
|
||||||
{ continue; }
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
items[i] = ConvertData<T>(block.Data, offset);
|
items[i] = ConvertData<T>(block.Data, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1583,7 +1564,8 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
public static T[] ConvertDataArray<T>(Meta meta, MetaName name, ulong pointer, uint count) where T : struct
|
public static T[] ConvertDataArray<T>(Meta meta, MetaName name, ulong pointer, uint count) where T : struct
|
||||||
{
|
{
|
||||||
if (count == 0) return null;
|
if (count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
T[] items = new T[count];
|
T[] items = new T[count];
|
||||||
int itemsize = Marshal.SizeOf(typeof(T));
|
int itemsize = Marshal.SizeOf(typeof(T));
|
||||||
@ -1593,7 +1575,9 @@ namespace CodeWalker.GameFiles
|
|||||||
uint ptroffset = (uint)((pointer >> 12) & 0xFFFFF);
|
uint ptroffset = (uint)((pointer >> 12) & 0xFFFFF);
|
||||||
var ptrblock = (ptrindex < meta.DataBlocks.Count) ? meta.DataBlocks[(int)ptrindex] : null;
|
var ptrblock = (ptrindex < meta.DataBlocks.Count) ? meta.DataBlocks[(int)ptrindex] : null;
|
||||||
if ((ptrblock == null) || (ptrblock.Data == null) || (ptrblock.StructureNameHash != name))
|
if ((ptrblock == null) || (ptrblock.Data == null) || (ptrblock.StructureNameHash != name))
|
||||||
{ return null; } //no block or wrong block? shouldn't happen!
|
{
|
||||||
|
return null;
|
||||||
|
} //no block or wrong block? shouldn't happen!
|
||||||
|
|
||||||
int byteoffset = (int)ptroffset;// (ptroffset * 16 + ptrunkval);
|
int byteoffset = (int)ptroffset;// (ptroffset * 16 + ptrunkval);
|
||||||
int itemoffset = byteoffset / itemsize;
|
int itemoffset = byteoffset / itemsize;
|
||||||
@ -1608,25 +1592,30 @@ namespace CodeWalker.GameFiles
|
|||||||
itemcount = itemsleft;
|
itemcount = itemsleft;
|
||||||
} //don't try to read too many items..
|
} //don't try to read too many items..
|
||||||
|
|
||||||
|
ConvertDataArray<T>(ptrblock.Data, itemoffset * Marshal.SizeOf(typeof(T)), itemcount).CopyTo(items.AsSpan(curi));
|
||||||
//ConvertDataArray<T>(ptrblock.Data, itemoffset * Marshal.SizeOf(typeof(T)), itemcount).CopyTo(items.AsSpan(curi));
|
//for (int i = 0; i < itemcount; i++)
|
||||||
for (int i = 0; i < itemcount; i++)
|
//{
|
||||||
{
|
// int offset = (itemoffset + i) * itemsize;
|
||||||
int offset = (itemoffset + i) * itemsize;
|
// int index = curi + i;
|
||||||
int index = curi + i;
|
// items[index] = ConvertData<T>(ptrblock.Data, offset);
|
||||||
items[index] = ConvertData<T>(ptrblock.Data, offset);
|
//}
|
||||||
}
|
|
||||||
itemoffset = 0; //start at beginning of next block..
|
itemoffset = 0; //start at beginning of next block..
|
||||||
curi += itemcount;
|
curi += itemcount;
|
||||||
itemsleft -= itemcount;
|
itemsleft -= itemcount;
|
||||||
if (itemsleft <= 0)
|
if (itemsleft <= 0)
|
||||||
{ return items; }//all done!
|
{
|
||||||
|
return items;
|
||||||
|
}//all done!
|
||||||
ptrindex++;
|
ptrindex++;
|
||||||
ptrblock = (ptrindex < meta.DataBlocks.Count) ? meta.DataBlocks[(int)ptrindex] : null;
|
ptrblock = (ptrindex < meta.DataBlocks.Count) ? meta.DataBlocks[(int)ptrindex] : null;
|
||||||
if ((ptrblock == null) || (ptrblock.Data == null))
|
if ((ptrblock == null) || (ptrblock.Data == null))
|
||||||
{ break; } //not enough items..?
|
{
|
||||||
|
break;
|
||||||
|
} //not enough items..?
|
||||||
if (ptrblock.StructureNameHash != name)
|
if (ptrblock.StructureNameHash != name)
|
||||||
{ break; } //type mismatch..
|
{
|
||||||
|
break;
|
||||||
|
} //type mismatch..
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -2207,12 +2207,7 @@ namespace CodeWalker.GameFiles
|
|||||||
public static string XmlEscape(string unescaped)
|
public static string XmlEscape(string unescaped)
|
||||||
{
|
{
|
||||||
if (unescaped == null) return null;
|
if (unescaped == null) return null;
|
||||||
XmlDocument doc = new XmlDocument();
|
var escaped = System.Web.HttpUtility.HtmlEncode(unescaped).Replace("\"", """);
|
||||||
XmlNode node = doc.CreateElement("root");
|
|
||||||
node.InnerText = unescaped;
|
|
||||||
var escaped = node.InnerXml.Replace("\"", """);
|
|
||||||
if (escaped != unescaped)
|
|
||||||
{ }
|
|
||||||
return escaped;
|
return escaped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +117,7 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -880,8 +881,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
foreach (var str in strs)
|
foreach (var str in strs)
|
||||||
{
|
{
|
||||||
JenkIndex.Ensure(str);
|
JenkIndex.EnsureBoth(str);
|
||||||
JenkIndex.EnsureLower(str);
|
|
||||||
}
|
}
|
||||||
Strings = strs.ToArray();
|
Strings = strs.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -471,7 +471,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
|
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
|
||||||
MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream("Decompress", data.Length);
|
MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream("Decompress", data.Length);
|
||||||
ds.CopyToFast(outstr);
|
ds.CopyTo(outstr, 524288);
|
||||||
return outstr.ToArray();
|
return outstr.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,11 +104,12 @@ namespace CodeWalker.GameFiles
|
|||||||
position = value;
|
position = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new resource data reader for the specified system- and graphics-stream.
|
/// Initializes a new resource data reader for the specified system- and graphics-stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ResourceDataReader(Stream systemStream, Stream graphicsStream, Endianess endianess = Endianess.LittleEndian)
|
public ResourceDataReader(Stream systemStream, Stream graphicsStream, Endianess endianess = Endianess.LittleEndian)
|
||||||
: base((Stream)null, endianess)
|
: base(null, endianess)
|
||||||
{
|
{
|
||||||
this.systemStream = systemStream;
|
this.systemStream = systemStream;
|
||||||
this.graphicsStream = graphicsStream;
|
this.graphicsStream = graphicsStream;
|
||||||
@ -117,7 +118,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ResourceDataReader(RpfResourceFileEntry resentry, byte[] data, Endianess endianess = Endianess.LittleEndian)
|
public ResourceDataReader(RpfResourceFileEntry resentry, byte[] data, Endianess endianess = Endianess.LittleEndian)
|
||||||
: base((Stream)null, endianess)
|
: base(null, endianess)
|
||||||
{
|
{
|
||||||
FileEntry = resentry;
|
FileEntry = resentry;
|
||||||
this.systemSize = resentry.SystemSize;
|
this.systemSize = resentry.SystemSize;
|
||||||
@ -138,21 +139,21 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if ((int)systemSize > data.Length)
|
if ((int)systemSize > data.Length)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"systemSize {systemSize} is larger than data length ({data.Length})", nameof(systemSize));
|
throw new ArgumentException($"systemSize {systemSize} is larger than data length ({data.Length})", nameof(resentry));
|
||||||
}
|
}
|
||||||
if ((int)graphicsSize > data.Length)
|
if ((int)graphicsSize > data.Length)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"graphicsSize {graphicsSize} is larger than data length ({data.Length})", nameof(graphicsSize));
|
throw new ArgumentException($"graphicsSize {graphicsSize} is larger than data length ({data.Length})", nameof(resentry));
|
||||||
}
|
}
|
||||||
this.systemStream = Stream.Synchronized(new MemoryStream(data, 0, (int)systemSize));
|
this.systemStream = new MemoryStream(data, 0, (int)systemSize);
|
||||||
this.graphicsStream = Stream.Synchronized(new MemoryStream(data, (int)systemSize, (int)graphicsSize));
|
this.graphicsStream = new MemoryStream(data, (int)systemSize, (int)graphicsSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceDataReader(int systemSize, int graphicsSize, byte[] data, Endianess endianess = Endianess.LittleEndian)
|
public ResourceDataReader(int systemSize, int graphicsSize, byte[] data, Endianess endianess = Endianess.LittleEndian)
|
||||||
: base((Stream)null, endianess)
|
: base(null, endianess)
|
||||||
{
|
{
|
||||||
this.systemStream = Stream.Synchronized(new MemoryStream(data, 0, systemSize));
|
this.systemStream = new MemoryStream(data, 0, systemSize);
|
||||||
this.graphicsStream = Stream.Synchronized(new MemoryStream(data, systemSize, graphicsSize));
|
this.graphicsStream = new MemoryStream(data, systemSize, graphicsSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Stream GetStream()
|
public override Stream GetStream()
|
||||||
@ -269,7 +270,6 @@ namespace CodeWalker.GameFiles
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal const int StackallocThreshold = 512;
|
|
||||||
public unsafe byte[] ReadBytesAt(ulong position, uint count, bool cache = true, byte[] buffer = null)
|
public unsafe byte[] ReadBytesAt(ulong position, uint count, bool cache = true, byte[] buffer = null)
|
||||||
{
|
{
|
||||||
long pos = (long)position;
|
long pos = (long)position;
|
||||||
@ -489,6 +489,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
systemStream?.Dispose();
|
systemStream?.Dispose();
|
||||||
graphicsStream?.Dispose();
|
graphicsStream?.Dispose();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,6 +648,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
systemStream?.Dispose();
|
systemStream?.Dispose();
|
||||||
graphicsStream?.Dispose();
|
graphicsStream?.Dispose();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,26 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
{
|
{
|
||||||
|
public struct FileCounts
|
||||||
|
{
|
||||||
|
public uint Rpfs;
|
||||||
|
public uint Files;
|
||||||
|
public uint Folders;
|
||||||
|
public uint Resources;
|
||||||
|
public uint BinaryFiles;
|
||||||
|
|
||||||
|
public static FileCounts operator +(FileCounts a, FileCounts b)
|
||||||
|
{
|
||||||
|
return new FileCounts
|
||||||
|
{
|
||||||
|
Rpfs = a.Rpfs + b.Rpfs,
|
||||||
|
Files = a.Files + b.Files,
|
||||||
|
Folders = a.Folders + b.Folders,
|
||||||
|
Resources = a.Resources + b.Resources,
|
||||||
|
BinaryFiles = a.BinaryFiles + b.BinaryFiles
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class RpfFile
|
public class RpfFile
|
||||||
{
|
{
|
||||||
@ -53,15 +73,6 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
public uint TotalFileCount { get; set; }
|
public uint TotalFileCount { get; set; }
|
||||||
public uint TotalFolderCount { get; set; }
|
|
||||||
public uint TotalResourceCount { get; set; }
|
|
||||||
public uint TotalBinaryFileCount { get; set; }
|
|
||||||
public uint GrandTotalRpfCount { get; set; }
|
|
||||||
public uint GrandTotalFileCount { get; set; }
|
|
||||||
public uint GrandTotalFolderCount { get; set; }
|
|
||||||
public uint GrandTotalResourceCount { get; set; }
|
|
||||||
public uint GrandTotalBinaryFileCount { get; set; }
|
|
||||||
public long ExtractedByteCount { get; set; }
|
|
||||||
|
|
||||||
static RpfFile()
|
static RpfFile()
|
||||||
{
|
{
|
||||||
@ -163,7 +174,10 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void ThrowInvalidResource()
|
||||||
|
{
|
||||||
|
throw new Exception("Invalid Resource - not GTAV!");
|
||||||
|
}
|
||||||
|
|
||||||
private void ReadHeader(BinaryReader br)
|
private void ReadHeader(BinaryReader br)
|
||||||
{
|
{
|
||||||
@ -178,7 +192,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (Version != 0x52504637)
|
if (Version != 0x52504637)
|
||||||
{
|
{
|
||||||
throw new Exception("Invalid Resource - not GTAV!");
|
ThrowInvalidResource();
|
||||||
}
|
}
|
||||||
|
|
||||||
var entriesLength = (int)EntryCount * 16;
|
var entriesLength = (int)EntryCount * 16;
|
||||||
@ -202,8 +216,8 @@ namespace CodeWalker.GameFiles
|
|||||||
break;
|
break;
|
||||||
case RpfEncryption.NG:
|
case RpfEncryption.NG:
|
||||||
default:
|
default:
|
||||||
GTACrypto.DecryptNG(entriesdata, Name, (uint)FileSize, 0, entriesLength);
|
GTACrypto.DecryptNG(entriesdata.AsSpan(0, entriesLength), Name, (uint)FileSize);
|
||||||
GTACrypto.DecryptNG(namesdata, Name, (uint)FileSize, 0, namesLength);
|
GTACrypto.DecryptNG(namesdata.AsSpan(0, namesLength), Name, (uint)FileSize);
|
||||||
|
|
||||||
IsNGEncrypted = true;
|
IsNGEncrypted = true;
|
||||||
break;
|
break;
|
||||||
@ -215,9 +229,6 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
AllEntries = new List<RpfEntry>((int)EntryCount);
|
AllEntries = new List<RpfEntry>((int)EntryCount);
|
||||||
TotalFileCount = 0;
|
TotalFileCount = 0;
|
||||||
TotalFolderCount = 0;
|
|
||||||
TotalResourceCount = 0;
|
|
||||||
TotalBinaryFileCount = 0;
|
|
||||||
|
|
||||||
for (uint i = 0; i < EntryCount; i++)
|
for (uint i = 0; i < EntryCount; i++)
|
||||||
{
|
{
|
||||||
@ -231,18 +242,15 @@ namespace CodeWalker.GameFiles
|
|||||||
if (x == 0x7fffff00) //directory entry
|
if (x == 0x7fffff00) //directory entry
|
||||||
{
|
{
|
||||||
e = new RpfDirectoryEntry();
|
e = new RpfDirectoryEntry();
|
||||||
TotalFolderCount++;
|
|
||||||
}
|
}
|
||||||
else if ((x & 0x80000000) == 0) //binary file entry
|
else if ((x & 0x80000000) == 0) //binary file entry
|
||||||
{
|
{
|
||||||
e = new RpfBinaryFileEntry();
|
e = new RpfBinaryFileEntry();
|
||||||
TotalBinaryFileCount++;
|
|
||||||
TotalFileCount++;
|
TotalFileCount++;
|
||||||
}
|
}
|
||||||
else //assume resource file entry
|
else //assume resource file entry
|
||||||
{
|
{
|
||||||
e = new RpfResourceFileEntry();
|
e = new RpfResourceFileEntry();
|
||||||
TotalResourceCount++;
|
|
||||||
TotalFileCount++;
|
TotalFileCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,39 +336,39 @@ namespace CodeWalker.GameFiles
|
|||||||
ArrayPool<byte>.Shared.Return(namesdata);
|
ArrayPool<byte>.Shared.Return(namesdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ScanStructure(Action<string> updateStatus, Action<string> errorLog)
|
public FileCounts ScanStructure(Action<string> updateStatus, Action<string> errorLog)
|
||||||
{
|
{
|
||||||
|
|
||||||
using var fileStream = File.OpenRead(FilePath);
|
using var fileStream = File.OpenRead(FilePath);
|
||||||
using var br = new BinaryReader(fileStream);
|
using var br = new BinaryReader(fileStream);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return ScanStructure(br, updateStatus, errorLog);
|
return ScanStructure(br, updateStatus, errorLog) ?? default;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LastError = ex.ToString();
|
LastError = ex.ToString();
|
||||||
LastException = ex;
|
LastException = ex;
|
||||||
errorLog?.Invoke(FilePath + ": " + LastError);
|
errorLog?.Invoke(FilePath + ": " + LastError);
|
||||||
return false;
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private bool ScanStructure(BinaryReader br, Action<string> updateStatus, Action<string> errorLog)
|
private FileCounts? ScanStructure(BinaryReader br, Action<string> updateStatus, Action<string> errorLog)
|
||||||
{
|
{
|
||||||
if (FilePath == "update\\update.rpf\\dlc_patch\\patchday1ng\\x64\\patch\\data\\lang\\chinesesimp.rpf") return false;
|
if (FilePath == "update\\update.rpf\\dlc_patch\\patchday1ng\\x64\\patch\\data\\lang\\chinesesimp.rpf") return null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ReadHeader(br);
|
ReadHeader(br);
|
||||||
} catch
|
} catch
|
||||||
{
|
{
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
GrandTotalRpfCount = 1; //count this file..
|
var fileCounts = new FileCounts
|
||||||
GrandTotalFileCount = 1; //start with this one.
|
{
|
||||||
GrandTotalFolderCount = 0;
|
Rpfs = 1,
|
||||||
GrandTotalResourceCount = 0;
|
Files = 1
|
||||||
GrandTotalBinaryFileCount = 0;
|
};
|
||||||
|
|
||||||
Children = new List<RpfFile>();
|
Children = new List<RpfFile>();
|
||||||
|
|
||||||
@ -383,32 +391,29 @@ namespace CodeWalker.GameFiles
|
|||||||
subfile.Parent = this;
|
subfile.Parent = this;
|
||||||
subfile.ParentFileEntry = binentry;
|
subfile.ParentFileEntry = binentry;
|
||||||
|
|
||||||
if (subfile.ScanStructure(br, updateStatus, errorLog))
|
var result = subfile.ScanStructure(br, updateStatus, errorLog);
|
||||||
{
|
|
||||||
GrandTotalRpfCount += subfile.GrandTotalRpfCount;
|
|
||||||
GrandTotalFileCount += subfile.GrandTotalFileCount;
|
|
||||||
GrandTotalFolderCount += subfile.GrandTotalFolderCount;
|
|
||||||
GrandTotalResourceCount += subfile.GrandTotalResourceCount;
|
|
||||||
GrandTotalBinaryFileCount += subfile.GrandTotalBinaryFileCount;
|
|
||||||
|
|
||||||
|
if (result is not null)
|
||||||
|
{
|
||||||
|
fileCounts += result.Value;
|
||||||
Children.Add(subfile);
|
Children.Add(subfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//binary file that's not an rpf...
|
//binary file that's not an rpf...
|
||||||
GrandTotalBinaryFileCount++;
|
fileCounts.BinaryFiles++;
|
||||||
GrandTotalFileCount++;
|
fileCounts.Files++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (entry is RpfResourceFileEntry)
|
else if (entry is RpfResourceFileEntry)
|
||||||
{
|
{
|
||||||
GrandTotalResourceCount++;
|
fileCounts.Resources++;
|
||||||
GrandTotalFileCount++;
|
fileCounts.Files++;
|
||||||
}
|
}
|
||||||
else if (entry is RpfDirectoryEntry)
|
else if (entry is RpfDirectoryEntry)
|
||||||
{
|
{
|
||||||
GrandTotalFolderCount++;
|
fileCounts.Folders++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -416,7 +421,7 @@ namespace CodeWalker.GameFiles
|
|||||||
errorLog?.Invoke(entry.Path + ": " + ex.ToString());
|
errorLog?.Invoke(entry.Path + ": " + ex.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return fileCounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -500,7 +505,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GTACrypto.DecryptNG(tbytes, resentry.Name, resentry.FileSize);
|
GTACrypto.DecryptNG(tbytes.AsSpan(0, (int)totlen), resentry.Name, resentry.FileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -510,10 +515,8 @@ namespace CodeWalker.GameFiles
|
|||||||
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
|
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
|
||||||
|
|
||||||
MemoryStream outstr = recyclableMemoryStreamManager.GetStream();
|
MemoryStream outstr = recyclableMemoryStreamManager.GetStream();
|
||||||
ds.CopyToFast(outstr);
|
ds.CopyTo(outstr);
|
||||||
byte[] deflated = outstr.GetBuffer();
|
byte[] outbuf = outstr.ToArray();
|
||||||
byte[] outbuf = new byte[outstr.Length]; //need to copy to the right size buffer for File.WriteAllBytes().
|
|
||||||
Array.Copy(deflated, outbuf, outbuf.Length);
|
|
||||||
|
|
||||||
bool pathok = true;
|
bool pathok = true;
|
||||||
if (File.Exists(ofpath))
|
if (File.Exists(ofpath))
|
||||||
@ -604,11 +607,12 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
LastError = ex.ToString();
|
LastError = ex.ToString();
|
||||||
LastException = ex;
|
LastException = ex;
|
||||||
|
Console.WriteLine(ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ValueTask<byte[]> ExtractFileAsync(RpfFileEntry entry)
|
public async ValueTask<byte[]> ExtractFileAsync(RpfFileEntry entry)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -617,16 +621,16 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
if (entry is RpfBinaryFileEntry binaryFileEntry)
|
if (entry is RpfBinaryFileEntry binaryFileEntry)
|
||||||
{
|
{
|
||||||
return ExtractFileBinaryAsync(binaryFileEntry, br);
|
return await ExtractFileBinaryAsync(binaryFileEntry, br).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (entry is RpfResourceFileEntry resourceFileEntry)
|
else if (entry is RpfResourceFileEntry resourceFileEntry)
|
||||||
{
|
{
|
||||||
return ExtractFileResourceAsync(resourceFileEntry, br);
|
return await ExtractFileResourceAsync(resourceFileEntry, br).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{entry} is not a BinaryFileEntry of ResourceFileEntry");
|
Console.WriteLine($"{entry} is not a BinaryFileEntry of ResourceFileEntry");
|
||||||
return new ValueTask<byte[]>();
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -634,7 +638,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
LastError = ex.ToString();
|
LastError = ex.ToString();
|
||||||
LastException = ex;
|
LastException = ex;
|
||||||
return new ValueTask<byte[]>();
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,7 +669,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
||||||
{
|
{
|
||||||
GTACrypto.DecryptNG(tbytes, entry.Name, entry.FileUncompressedSize, 0, (int)totlen);
|
GTACrypto.DecryptNG(tbytes.AsSpan(0, (int)totlen), entry.Name, entry.FileUncompressedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -712,7 +716,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
||||||
{
|
{
|
||||||
GTACrypto.DecryptNG(tbytes, entry.Name, entry.FileUncompressedSize, 0, (int)totlen);
|
GTACrypto.DecryptNG(tbytes.AsSpan(0, (int)totlen), entry.Name, entry.FileUncompressedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -758,7 +762,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
||||||
{
|
{
|
||||||
GTACrypto.DecryptNG(tbytes, entry.Name, entry.FileSize, 0, (int)totlen);
|
GTACrypto.DecryptNG(tbytes.AsSpan(0, (int)totlen), entry.Name, entry.FileSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,7 +813,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
||||||
{
|
{
|
||||||
GTACrypto.DecryptNG(tbytes, entry.Name, entry.FileSize, 0, (int)totlen);
|
GTACrypto.DecryptNG(tbytes.AsSpan(0, (int)totlen), entry.Name, entry.FileSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1033,7 +1037,6 @@ namespace CodeWalker.GameFiles
|
|||||||
public string TestExtractAllFiles()
|
public string TestExtractAllFiles()
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
ExtractedByteCount = 0;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (BinaryReader br = new BinaryReader(File.OpenRead(GetPhysicalFilePath())))
|
using (BinaryReader br = new BinaryReader(File.OpenRead(GetPhysicalFilePath())))
|
||||||
@ -1068,10 +1071,6 @@ namespace CodeWalker.GameFiles
|
|||||||
sb.AppendFormat("{0} : Decompressed output was empty.", entry.Path);
|
sb.AppendFormat("{0} : Decompressed output was empty.", entry.Path);
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ExtractedByteCount += data.Length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (entry is RpfResourceFileEntry)
|
else if (entry is RpfResourceFileEntry)
|
||||||
{
|
{
|
||||||
@ -1095,10 +1094,6 @@ namespace CodeWalker.GameFiles
|
|||||||
sb.AppendFormat("{0} : Decompressed output was empty.", entry.Path);
|
sb.AppendFormat("{0} : Decompressed output was empty.", entry.Path);
|
||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ExtractedByteCount += data.Length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1128,18 +1123,22 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public List<RpfFileEntry> GetFiles(string folder, bool recurse)
|
public List<RpfFileEntry> GetFiles(string folder, bool recurse)
|
||||||
{
|
{
|
||||||
|
if (Root == null)
|
||||||
|
{
|
||||||
|
return new List<RpfFileEntry>();
|
||||||
|
}
|
||||||
List<RpfFileEntry> result = new List<RpfFileEntry>();
|
List<RpfFileEntry> result = new List<RpfFileEntry>();
|
||||||
string[] parts = folder.ToLowerInvariant().Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
//folder.AsSpan().Split
|
||||||
RpfDirectoryEntry dir = Root;
|
RpfDirectoryEntry dir = Root;
|
||||||
for (int i = 0; i < parts.Length; i++)
|
foreach(var part in folder.EnumerateSplit('\\'))
|
||||||
{
|
{
|
||||||
if (dir == null) break;
|
if (part.Length == 0)
|
||||||
dir = FindSubDirectory(dir, parts[i]);
|
continue;
|
||||||
|
dir = FindSubDirectory(dir, part);
|
||||||
}
|
}
|
||||||
if (dir != null)
|
|
||||||
{
|
|
||||||
GetFiles(dir, result, recurse);
|
GetFiles(dir, result, recurse);
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public void GetFiles(RpfDirectoryEntry dir, List<RpfFileEntry> result, bool recurse)
|
public void GetFiles(RpfDirectoryEntry dir, List<RpfFileEntry> result, bool recurse)
|
||||||
@ -1167,7 +1166,7 @@ namespace CodeWalker.GameFiles
|
|||||||
for (int i = 0; i < dir.Directories.Count; i++)
|
for (int i = 0; i < dir.Directories.Count; i++)
|
||||||
{
|
{
|
||||||
var cdir = dir.Directories[i];
|
var cdir = dir.Directories[i];
|
||||||
if (cdir.Name.ToLowerInvariant() == name)
|
if (cdir.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return cdir;
|
return cdir;
|
||||||
}
|
}
|
||||||
@ -1175,8 +1174,25 @@ namespace CodeWalker.GameFiles
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private RpfDirectoryEntry FindSubDirectory(RpfDirectoryEntry dir, ReadOnlySpan<char> name)
|
||||||
|
{
|
||||||
|
if (dir == null) return null;
|
||||||
|
if (dir.Directories == null) return null;
|
||||||
|
|
||||||
|
for (int i = 0; i < dir.Directories.Count; i++)
|
||||||
|
{
|
||||||
|
var cdir = dir.Directories[i];
|
||||||
|
if (cdir.Name.AsSpan() == name || cdir.Name.AsSpan().Equals(name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return cdir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly Stopwatch compression = new Stopwatch();
|
||||||
public static RecyclableMemoryStreamManager recyclableMemoryStreamManager = new RecyclableMemoryStreamManager(256 * 1024, 1024 * 1024, 128 * 1024 * 1024, false, 256 * 1024 * 100, 1024 * 1024 * 128 * 4);
|
public static RecyclableMemoryStreamManager recyclableMemoryStreamManager = new RecyclableMemoryStreamManager(256 * 1024, 1024 * 1024, 128 * 1024 * 1024, false, 256 * 1024 * 100, 1024 * 1024 * 128 * 4);
|
||||||
|
|
||||||
public byte[] DecompressBytes(byte[] bytes)
|
public byte[] DecompressBytes(byte[] bytes)
|
||||||
@ -1186,7 +1202,7 @@ namespace CodeWalker.GameFiles
|
|||||||
using DeflateStream ds = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress);
|
using DeflateStream ds = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress);
|
||||||
using var outstr = recyclableMemoryStreamManager.GetStream("DecompressBytes", bytes.Length);
|
using var outstr = recyclableMemoryStreamManager.GetStream("DecompressBytes", bytes.Length);
|
||||||
|
|
||||||
ds.CopyToFast(outstr);
|
ds.CopyTo(outstr, 524288);
|
||||||
byte[] outbuf = outstr.ToArray(); //need to copy to the right size buffer for output.
|
byte[] outbuf = outstr.ToArray(); //need to copy to the right size buffer for output.
|
||||||
|
|
||||||
if (outbuf.Length <= bytes.Length)
|
if (outbuf.Length <= bytes.Length)
|
||||||
@ -1212,14 +1228,8 @@ namespace CodeWalker.GameFiles
|
|||||||
using DeflateStream ds = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress);
|
using DeflateStream ds = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress);
|
||||||
using var outstr = recyclableMemoryStreamManager.GetStream("DecompressBytes", bytes.Length);
|
using var outstr = recyclableMemoryStreamManager.GetStream("DecompressBytes", bytes.Length);
|
||||||
|
|
||||||
await ds.CopyToFastAsync(outstr).ConfigureAwait(false);
|
await ds.CopyToAsync(outstr, 524288).ConfigureAwait(false);
|
||||||
byte[] outbuf = outstr.ToArray(); //need to copy to the right size buffer for output.
|
byte[] outbuf = outstr.ToArray(); //need to copy to the right size buffer for output.
|
||||||
//byte[] deflated = outstr.GetBuffer();
|
|
||||||
//Console.WriteLine($"{outstr.Read(outbuf, 0, outbuf.Length)}; {outbuf.Length}");
|
|
||||||
|
|
||||||
//Buffer.BlockCopy(deflated, 0, outbuf, 0, outbuf.Length);
|
|
||||||
|
|
||||||
//Buffer.BlockCopy(deflated, 0, outbuf, 0, outbuf.Length);
|
|
||||||
|
|
||||||
if (outbuf.Length <= bytes.Length)
|
if (outbuf.Length <= bytes.Length)
|
||||||
{
|
{
|
||||||
@ -1245,9 +1255,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
ds.Write(data, 0, data.Length);
|
ds.Write(data, 0, data.Length);
|
||||||
ds.Close();
|
ds.Close();
|
||||||
byte[] deflated = ms.GetBuffer();
|
byte[] outbuf = ms.ToArray(); //need to copy to the right size buffer...
|
||||||
byte[] outbuf = new byte[ms.Length]; //need to copy to the right size buffer...
|
|
||||||
Buffer.BlockCopy(deflated, 0, outbuf, 0, outbuf.Length);
|
|
||||||
return outbuf;
|
return outbuf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1377,8 +1385,8 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
private byte[] GetHeaderNamesData()
|
private byte[] GetHeaderNamesData()
|
||||||
{
|
{
|
||||||
MemoryStream namesstream = new MemoryStream();
|
using MemoryStream namesstream = new MemoryStream();
|
||||||
DataWriter nameswriter = new DataWriter(namesstream);
|
using DataWriter nameswriter = new DataWriter(namesstream);
|
||||||
var namedict = new Dictionary<string, uint>();
|
var namedict = new Dictionary<string, uint>();
|
||||||
foreach (var entry in AllEntries)
|
foreach (var entry in AllEntries)
|
||||||
{
|
{
|
||||||
@ -1395,10 +1403,10 @@ namespace CodeWalker.GameFiles
|
|||||||
nameswriter.Write(name);
|
nameswriter.Write(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var buf = new byte[namesstream.Length];
|
var buf = new byte[Math.Max(namesstream.Length, 16)];
|
||||||
namesstream.Position = 0;
|
namesstream.Position = 0;
|
||||||
namesstream.Read(buf, 0, buf.Length);
|
namesstream.Read(buf, 0, (int)namesstream.Length);
|
||||||
return PadBuffer(buf, 16);
|
return buf;
|
||||||
}
|
}
|
||||||
private byte[] GetHeaderEntriesData()
|
private byte[] GetHeaderEntriesData()
|
||||||
{
|
{
|
||||||
@ -1419,18 +1427,6 @@ namespace CodeWalker.GameFiles
|
|||||||
uint headerblockcount = GetBlockCount(headerusedbytes);
|
uint headerblockcount = GetBlockCount(headerusedbytes);
|
||||||
return headerblockcount;
|
return headerblockcount;
|
||||||
}
|
}
|
||||||
private static byte[] PadBuffer(byte[] buf, uint n)//add extra bytes as necessary to nearest n
|
|
||||||
{
|
|
||||||
uint buflen = (uint)buf.Length;
|
|
||||||
uint newlen = PadLength(buflen, n);
|
|
||||||
if (newlen != buflen)
|
|
||||||
{
|
|
||||||
byte[] buf2 = new byte[newlen];
|
|
||||||
Buffer.BlockCopy(buf, 0, buf2, 0, buf.Length);
|
|
||||||
return buf2;
|
|
||||||
}
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
private static uint PadLength(uint l, uint n)//round up to nearest n bytes
|
private static uint PadLength(uint l, uint n)//round up to nearest n bytes
|
||||||
{
|
{
|
||||||
uint rem = l % n;
|
uint rem = l % n;
|
||||||
@ -2430,7 +2426,10 @@ namespace CodeWalker.GameFiles
|
|||||||
char ch = Name[i];
|
char ch = Name[i];
|
||||||
if (ch == '.')
|
if (ch == '.')
|
||||||
{
|
{
|
||||||
extension = Name.Substring(i, length - i).ToLowerInvariant();
|
var result = Name.AsSpan(i, length - i);
|
||||||
|
Span<char> lowered = stackalloc char[result.Length];
|
||||||
|
result.ToLowerInvariant(lowered);
|
||||||
|
extension = lowered.ToString();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ch == System.IO.Path.DirectorySeparatorChar || ch == System.IO.Path.AltDirectorySeparatorChar)
|
if (ch == System.IO.Path.DirectorySeparatorChar || ch == System.IO.Path.AltDirectorySeparatorChar)
|
||||||
@ -3006,7 +3005,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
public uint Value { get; set; }
|
public uint Value { get; set; }
|
||||||
|
|
||||||
public RpfResourcePage[] Pages
|
public readonly RpfResourcePage[] Pages
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -3032,10 +3031,10 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint TypeVal { get { return (Value >> 28) & 0xF; } }
|
public readonly uint TypeVal { get { return (Value >> 28) & 0xF; } }
|
||||||
public uint BaseShift { get { return (Value & 0xF); } }
|
public readonly uint BaseShift { get { return (Value & 0xF); } }
|
||||||
public uint BaseSize { get { return (0x200u << (int)BaseShift); } }
|
public readonly uint BaseSize { get { return (0x200u << (int)BaseShift); } }
|
||||||
public uint[] BaseSizes
|
public readonly uint[] BaseSizes
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -3054,7 +3053,7 @@ namespace CodeWalker.GameFiles
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public uint[] PageCounts
|
public readonly uint[] PageCounts
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -3072,7 +3071,7 @@ namespace CodeWalker.GameFiles
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public uint[] PageSizes
|
public readonly uint[] PageSizes
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -3092,7 +3091,7 @@ namespace CodeWalker.GameFiles
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public uint Count
|
public readonly uint Count
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -3100,7 +3099,7 @@ namespace CodeWalker.GameFiles
|
|||||||
return c[0] + c[1] + c[2] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8];
|
return c[0] + c[1] + c[2] + c[3] + c[4] + c[5] + c[6] + c[7] + c[8];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public uint Size
|
public readonly uint Size
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -3152,7 +3151,7 @@ namespace CodeWalker.GameFiles
|
|||||||
return new RpfResourcePageFlags(v);
|
return new RpfResourcePageFlags(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override readonly string ToString()
|
||||||
{
|
{
|
||||||
return "Size: " + Size.ToString() + ", Pages: " + Count.ToString();
|
return "Size: " + Size.ToString() + ", Pages: " + Count.ToString();
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
{
|
{
|
||||||
@ -42,6 +44,9 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public volatile bool IsInited = false;
|
public volatile bool IsInited = false;
|
||||||
|
|
||||||
|
private const int DefaultEntryDictCapacity = 354878;
|
||||||
|
private const int DefaultRpfDictCapacity = 4650;
|
||||||
|
|
||||||
public void Init(string folder, Action<string> updateStatus, Action<string> errorLog, bool rootOnly = false, bool buildIndex = true)
|
public void Init(string folder, Action<string> updateStatus, Action<string> errorLog, bool rootOnly = false, bool buildIndex = true)
|
||||||
{
|
{
|
||||||
using var _ = new DisposableTimer("RpfManager.Init");
|
using var _ = new DisposableTimer("RpfManager.Init");
|
||||||
@ -52,14 +57,14 @@ namespace CodeWalker.GameFiles
|
|||||||
var sopt = rootOnly ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories;
|
var sopt = rootOnly ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories;
|
||||||
string[] allfiles = Directory.GetFiles(folder, "*.rpf", sopt);
|
string[] allfiles = Directory.GetFiles(folder, "*.rpf", sopt);
|
||||||
|
|
||||||
BaseRpfs = new List<RpfFile>();
|
BaseRpfs = new List<RpfFile>(1300);
|
||||||
ModRpfs = new List<RpfFile>();
|
ModRpfs = new List<RpfFile>(0);
|
||||||
DlcRpfs = new List<RpfFile>();
|
DlcRpfs = new List<RpfFile>(3500);
|
||||||
AllRpfs = new List<RpfFile>();
|
AllRpfs = new List<RpfFile>(5000);
|
||||||
DlcNoModRpfs = new List<RpfFile>();
|
DlcNoModRpfs = new List<RpfFile>(3500);
|
||||||
AllNoModRpfs = new List<RpfFile>();
|
AllNoModRpfs = new List<RpfFile>(5000);
|
||||||
RpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
RpfDict = new Dictionary<string, RpfFile>(DefaultRpfDictCapacity, StringComparer.OrdinalIgnoreCase);
|
||||||
EntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
EntryDict = new Dictionary<string, RpfEntry>(DefaultEntryDictCapacity, StringComparer.OrdinalIgnoreCase);
|
||||||
ModRpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
ModRpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
||||||
ModEntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
ModEntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
@ -88,6 +93,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (rf.LastException != null) //incase of corrupted rpf (or renamed NG encrypted RPF)
|
if (rf.LastException != null) //incase of corrupted rpf (or renamed NG encrypted RPF)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine(rf.LastException);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,12 +105,10 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var calculateSum = (RpfFile rpf) => { return 0; };
|
static int calculateSum(RpfFile rpf)
|
||||||
|
|
||||||
calculateSum = (RpfFile rpf) =>
|
|
||||||
{
|
{
|
||||||
return rpf.AllEntries?.Count ?? 0 + rpf.Children?.Sum(calculateSum) ?? 0;
|
return rpf.AllEntries?.Count ?? 0 + rpf.Children?.Sum(calculateSum) ?? 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
var minCapacity = rpfs.Sum(calculateSum);
|
var minCapacity = rpfs.Sum(calculateSum);
|
||||||
if (minCapacity > AllRpfs.Capacity)
|
if (minCapacity > AllRpfs.Capacity)
|
||||||
@ -119,13 +123,13 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (buildIndex)
|
if (buildIndex)
|
||||||
{
|
{
|
||||||
updateStatus?.Invoke("Building jenkindex...");
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
|
updateStatus?.Invoke("Building jenkindex...");
|
||||||
BuildBaseJenkIndex();
|
BuildBaseJenkIndex();
|
||||||
IsInited = true;
|
IsInited = true;
|
||||||
});
|
|
||||||
updateStatus?.Invoke("Scan complete");
|
updateStatus?.Invoke("Scan complete");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -135,7 +139,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Console.WriteLine($"AllRpfs: {AllRpfs.Count}; RpfDict: {RpfDict.Count}; EntryDict: {EntryDict.Count}; BaseRpfs: {BaseRpfs.Count}; ModRpfs: {ModRpfs.Count}; DlcRpfs: {DlcRpfs.Count}; DlcNoModRpfs: {DlcNoModRpfs.Count}; AllNoModRpfs: {AllNoModRpfs.Count}; ModRpfDict: {ModRpfDict.Count}; ModEntryDict: {ModEntryDict.Count}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init(List<RpfFile> allRpfs)
|
public void Init(List<RpfFile> allRpfs)
|
||||||
@ -149,20 +153,23 @@ namespace CodeWalker.GameFiles
|
|||||||
DlcRpfs = new List<RpfFile>();
|
DlcRpfs = new List<RpfFile>();
|
||||||
DlcNoModRpfs = new List<RpfFile>();
|
DlcNoModRpfs = new List<RpfFile>();
|
||||||
AllNoModRpfs = new List<RpfFile>();
|
AllNoModRpfs = new List<RpfFile>();
|
||||||
RpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
RpfDict = new Dictionary<string, RpfFile>(DefaultRpfDictCapacity, StringComparer.OrdinalIgnoreCase);
|
||||||
EntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
EntryDict = new Dictionary<string, RpfEntry>(DefaultEntryDictCapacity, StringComparer.OrdinalIgnoreCase);
|
||||||
ModRpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
ModRpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
||||||
ModEntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
ModEntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
||||||
foreach (var rpf in allRpfs)
|
foreach (var rpf in allRpfs)
|
||||||
{
|
{
|
||||||
RpfDict[rpf.Path] = rpf;
|
RpfDict[rpf.Path] = rpf;
|
||||||
if (rpf.AllEntries == null) continue;
|
if (rpf.AllEntries == null)
|
||||||
|
continue;
|
||||||
foreach (var entry in rpf.AllEntries)
|
foreach (var entry in rpf.AllEntries)
|
||||||
{
|
{
|
||||||
EntryDict[entry.Path] = entry;
|
EntryDict[entry.Path] = entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"RpfDict: {RpfDict.Count}; EntryDict: {EntryDict.Count}");
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
BuildBaseJenkIndex();
|
BuildBaseJenkIndex();
|
||||||
@ -173,7 +180,10 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
private void AddRpfFile(RpfFile file, bool isdlc, bool ismod)
|
private void AddRpfFile(RpfFile file, bool isdlc, bool ismod)
|
||||||
{
|
{
|
||||||
isdlc = isdlc || file.Name.Equals("update.rpf", StringComparison.OrdinalIgnoreCase) || (file.Name.StartsWith("dlc", StringComparison.OrdinalIgnoreCase) && file.Name.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase));
|
if (file.AllEntries == null && file.Children == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
isdlc = isdlc || (file.Name.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase) && (file.Name.StartsWith("dlc", StringComparison.OrdinalIgnoreCase) || file.Name.Equals("update.rpf", StringComparison.OrdinalIgnoreCase)));
|
||||||
ismod = ismod || (file.Path.StartsWith("mods\\", StringComparison.OrdinalIgnoreCase));
|
ismod = ismod || (file.Path.StartsWith("mods\\", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
if (file.AllEntries != null)
|
if (file.AllEntries != null)
|
||||||
@ -313,6 +323,7 @@ namespace CodeWalker.GameFiles
|
|||||||
byte[] bytes = GetFileData(path);
|
byte[] bytes = GetFileData(path);
|
||||||
return TextUtil.GetUTF8Text(bytes);
|
return TextUtil.GetUTF8Text(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public XmlDocument GetFileXml(string path)
|
public XmlDocument GetFileXml(string path)
|
||||||
{
|
{
|
||||||
XmlDocument doc = new XmlDocument();
|
XmlDocument doc = new XmlDocument();
|
||||||
@ -321,6 +332,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
doc.LoadXml(text);
|
doc.LoadXml(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,12 +385,12 @@ namespace CodeWalker.GameFiles
|
|||||||
file.Load(data, entry);
|
file.Load(data, entry);
|
||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
} catch(Exception ex)
|
}
|
||||||
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex);
|
Console.WriteLine(ex);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public bool LoadFile<T>(T file, RpfEntry e) where T : class, PackedFile
|
public bool LoadFile<T>(T file, RpfEntry e) where T : class, PackedFile
|
||||||
{
|
{
|
||||||
@ -428,12 +440,96 @@ namespace CodeWalker.GameFiles
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ConcurrentDictionary<string, int> counts = new ConcurrentDictionary<string, int>();
|
||||||
|
public void AddAllLods(string name)
|
||||||
|
{
|
||||||
|
var idx = name.LastIndexOf('_');
|
||||||
|
if (idx > 0)
|
||||||
|
{
|
||||||
|
var str1 = name.AsSpan(0, idx);
|
||||||
|
var idx2 = str1.LastIndexOf('_');
|
||||||
|
if (idx2 > 0)
|
||||||
|
{
|
||||||
|
// Filter some peds and clothing models (ydd's) which don't have LOD hashes we're interested in.
|
||||||
|
// This saves about 50% of the time it takes to do initial hashing
|
||||||
|
var str2 = str1.Slice(0, idx2 + 1);
|
||||||
|
if (str2.Length <= 2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch(str2)
|
||||||
|
{
|
||||||
|
case "uppr_":
|
||||||
|
case "p_":
|
||||||
|
case "accs_":
|
||||||
|
case "decl_":
|
||||||
|
case "berd_":
|
||||||
|
case "hair_":
|
||||||
|
case "teef_":
|
||||||
|
case "lowr_":
|
||||||
|
case "jbib_":
|
||||||
|
case "hand_":
|
||||||
|
case "feet_":
|
||||||
|
case "task_":
|
||||||
|
case "head_":
|
||||||
|
case "s_m_y_":
|
||||||
|
case "s_m_":
|
||||||
|
case "s_m_m_":
|
||||||
|
case "s_f_y_":
|
||||||
|
case "a_m_y_":
|
||||||
|
case "ig_":
|
||||||
|
case "u_m_y_":
|
||||||
|
case "u_m_m_":
|
||||||
|
case "u_m_":
|
||||||
|
case "minimap_":
|
||||||
|
case "a_":
|
||||||
|
case "u_f_":
|
||||||
|
case "csb_":
|
||||||
|
case "g_m_y_":
|
||||||
|
case "a_f_m_":
|
||||||
|
case "a_m_m_":
|
||||||
|
case "g_m_m_":
|
||||||
|
case "mp_m_":
|
||||||
|
case "mp_f_":
|
||||||
|
case "hand_000_":
|
||||||
|
case "hand_001_":
|
||||||
|
case "hair_000_":
|
||||||
|
case "a_f_y_":
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Span<char> buff = stackalloc char[str2.Length + 2 + 4];
|
||||||
|
str2.CopyTo(buff.Slice(0, str2.Length));
|
||||||
|
"lod".AsSpan().CopyTo(buff.Slice(str2.Length, 3));
|
||||||
|
//Console.WriteLine(buff.Slice(0, str2.Length + 3).ToString());
|
||||||
|
JenkIndex.EnsureLower(buff.Slice(0, str2.Length + 3));
|
||||||
|
var maxi = 99;
|
||||||
|
|
||||||
|
"00_lod".AsSpan().CopyTo(buff.Slice(str2.Length, 6));
|
||||||
|
for (int i = 1; i <= maxi; i++)
|
||||||
|
{
|
||||||
|
if (i < 10)
|
||||||
|
{
|
||||||
|
i.ToString().AsSpan().CopyTo(buff.Slice(str2.Length + 1, 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i.ToString().AsSpan().CopyTo(buff.Slice(str2.Length, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Console.WriteLine(buff.ToString());
|
||||||
|
//JenkIndex.Ensure(buff);
|
||||||
|
JenkIndex.EnsureLower(buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void BuildBaseJenkIndex()
|
public void BuildBaseJenkIndex()
|
||||||
{
|
{
|
||||||
using var _ = new DisposableTimer("BuildBaseJenkIndex");
|
using var _ = new DisposableTimer("BuildBaseJenkIndex");
|
||||||
Parallel.ForEach(AllRpfs, new ParallelOptions { MaxDegreeOfParallelism = 4 }, (file) =>
|
Parallel.ForEach(AllRpfs, (file) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -475,24 +571,26 @@ namespace CodeWalker.GameFiles
|
|||||||
JenkIndex.EnsureLower(nameChildrenLod + 'a');
|
JenkIndex.EnsureLower(nameChildrenLod + 'a');
|
||||||
JenkIndex.EnsureLower(nameChildrenLod + 'b');
|
JenkIndex.EnsureLower(nameChildrenLod + 'b');
|
||||||
}
|
}
|
||||||
var idx = name.LastIndexOf('_');
|
//var idx = name.LastIndexOf('_');
|
||||||
if (idx > 0)
|
//if (idx > 0)
|
||||||
{
|
//{
|
||||||
var str1 = name.Substring(0, idx);
|
// var str1 = name.Substring(0, idx);
|
||||||
var idx2 = str1.LastIndexOf('_');
|
// var idx2 = str1.LastIndexOf('_');
|
||||||
if (idx2 > 0)
|
// if (idx2 > 0)
|
||||||
{
|
// {
|
||||||
var str2 = str1.Substring(0, idx2);
|
// var str2 = str1.Substring(0, idx2);
|
||||||
JenkIndex.EnsureLower(str2 + "_lod");
|
// JenkIndex.EnsureLower(str2 + "_lod");
|
||||||
var maxi = 100;
|
// var maxi = 100;
|
||||||
for (int i = 1; i <= maxi; i++)
|
|
||||||
{
|
// for (int i = 1; i <= maxi; i++)
|
||||||
var str3 = str2 + '_' + i.ToString().PadLeft(2, '0') + "_lod";
|
// {
|
||||||
//JenkIndex.Ensure(str3);
|
// var str3 = str2 + '_' + i.ToString().PadLeft(2, '0') + "_lod";
|
||||||
JenkIndex.EnsureLower(str3);
|
// //JenkIndex.Ensure(str3);
|
||||||
}
|
// JenkIndex.EnsureLower(str3);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
//}
|
||||||
|
AddAllLods(name);
|
||||||
}
|
}
|
||||||
else if(name.EndsWith(".sps", StringComparison.OrdinalIgnoreCase))
|
else if(name.EndsWith(".sps", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
@ -560,6 +658,7 @@ namespace CodeWalker.GameFiles
|
|||||||
catch(Exception err)
|
catch(Exception err)
|
||||||
{
|
{
|
||||||
ErrorLog?.Invoke(err.ToString());
|
ErrorLog?.Invoke(err.ToString());
|
||||||
|
Console.WriteLine(err.ToString());
|
||||||
//failing silently!! not so good really
|
//failing silently!! not so good really
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -572,6 +671,14 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
JenkIndex.Ensure(i.ToString("00"));
|
JenkIndex.Ensure(i.ToString("00"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Task.Run(() =>
|
||||||
|
//{
|
||||||
|
// foreach (var count in counts.OrderBy(p => p.Value))
|
||||||
|
// {
|
||||||
|
// Console.WriteLine($"{count.Key,30}: {count.Value,3}");
|
||||||
|
// }
|
||||||
|
//});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,8 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
public enum Endianess
|
public enum Endianess
|
||||||
{
|
{
|
||||||
LittleEndian,
|
LittleEndian = 0,
|
||||||
BigEndian
|
BigEndian = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DataType
|
public enum DataType
|
||||||
@ -64,16 +64,10 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
private Stream baseStream;
|
private Stream baseStream;
|
||||||
|
|
||||||
private readonly byte[] _buffer = new byte[8];
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the endianess of the underlying stream.
|
/// Gets or sets the endianess of the underlying stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Endianess Endianess
|
public Endianess Endianess { get; set; } = Endianess.LittleEndian;
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the length of the underlying stream.
|
/// Gets the length of the underlying stream.
|
||||||
@ -101,15 +95,19 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public DataReader(Stream stream)
|
||||||
/// Initializes a new data reader for the specified stream.
|
|
||||||
/// </summary>
|
|
||||||
public DataReader(Stream stream, Endianess endianess = Endianess.LittleEndian)
|
|
||||||
{
|
{
|
||||||
if (stream is not null)
|
if (stream is not null)
|
||||||
{
|
{
|
||||||
this.baseStream = Stream.Synchronized(stream);
|
this.baseStream = Stream.Synchronized(stream);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new data reader for the specified stream.
|
||||||
|
/// </summary>
|
||||||
|
public DataReader(Stream stream, Endianess endianess) : this(stream)
|
||||||
|
{
|
||||||
this.Endianess = endianess;
|
this.Endianess = endianess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +121,25 @@ namespace CodeWalker.GameFiles
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void ReadFromStream(Span<byte> buffer, bool ignoreEndianess = false)
|
||||||
|
{
|
||||||
|
var stream = GetStream();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stream.Read(buffer);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SetPositionAfterRead(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
||||||
|
{
|
||||||
|
buffer.Reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads data from the underlying stream. This is the only method that directly accesses
|
/// Reads data from the underlying stream. This is the only method that directly accesses
|
||||||
/// the data in the underlying stream.
|
/// the data in the underlying stream.
|
||||||
@ -187,7 +204,17 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public short ReadInt16()
|
public short ReadInt16()
|
||||||
{
|
{
|
||||||
return BitConverter.ToInt16(ReadFromStream(2, buffer: _buffer), 0);
|
Span<byte> _buffer = stackalloc byte[sizeof(short)];
|
||||||
|
ReadFromStream(_buffer, true);
|
||||||
|
|
||||||
|
if (Endianess == Endianess.LittleEndian)
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadInt16LittleEndian(_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadInt16BigEndian(_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -195,7 +222,17 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int ReadInt32()
|
public int ReadInt32()
|
||||||
{
|
{
|
||||||
return BitConverter.ToInt32(ReadFromStream(4, buffer: _buffer), 0);
|
Span<byte> _buffer = stackalloc byte[sizeof(int)];
|
||||||
|
ReadFromStream(_buffer, true);
|
||||||
|
|
||||||
|
if (Endianess == Endianess.LittleEndian)
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadInt32LittleEndian(_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadInt32BigEndian(_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -203,7 +240,17 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public long ReadInt64()
|
public long ReadInt64()
|
||||||
{
|
{
|
||||||
return BitConverter.ToInt64(ReadFromStream(8, buffer: _buffer), 0);
|
Span<byte> _buffer = stackalloc byte[sizeof(long)];
|
||||||
|
ReadFromStream(_buffer, true);
|
||||||
|
|
||||||
|
if (Endianess == Endianess.LittleEndian)
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadInt64LittleEndian(_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadInt64BigEndian(_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -211,7 +258,17 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ushort ReadUInt16()
|
public ushort ReadUInt16()
|
||||||
{
|
{
|
||||||
return BitConverter.ToUInt16(ReadFromStream(2, buffer: _buffer), 0);
|
Span<byte> _buffer = stackalloc byte[sizeof(ushort)];
|
||||||
|
ReadFromStream(_buffer, true);
|
||||||
|
|
||||||
|
if (Endianess == Endianess.LittleEndian)
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadUInt16LittleEndian(_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadUInt16BigEndian(_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -219,7 +276,17 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public uint ReadUInt32()
|
public uint ReadUInt32()
|
||||||
{
|
{
|
||||||
return BitConverter.ToUInt32(ReadFromStream(4, buffer: _buffer), 0);
|
Span<byte> _buffer = stackalloc byte[sizeof(uint)];
|
||||||
|
ReadFromStream(_buffer, true);
|
||||||
|
|
||||||
|
if (Endianess == Endianess.LittleEndian)
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadUInt32LittleEndian(_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadUInt32BigEndian(_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -227,7 +294,18 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ulong ReadUInt64()
|
public ulong ReadUInt64()
|
||||||
{
|
{
|
||||||
return BitConverter.ToUInt64(ReadFromStream(8, buffer: _buffer), 0);
|
Span<byte> _buffer = stackalloc byte[sizeof(ulong)];
|
||||||
|
ReadFromStream(_buffer, true);
|
||||||
|
|
||||||
|
if (Endianess == Endianess.LittleEndian)
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadUInt64LittleEndian(_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadUInt64BigEndian(_buffer);
|
||||||
|
}
|
||||||
|
//return BitConverter.ToUInt64(ReadFromStream(_buffer), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -235,7 +313,17 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public float ReadSingle()
|
public float ReadSingle()
|
||||||
{
|
{
|
||||||
return BitConverter.ToSingle(ReadFromStream(4, buffer: _buffer), 0);
|
Span<byte> _buffer = stackalloc byte[sizeof(float)];
|
||||||
|
ReadFromStream(_buffer, true);
|
||||||
|
|
||||||
|
if (Endianess == Endianess.LittleEndian)
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadSingleLittleEndian(_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadSingleBigEndian(_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -243,12 +331,23 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public double ReadDouble()
|
public double ReadDouble()
|
||||||
{
|
{
|
||||||
return BitConverter.ToDouble(ReadFromStream(8, buffer: _buffer), 0);
|
Span<byte> _buffer = stackalloc byte[sizeof(double)];
|
||||||
|
ReadFromStream(_buffer, true);
|
||||||
|
|
||||||
|
if (Endianess == Endianess.LittleEndian)
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadDoubleLittleEndian(_buffer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return BinaryPrimitives.ReadDoubleBigEndian(_buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a string.
|
/// Reads a string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[SkipLocalsInit]
|
||||||
unsafe public string ReadStringLength(int length)
|
unsafe public string ReadStringLength(int length)
|
||||||
{
|
{
|
||||||
if (length == 0)
|
if (length == 0)
|
||||||
@ -268,47 +367,30 @@ namespace CodeWalker.GameFiles
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a string.
|
/// Reads a string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[SkipLocalsInit]
|
||||||
unsafe public string ReadString(int maxLength = 1024)
|
unsafe public string ReadString(int maxLength = 1024)
|
||||||
{
|
{
|
||||||
var bytes = stackalloc byte[Math.Min(maxLength, 1024)];
|
Span<byte> bytes = stackalloc byte[Math.Min(maxLength, 1024)];
|
||||||
var chars = stackalloc char[Math.Min(maxLength, 1024)];
|
Span<char> chars = stackalloc char[Math.Min(maxLength, 1024)];
|
||||||
var temp = ReadByte();
|
var temp = ReadByte();
|
||||||
var charsRead = 0;
|
var bytesRead = 0;
|
||||||
while (temp != 0 && (Length == -1 || Position <= Length))
|
var length = Length;
|
||||||
|
while (temp != 0 && (length == -1 || Position <= length))
|
||||||
{
|
{
|
||||||
if (charsRead < maxLength && charsRead < 1024)
|
if (bytesRead < maxLength && bytesRead < 1024)
|
||||||
{
|
{
|
||||||
bytes[charsRead] = temp;
|
bytes[bytesRead] = temp;
|
||||||
}
|
}
|
||||||
temp = ReadByte();
|
temp = ReadByte();
|
||||||
charsRead++;
|
bytesRead++;
|
||||||
}
|
}
|
||||||
|
|
||||||
var charsCount = Encoding.UTF8.GetChars(bytes, charsRead, chars, Math.Min(maxLength, 1024));
|
var charsRead = Encoding.UTF8.GetChars(bytes.Slice(0, bytesRead), chars);
|
||||||
|
|
||||||
return new string(chars, 0, charsCount);
|
return chars.Slice(0, charsRead).ToString();
|
||||||
//return Encoding.UTF8.GetString(bytes, Math.Min(charsRead, maxLength));
|
//return Encoding.UTF8.GetString(bytes, Math.Min(charsRead, maxLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe public string ReadStringLower()
|
|
||||||
{
|
|
||||||
var bytes = stackalloc byte[1024];
|
|
||||||
var temp = ReadByte();
|
|
||||||
var charsRead = 0;
|
|
||||||
while (temp != 0 && (Length == -1 || Position <= Length))
|
|
||||||
{
|
|
||||||
if (charsRead > 1023)
|
|
||||||
{
|
|
||||||
throw new Exception("String too long!");
|
|
||||||
}
|
|
||||||
bytes[charsRead] = temp;
|
|
||||||
temp = ReadByte();
|
|
||||||
charsRead++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Encoding.UTF8.GetString(bytes, charsRead);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Vector3 ReadVector3()
|
public Vector3 ReadVector3()
|
||||||
{
|
{
|
||||||
|
@ -29,6 +29,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -59,21 +60,33 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public static byte[] DecryptAESData(byte[] data, byte[] key, int length, int rounds = 1)
|
public static byte[] DecryptAESData(byte[] data, byte[] key, int length, int rounds = 1)
|
||||||
{
|
{
|
||||||
var rijndael = Rijndael.Create();
|
using var aes = Aes.Create();
|
||||||
rijndael.KeySize = 256;
|
aes.KeySize = 256;
|
||||||
rijndael.Key = key;
|
aes.Key = key;
|
||||||
rijndael.BlockSize = 128;
|
aes.BlockSize = 128;
|
||||||
rijndael.Mode = CipherMode.ECB;
|
aes.Mode = CipherMode.ECB;
|
||||||
rijndael.Padding = PaddingMode.None;
|
aes.Padding = PaddingMode.None;
|
||||||
|
//var rijndael = Rijndael.Create();
|
||||||
|
//rijndael.KeySize = 256;
|
||||||
|
//rijndael.Key = key;
|
||||||
|
//rijndael.BlockSize = 128;
|
||||||
|
//rijndael.Mode = CipherMode.ECB;
|
||||||
|
//rijndael.Padding = PaddingMode.None;
|
||||||
|
|
||||||
length = length - length % 16;
|
length = length - length % 16;
|
||||||
|
|
||||||
// decrypt...
|
// decrypt...
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
{
|
{
|
||||||
var decryptor = rijndael.CreateDecryptor();
|
using var decryptorAes = aes.CreateDecryptor();
|
||||||
for (var roundIndex = 0; roundIndex < rounds; roundIndex++)
|
for (var roundIndex = 0; roundIndex < rounds; roundIndex++)
|
||||||
decryptor.TransformBlock(data, 0, length, data, 0);
|
{
|
||||||
|
decryptorAes.TransformBlock(data, 0, length, data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//var decryptor = rijndael.CreateDecryptor();
|
||||||
|
//for (var roundIndex = 0; roundIndex < rounds; roundIndex++)
|
||||||
|
// decryptor.TransformBlock(data, 0, length, data, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
@ -104,7 +117,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static uint[][] GetNGKey(string name, uint length)
|
public static uint[][] GetNGKey(string name, uint length)
|
||||||
{
|
{
|
||||||
uint hash = GTA5Hash.CalculateHash(name);
|
uint hash = GTA5Hash.CalculateHash(name);
|
||||||
@ -112,36 +125,39 @@ namespace CodeWalker.GameFiles
|
|||||||
return GTA5Keys.PC_NG_KEYS[keyidx];
|
return GTA5Keys.PC_NG_KEYS[keyidx];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static byte[] DecryptNG(byte[] data, string name, uint fileSize, int offset = 0, int? length = null)
|
public static void DecryptNG(byte[] data, string name, uint fileSize, int offset = 0, int? length = null)
|
||||||
{
|
{
|
||||||
var key = GetNGKey(name, fileSize);
|
var key = GetNGKey(name, fileSize);
|
||||||
return DecryptNG(data, key, offset, length);
|
length ??= data.Length;
|
||||||
|
DecryptNG(data.AsSpan(offset, length.Value), key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe static byte[] DecryptNG(byte[] data, uint[][] key, int offset = 0, int? length = null)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void DecryptNG(Span<byte> data, string name, uint fileSize)
|
||||||
|
{
|
||||||
|
var key = GetNGKey(name, fileSize);
|
||||||
|
DecryptNG(data, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public unsafe static void DecryptNG(byte[] data, uint[][] key, int offset = 0, int? length = null)
|
||||||
{
|
{
|
||||||
length ??= data.Length;
|
length ??= data.Length;
|
||||||
fixed (byte* bptr = data)
|
DecryptNG(data.AsSpan(offset, length.Value), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void DecryptNG(Span<byte> data, uint[][] key)
|
||||||
{
|
{
|
||||||
for (int blockIndex = offset * 16; blockIndex < length / 16; blockIndex++)
|
for (int blockIndex = 0; blockIndex < data.Length / 16; blockIndex++)
|
||||||
{
|
{
|
||||||
DecryptNGBlock(bptr + 16 * blockIndex, key);
|
DecryptNGBlock(data.Slice(16 * blockIndex, 16), key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
}
|
public static void DecryptNGBlock(Span<byte> data, uint[][] key)
|
||||||
|
|
||||||
public unsafe static void DecryptNGBlock(byte[] data, uint[][] key)
|
|
||||||
{
|
|
||||||
fixed(byte* bptr = data)
|
|
||||||
{
|
|
||||||
DecryptNGBlock(data, key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe static void DecryptNGBlock(byte* data, uint[][] key)
|
|
||||||
{
|
{
|
||||||
DecryptNGRoundA(data, key[0], GTA5Keys.PC_NG_DECRYPT_TABLES[0]);
|
DecryptNGRoundA(data, key[0], GTA5Keys.PC_NG_DECRYPT_TABLES[0]);
|
||||||
DecryptNGRoundA(data, key[1], GTA5Keys.PC_NG_DECRYPT_TABLES[1]);
|
DecryptNGRoundA(data, key[1], GTA5Keys.PC_NG_DECRYPT_TABLES[1]);
|
||||||
@ -150,24 +166,8 @@ namespace CodeWalker.GameFiles
|
|||||||
DecryptNGRoundA(data, key[16], GTA5Keys.PC_NG_DECRYPT_TABLES[16]);
|
DecryptNGRoundA(data, key[16], GTA5Keys.PC_NG_DECRYPT_TABLES[16]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe static void DecryptNGRoundA(byte[] data, uint[] key, uint[][] table)
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
{
|
public static void DecryptNGRoundA(Span<byte> data, uint[] key, uint[][] table)
|
||||||
fixed(byte* bptr = data)
|
|
||||||
{
|
|
||||||
DecryptNGRoundA(bptr, key, table);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public unsafe static void DecryptNGRoundB(byte[] data, uint[] key, uint[][] table)
|
|
||||||
{
|
|
||||||
fixed (byte* bptr = data)
|
|
||||||
{
|
|
||||||
DecryptNGRoundB(bptr, key, table);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// round 1,2,16
|
|
||||||
public unsafe static void DecryptNGRoundA(byte* data, uint[] key, uint[][] table)
|
|
||||||
{
|
{
|
||||||
var x1 =
|
var x1 =
|
||||||
table[0][data[0]] ^
|
table[0][data[0]] ^
|
||||||
@ -194,14 +194,16 @@ namespace CodeWalker.GameFiles
|
|||||||
table[15][data[15]] ^
|
table[15][data[15]] ^
|
||||||
key[3];
|
key[3];
|
||||||
|
|
||||||
*(uint*)data = x1;
|
MemoryMarshal.Write(data.Slice(0, 4), ref x1);
|
||||||
*(uint*)(data + 4) = x2;
|
MemoryMarshal.Write(data.Slice(4, 4), ref x2);
|
||||||
*(uint*)(data + 8) = x3;
|
MemoryMarshal.Write(data.Slice(8, 4), ref x3);
|
||||||
*(uint*)(data + 12) = x4;
|
MemoryMarshal.Write(data.Slice(12, 4), ref x4);
|
||||||
}
|
}
|
||||||
|
|
||||||
// round 3-15
|
// round 3-15
|
||||||
public unsafe static void DecryptNGRoundB(byte* data, uint[] key, uint[][] table)
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public unsafe static void DecryptNGRoundB(Span<byte> data, uint[] key, uint[][] table)
|
||||||
{
|
{
|
||||||
var x1 =
|
var x1 =
|
||||||
table[0][data[0]] ^
|
table[0][data[0]] ^
|
||||||
@ -228,10 +230,10 @@ namespace CodeWalker.GameFiles
|
|||||||
table[12][data[12]] ^
|
table[12][data[12]] ^
|
||||||
key[3];
|
key[3];
|
||||||
|
|
||||||
*(uint*)data = x1;
|
MemoryMarshal.Write(data.Slice(0, 4), ref x1);
|
||||||
*(uint*)(data + 4) = x2;
|
MemoryMarshal.Write(data.Slice(4, 4), ref x2);
|
||||||
*(uint*)(data + 8) = x3;
|
MemoryMarshal.Write(data.Slice(8, 4), ref x3);
|
||||||
*(uint*)(data + 12) = x4;
|
MemoryMarshal.Write(data.Slice(12, 4), ref x4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -248,8 +250,6 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static byte[] EncryptNG(byte[] data, string name, uint length)
|
public static byte[] EncryptNG(byte[] data, string name, uint length)
|
||||||
{
|
{
|
||||||
var key = GetNGKey(name, length);
|
var key = GetNGKey(name, length);
|
||||||
@ -396,136 +396,5 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class DecryptNGStream : Stream
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
private long _length = 0;
|
|
||||||
|
|
||||||
private Stream _baseStream;
|
|
||||||
|
|
||||||
public Stream BaseStream { get => _baseStream; private set => _baseStream = value; }
|
|
||||||
|
|
||||||
public uint[][] Key { get; set; }
|
|
||||||
private long offset = 0;
|
|
||||||
|
|
||||||
public override long Length
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_length != 0) return _length;
|
|
||||||
return _baseStream.Length - offset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private DecryptNGStream(string name, uint length)
|
|
||||||
{
|
|
||||||
_length = length;
|
|
||||||
Name = name;
|
|
||||||
Key = GTACrypto.GetNGKey(name, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DecryptNGStream(byte[] data, string name, uint fileSize) : this(name, fileSize)
|
|
||||||
{
|
|
||||||
BaseStream = new MemoryStream(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DecryptNGStream(Stream data, string name, uint fileSize) : this(name, fileSize)
|
|
||||||
{
|
|
||||||
BaseStream = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DecryptNGStream(Stream data, string name, uint fileSize, int start, int length = 0): this(data, name, fileSize)
|
|
||||||
{
|
|
||||||
this.offset = start;
|
|
||||||
this._length = length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanRead => _baseStream.CanRead;
|
|
||||||
|
|
||||||
public override bool CanSeek => _baseStream.CanSeek;
|
|
||||||
|
|
||||||
public override bool CanWrite => _baseStream.CanWrite;
|
|
||||||
|
|
||||||
public override long Position
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var position = _baseStream.Position - offset;
|
|
||||||
|
|
||||||
position = position - position % 16;
|
|
||||||
return position + positionInBuffer;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
positionInBuffer = 0;
|
|
||||||
_baseStream.Position = (value + offset);
|
|
||||||
ReadBlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Flush()
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ReadBlock()
|
|
||||||
{
|
|
||||||
_baseStream.Read(_buffer, 0, _buffer.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] _buffer = new byte[16];
|
|
||||||
private byte positionInBuffer = 0;
|
|
||||||
public override int Read(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
if (positionInBuffer > 0)
|
|
||||||
{
|
|
||||||
var toCopy = (byte)Math.Min(16 - positionInBuffer, count);
|
|
||||||
Array.Copy(_buffer, positionInBuffer, buffer, offset, toCopy);
|
|
||||||
positionInBuffer += toCopy;
|
|
||||||
if (positionInBuffer >= 16)
|
|
||||||
{
|
|
||||||
positionInBuffer = 0;
|
|
||||||
}
|
|
||||||
offset += toCopy;
|
|
||||||
count -= toCopy;
|
|
||||||
}
|
|
||||||
var i = 0;
|
|
||||||
while (count >= 16)
|
|
||||||
{
|
|
||||||
_baseStream.Read(buffer, offset + i, 16);
|
|
||||||
i += 16;
|
|
||||||
}
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
_baseStream.Read(_buffer, 0, 16);
|
|
||||||
GTACrypto.DecryptNG(_buffer, Key, 0, 16);
|
|
||||||
Array.Copy(_buffer, positionInBuffer, buffer, offset + i, count - i);
|
|
||||||
positionInBuffer += (byte)(count - i);
|
|
||||||
}
|
|
||||||
var data = _baseStream.Read(buffer, offset, count);
|
|
||||||
|
|
||||||
GTACrypto.DecryptNG(buffer, Key, offset, count);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override long Seek(long offset, SeekOrigin origin)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetLength(long value)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Write(byte[] buffer, int offset, int count)
|
|
||||||
{
|
|
||||||
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,8 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -69,15 +71,15 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static void Generate(byte[] exeData, Action<string> updateStatus) //Stream exeStr)//
|
public static void Generate(byte[] exeData, Action<string>? updateStatus) //Stream exeStr)//
|
||||||
{
|
{
|
||||||
var exeStr = new MemoryStream(exeData);
|
var exeStr = Stream.Synchronized(new MemoryStream(exeData));
|
||||||
|
|
||||||
updateStatus("Searching for AES key...");
|
updateStatus?.Invoke("Searching for AES key...");
|
||||||
PC_AES_KEY = HashSearch.SearchHash(exeStr, GTA5KeyHashes.PC_AES_KEY_HASH, 32);
|
PC_AES_KEY = HashSearch.SearchHash(exeStr, GTA5KeyHashes.PC_AES_KEY_HASH, 32);
|
||||||
//updateStatus("aes key found");
|
//updateStatus("aes key found");
|
||||||
|
|
||||||
updateStatus("Searching for NG keys...");
|
updateStatus?.Invoke("Searching for NG keys...");
|
||||||
//PC_NG_KEYS = HashSearch.SearchHashes(exeStr, GTA5KeyHashes.PC_NG_KEY_HASHES, 272);
|
//PC_NG_KEYS = HashSearch.SearchHashes(exeStr, GTA5KeyHashes.PC_NG_KEY_HASHES, 272);
|
||||||
var tabs = HashSearch.SearchHashes(exeStr, GTA5KeyHashes.PC_NG_KEY_HASHES, 272);
|
var tabs = HashSearch.SearchHashes(exeStr, GTA5KeyHashes.PC_NG_KEY_HASHES, 272);
|
||||||
PC_NG_KEYS = new uint[tabs.Length][][];
|
PC_NG_KEYS = new uint[tabs.Length][][];
|
||||||
@ -92,31 +94,21 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
//updateStatus("ng keys found");
|
//updateStatus("ng keys found");
|
||||||
|
|
||||||
updateStatus("Searching for NG decrypt tables...");
|
updateStatus?.Invoke("Searching for NG decrypt tables...");
|
||||||
tabs = HashSearch.SearchHashes(exeStr, GTA5KeyHashes.PC_NG_DECRYPT_TABLE_HASHES, 1024);
|
tabs = HashSearch.SearchHashes(exeStr, GTA5KeyHashes.PC_NG_DECRYPT_TABLE_HASHES, 1024);
|
||||||
//updateStatus("ng decrypt tables found");
|
//updateStatus("ng decrypt tables found");
|
||||||
|
|
||||||
updateStatus("Searching for NG hash lookup tables...");
|
updateStatus?.Invoke("Searching for NG hash lookup tables...");
|
||||||
// 17 rounds
|
// 17 rounds
|
||||||
PC_NG_DECRYPT_TABLES = new uint[17][][];
|
LoadPCNGDecryptTable(tabs);
|
||||||
for (int i = 0; i < 17; i++)
|
|
||||||
{
|
|
||||||
//
|
|
||||||
PC_NG_DECRYPT_TABLES[i] = new uint[16][];
|
|
||||||
for (int j = 0; j < 16; j++)
|
|
||||||
{
|
|
||||||
var buf = tabs[j + 16 * i];
|
|
||||||
PC_NG_DECRYPT_TABLES[i][j] = new uint[256];
|
|
||||||
Buffer.BlockCopy(buf, 0, PC_NG_DECRYPT_TABLES[i][j], 0, 1024);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PC_LUT = HashSearch.SearchHash(exeStr, GTA5KeyHashes.PC_LUT_HASH, 0x100);
|
PC_LUT = HashSearch.SearchHash(exeStr, GTA5KeyHashes.PC_LUT_HASH, 0x100);
|
||||||
//updateStatus("ng hash LUTs found");
|
//updateStatus("ng hash LUTs found");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
updateStatus("Calculating NG encryption tables...");
|
updateStatus?.Invoke("Calculating NG encryption tables...");
|
||||||
|
|
||||||
PC_NG_ENCRYPT_TABLES = new uint[17][][];
|
PC_NG_ENCRYPT_TABLES = new uint[17][][];
|
||||||
for (int i = 0; i < 17; i++)
|
for (int i = 0; i < 17; i++)
|
||||||
{
|
{
|
||||||
@ -142,28 +134,62 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
updateStatus("Calculating NG encryption tables (1/17)...");
|
updateStatus?.Invoke("Calculating NG encryption tables (1/17)...");
|
||||||
PC_NG_ENCRYPT_TABLES[0] = RandomGauss.Solve(PC_NG_DECRYPT_TABLES[0]);
|
PC_NG_ENCRYPT_TABLES[0] = RandomGauss.Solve(PC_NG_DECRYPT_TABLES[0]);
|
||||||
//updateStatus("ng encrypt table 1 of 17 calculated");
|
//updateStatus("ng encrypt table 1 of 17 calculated");
|
||||||
|
|
||||||
updateStatus("Calculating NG encryption tables (2/17)...");
|
updateStatus?.Invoke("Calculating NG encryption tables (2/17)...");
|
||||||
PC_NG_ENCRYPT_TABLES[1] = RandomGauss.Solve(PC_NG_DECRYPT_TABLES[1]);
|
PC_NG_ENCRYPT_TABLES[1] = RandomGauss.Solve(PC_NG_DECRYPT_TABLES[1]);
|
||||||
//updateStatus("ng encrypt table 2 of 17 calculated");
|
//updateStatus("ng encrypt table 2 of 17 calculated");
|
||||||
|
|
||||||
for (int k = 2; k <= 15; k++)
|
for (int k = 2; k <= 15; k++)
|
||||||
{
|
{
|
||||||
updateStatus("Calculating NG encryption tables (" + (k + 1).ToString() + "/17)...");
|
updateStatus?.Invoke("Calculating NG encryption tables (" + (k + 1).ToString() + "/17)...");
|
||||||
PC_NG_ENCRYPT_LUTs[k] = LookUpTableGenerator.BuildLUTs2(PC_NG_DECRYPT_TABLES[k]);
|
PC_NG_ENCRYPT_LUTs[k] = LookUpTableGenerator.BuildLUTs2(PC_NG_DECRYPT_TABLES[k]);
|
||||||
//updateStatus("ng encrypt table " + (k + 1).ToString() + " of 17 calculated");
|
//updateStatus("ng encrypt table " + (k + 1).ToString() + " of 17 calculated");
|
||||||
}
|
}
|
||||||
|
|
||||||
updateStatus("Calculating NG encryption tables (17/17)...");
|
updateStatus?.Invoke("Calculating NG encryption tables (17/17)...");
|
||||||
PC_NG_ENCRYPT_TABLES[16] = RandomGauss.Solve(PC_NG_DECRYPT_TABLES[16]);
|
PC_NG_ENCRYPT_TABLES[16] = RandomGauss.Solve(PC_NG_DECRYPT_TABLES[16]);
|
||||||
//updateStatus("ng encrypt table 17 of 17 calculated");
|
//updateStatus("ng encrypt table 17 of 17 calculated");
|
||||||
|
|
||||||
updateStatus("Complete.");
|
updateStatus?.Invoke("Complete.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void LoadPCNGDecryptTable(Span<byte> rawFlattenedKey)
|
||||||
|
{
|
||||||
|
PC_NG_DECRYPT_TABLES = new uint[17][][];
|
||||||
|
var flattenedKey = MemoryMarshal.Cast<byte, uint>(rawFlattenedKey);
|
||||||
|
for (int i = 0; i < 17; i++)
|
||||||
|
{
|
||||||
|
PC_NG_DECRYPT_TABLES[i] = new uint[16][];
|
||||||
|
for (int j = 0; j < 16; j++)
|
||||||
|
{
|
||||||
|
var buf = flattenedKey.Slice(0, 256);
|
||||||
|
flattenedKey = flattenedKey.Slice(256);
|
||||||
|
PC_NG_DECRYPT_TABLES[i][j] = new uint[256];
|
||||||
|
|
||||||
|
buf.CopyTo(PC_NG_DECRYPT_TABLES[i][j].AsSpan());
|
||||||
|
//Buffer.BlockCopy(buf, 0, PC_NG_DECRYPT_TABLES[i][j], 0, 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LoadPCNGDecryptTable(byte[][] rawKey)
|
||||||
|
{
|
||||||
|
PC_NG_DECRYPT_TABLES = new uint[17][][];
|
||||||
|
for (int i = 0; i < 17; i++)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
PC_NG_DECRYPT_TABLES[i] = new uint[16][];
|
||||||
|
for (int j = 0; j < 16; j++)
|
||||||
|
{
|
||||||
|
var buf = rawKey[j + 16 * i];
|
||||||
|
PC_NG_DECRYPT_TABLES[i][j] = new uint[256];
|
||||||
|
Buffer.BlockCopy(buf, 0, PC_NG_DECRYPT_TABLES[i][j], 0, 1024);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void GenerateV2(byte[] exeData, Action<string> updateStatus)
|
public static void GenerateV2(byte[] exeData, Action<string> updateStatus)
|
||||||
{
|
{
|
||||||
@ -175,10 +201,14 @@ namespace CodeWalker.GameFiles
|
|||||||
updateStatus?.Invoke("Complete.");
|
updateStatus?.Invoke("Complete.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool keysLoaded = false;
|
||||||
|
|
||||||
public static void LoadFromPath(string path = ".\\Keys", string key = null)
|
public static void LoadFromPath(string path = ".\\Keys", string key = null)
|
||||||
{
|
{
|
||||||
|
if (keysLoaded)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
//PC_AES_KEY = File.ReadAllBytes(path + "\\gtav_aes_key.dat");
|
//PC_AES_KEY = File.ReadAllBytes(path + "\\gtav_aes_key.dat");
|
||||||
//PC_NG_KEYS = CryptoIO.ReadNgKeys(path + "\\gtav_ng_key.dat");
|
//PC_NG_KEYS = CryptoIO.ReadNgKeys(path + "\\gtav_ng_key.dat");
|
||||||
//PC_NG_DECRYPT_TABLES = CryptoIO.ReadNgTables(path + "\\gtav_ng_decrypt_tables.dat");
|
//PC_NG_DECRYPT_TABLES = CryptoIO.ReadNgTables(path + "\\gtav_ng_decrypt_tables.dat");
|
||||||
@ -188,6 +218,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
//GenerateMagicData(path);
|
//GenerateMagicData(path);
|
||||||
UseMagicData(path, key);
|
UseMagicData(path, key);
|
||||||
|
keysLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveToPath(string path = ".\\Keys")
|
public static void SaveToPath(string path = ".\\Keys")
|
||||||
@ -298,7 +329,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
using (MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream())
|
using (MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream())
|
||||||
{
|
{
|
||||||
ds.CopyToFast(outstr);
|
ds.CopyTo(outstr);
|
||||||
b = outstr.GetBuffer();
|
b = outstr.GetBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -760,11 +791,12 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public static byte[][] SearchHashes(Stream stream, IList<byte[]> hashes, int length = 32)
|
public static byte[][] SearchHashes(Stream stream, IList<byte[]> hashes, int length = 32)
|
||||||
{
|
{
|
||||||
|
stream = Stream.Synchronized(stream);
|
||||||
var result = new byte[hashes.Count][];
|
var result = new byte[hashes.Count][];
|
||||||
|
|
||||||
Parallel.For(0, (stream.Length / BLOCK_LENGTH), (long k) => {
|
Parallel.For(0, (stream.Length / BLOCK_LENGTH), (long k) => {
|
||||||
|
|
||||||
var hashProvider = new SHA1CryptoServiceProvider();
|
var hashProvider = new SHA1CryptoServiceProvider();
|
||||||
|
// TODO: Convert to stack alloc when length appropriate (1024 or lower probs)
|
||||||
var buffer = new byte[length];
|
var buffer = new byte[length];
|
||||||
for (long i = 0; i < (BLOCK_LENGTH / ALIGN_LENGTH); i++)
|
for (long i = 0; i < (BLOCK_LENGTH / ALIGN_LENGTH); i++)
|
||||||
{
|
{
|
||||||
@ -772,11 +804,9 @@ namespace CodeWalker.GameFiles
|
|||||||
if (position >= stream.Length)
|
if (position >= stream.Length)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
lock (stream)
|
|
||||||
{
|
|
||||||
stream.Position = position;
|
stream.Position = position;
|
||||||
stream.Read(buffer, 0, length);
|
stream.Read(buffer, 0, length);
|
||||||
}
|
|
||||||
|
|
||||||
var hash = hashProvider.ComputeHash(buffer);
|
var hash = hashProvider.ComputeHash(buffer);
|
||||||
for (int j = 0; j < hashes.Count; j++)
|
for (int j = 0; j < hashes.Count; j++)
|
||||||
@ -852,7 +882,7 @@ namespace CodeWalker.GameFiles
|
|||||||
firstPivot.SetB();
|
firstPivot.SetB();
|
||||||
pivots.Add(firstPivot);
|
pivots.Add(firstPivot);
|
||||||
|
|
||||||
var buf_encrypted = new byte[16];
|
Span<byte> buf_encrypted = stackalloc byte[16];
|
||||||
for (int pivotIdx = 1; pivotIdx < 1024; pivotIdx++)
|
for (int pivotIdx = 1; pivotIdx < 1024; pivotIdx++)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
@ -1221,7 +1251,7 @@ namespace CodeWalker.GameFiles
|
|||||||
using (var fs = new FileStream(fileName, FileMode.Create))
|
using (var fs = new FileStream(fileName, FileMode.Create))
|
||||||
{
|
{
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
ms.CopyToFast(fs);
|
ms.CopyTo(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1308,7 +1338,7 @@ namespace CodeWalker.GameFiles
|
|||||||
using (var fs = new FileStream(fileName, FileMode.Create))
|
using (var fs = new FileStream(fileName, FileMode.Create))
|
||||||
{
|
{
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
ms.CopyToFast(fs);
|
ms.CopyTo(fs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1446,7 +1476,7 @@ namespace CodeWalker.GameFiles
|
|||||||
using (var fs = new FileStream(fileName, FileMode.Create))
|
using (var fs = new FileStream(fileName, FileMode.Create))
|
||||||
{
|
{
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
ms.CopyToFast(fs);
|
ms.CopyTo(fs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1463,6 +1493,7 @@ namespace CodeWalker.GameFiles
|
|||||||
LUT = GTA5Keys.PC_LUT;
|
LUT = GTA5Keys.PC_LUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static uint CalculateHash(string text)
|
public static uint CalculateHash(string text)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -276,7 +276,8 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public static class JenkIndex
|
public static class JenkIndex
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<uint, string> Index = new ConcurrentDictionary<uint, string>(32, 1500000);
|
//public static ConcurrentDictionary<uint, string> Index = new ConcurrentDictionary<uint, string>(Environment.ProcessorCount * 2, 2000000);
|
||||||
|
public static Dictionary<uint, string> Index = new Dictionary<uint, string>(2000000);
|
||||||
|
|
||||||
public static void Ensure(string str)
|
public static void Ensure(string str)
|
||||||
{
|
{
|
||||||
@ -293,7 +294,25 @@ namespace CodeWalker.GameFiles
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Index.TryAdd(hash, str);
|
lock(Index)
|
||||||
|
{
|
||||||
|
Index[hash] = str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Ensure(ReadOnlySpan<char> str, uint hash)
|
||||||
|
{
|
||||||
|
if (hash == 0) return;
|
||||||
|
|
||||||
|
if (Index.ContainsKey(hash))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock(Index)
|
||||||
|
{
|
||||||
|
Index[hash] = str.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EnsureLower(string str)
|
public static void EnsureLower(string str)
|
||||||
@ -302,6 +321,12 @@ namespace CodeWalker.GameFiles
|
|||||||
Ensure(str, hash);
|
Ensure(str, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EnsureLower(ReadOnlySpan<char> str)
|
||||||
|
{
|
||||||
|
uint hash = JenkHash.GenHashLower(str);
|
||||||
|
Ensure(str, hash);
|
||||||
|
}
|
||||||
|
|
||||||
public static void EnsureBoth(string str)
|
public static void EnsureBoth(string str)
|
||||||
{
|
{
|
||||||
uint hash = JenkHash.GenHash(str);
|
uint hash = JenkHash.GenHash(str);
|
||||||
@ -312,25 +337,15 @@ namespace CodeWalker.GameFiles
|
|||||||
Ensure(str, hashLower);
|
Ensure(str, hashLower);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static void AddRange(params string[] strings)
|
|
||||||
{
|
|
||||||
foreach(var s in strings)
|
|
||||||
{
|
|
||||||
uint hash = JenkHash.GenHash(s);
|
|
||||||
if (hash == 0) continue;
|
|
||||||
|
|
||||||
Index[hash] = s;
|
public static void EnsureBoth(ReadOnlySpan<char> str)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AddRangeLower(params string[] strings)
|
|
||||||
{
|
{
|
||||||
foreach (var s in strings)
|
uint hash = JenkHash.GenHash(str);
|
||||||
|
uint hashLower = JenkHash.GenHashLower(str);
|
||||||
|
Ensure(str, hash);
|
||||||
|
if (hash != hashLower)
|
||||||
{
|
{
|
||||||
uint hash = JenkHash.GenHashLower(s);
|
Ensure(str, hashLower);
|
||||||
if (hash == 0) continue;
|
|
||||||
|
|
||||||
Index[hash] = s;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,10 +196,6 @@ namespace CodeWalker.GameFiles
|
|||||||
var rel3 = XmlRel.GetRel(relxml);
|
var rel3 = XmlRel.GetRel(relxml);
|
||||||
if (rel3 != null)
|
if (rel3 != null)
|
||||||
{
|
{
|
||||||
if (rel3.RelDatasSorted?.Length != rel.RelDatasSorted?.Length)
|
|
||||||
{ } //check nothing went missing...
|
|
||||||
|
|
||||||
|
|
||||||
data = rel3.Save(); //full roundtrip!
|
data = rel3.Save(); //full roundtrip!
|
||||||
if (data != null)
|
if (data != null)
|
||||||
{
|
{
|
||||||
|
43
CodeWalker.Core/Utils/ETWEvents.cs
Normal file
43
CodeWalker.Core/Utils/ETWEvents.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.Tracing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CodeWalker.Core.Utils;
|
||||||
|
|
||||||
|
[EventSource(Name = "CodeWalker-Diagnostics")]
|
||||||
|
public class ETWEvents : EventSource
|
||||||
|
{
|
||||||
|
public static class Keywords
|
||||||
|
{
|
||||||
|
public const EventKeywords ComponentLifespan = (EventKeywords)1;
|
||||||
|
public const EventKeywords StateChanges = (EventKeywords)(1 << 1);
|
||||||
|
public const EventKeywords Performance = (EventKeywords)(1 << 2);
|
||||||
|
public const EventKeywords DumpState = (EventKeywords)(1 << 3);
|
||||||
|
public const EventKeywords StateTracking = (EventKeywords)(1 << 4);
|
||||||
|
}
|
||||||
|
internal static class DebugCounters
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ETWEvents(bool throwOnEventWriteErrors) : base(throwOnEventWriteErrors)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
[Event(1, Message = "Starting up.", Keywords = Keywords.Performance, Level = EventLevel.Informational)]
|
||||||
|
public void Startup() {
|
||||||
|
WriteEvent(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Event(2, Message = "Creating form {0}", Keywords = Keywords.Performance | Keywords.StateChanges, Level = EventLevel.Verbose)]
|
||||||
|
public void CreatingForm(string form) { WriteEvent(2, form); }
|
||||||
|
|
||||||
|
[Event(3, Message = "Loading form {0}", Keywords = Keywords.Performance | Keywords.StateChanges, Level = EventLevel.Verbose)]
|
||||||
|
public void LoadingForm(string form) { WriteEvent(3, form); }
|
||||||
|
|
||||||
|
public static readonly ETWEvents Log = new ETWEvents(true);
|
||||||
|
}
|
94
CodeWalker.Core/Utils/SplitEnumerator.cs
Normal file
94
CodeWalker.Core/Utils/SplitEnumerator.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CodeWalker.Core.Utils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enumerates the lines of a <see cref="ReadOnlySpan{Char}"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// To get an instance of this type, use <see cref="MemoryExtensions.EnumerateLines(ReadOnlySpan{char})"/>.
|
||||||
|
/// </remarks>
|
||||||
|
public ref struct SpanSplitEnumerator
|
||||||
|
{
|
||||||
|
private ReadOnlySpan<char> _remaining;
|
||||||
|
private ReadOnlySpan<char> _current;
|
||||||
|
private bool _isEnumeratorActive;
|
||||||
|
private char _splitBy;
|
||||||
|
|
||||||
|
internal SpanSplitEnumerator(ReadOnlySpan<char> buffer, char splitBy)
|
||||||
|
{
|
||||||
|
_remaining = buffer;
|
||||||
|
_current = default;
|
||||||
|
_isEnumeratorActive = true;
|
||||||
|
_splitBy = splitBy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the line at the current position of the enumerator.
|
||||||
|
/// </summary>
|
||||||
|
public ReadOnlySpan<char> Current => _current;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns this instance as an enumerator.
|
||||||
|
/// </summary>
|
||||||
|
public SpanSplitEnumerator GetEnumerator() => this;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Advances the enumerator to the next line of the span.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// True if the enumerator successfully advanced to the next line; false if
|
||||||
|
/// the enumerator has advanced past the end of the span.
|
||||||
|
/// </returns>
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (!_isEnumeratorActive)
|
||||||
|
{
|
||||||
|
return false; // EOF previously reached or enumerator was never initialized
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadOnlySpan<char> remaining = _remaining;
|
||||||
|
|
||||||
|
int idx = remaining.IndexOf(_splitBy);
|
||||||
|
|
||||||
|
if ((uint)idx < (uint)remaining.Length)
|
||||||
|
{
|
||||||
|
_current = remaining.Slice(0, idx);
|
||||||
|
_remaining = remaining.Slice(idx + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We've reached EOF, but we still need to return 'true' for this final
|
||||||
|
// iteration so that the caller can query the Current property once more.
|
||||||
|
|
||||||
|
_current = remaining;
|
||||||
|
_remaining = default;
|
||||||
|
_isEnumeratorActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class EnumerateSplitExtensions
|
||||||
|
{
|
||||||
|
public static SpanSplitEnumerator EnumerateSplit(this ReadOnlySpan<char> span, char splitBy)
|
||||||
|
{
|
||||||
|
return new SpanSplitEnumerator(span, splitBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpanSplitEnumerator EnumerateSplit(this Span<char> span, char splitBy)
|
||||||
|
{
|
||||||
|
return new SpanSplitEnumerator(span, splitBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpanSplitEnumerator EnumerateSplit(this string str, char splitBy)
|
||||||
|
{
|
||||||
|
return new SpanSplitEnumerator(str.AsSpan(), splitBy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Buffers.Binary;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -16,152 +17,45 @@ namespace CodeWalker.Core.Utils
|
|||||||
{
|
{
|
||||||
return br.BaseStream.ReadAsync(buffer, index, count);
|
return br.BaseStream.ReadAsync(buffer, index, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void CopyToFast(this Stream stream, Stream destination)
|
|
||||||
{
|
|
||||||
var buffer = ArrayPool<byte>.Shared.Rent(81920);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int read;
|
|
||||||
while ((read = stream.Read(buffer, 0, buffer.Length)) != 0)
|
|
||||||
destination.Write(buffer, 0, read);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task CopyToFastAsync(this Stream stream, Stream destination, int bufferSize = 131072, CancellationToken cancellationToken = default)
|
public ref struct SpanStream
|
||||||
{
|
{
|
||||||
var buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
|
public Span<byte> Buffer { get; private set; }
|
||||||
try
|
private int _position;
|
||||||
|
|
||||||
|
public SpanStream(Span<byte> buffer)
|
||||||
{
|
{
|
||||||
int bytesRead;
|
Buffer = buffer;
|
||||||
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
_position = 0;
|
||||||
{
|
|
||||||
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception ex)
|
|
||||||
{
|
|
||||||
Console.WriteLine(ex.ToString());
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<byte>.Shared.Return(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ReadOnlySpan<byte> InternalRead(int count)
|
||||||
|
{
|
||||||
|
int origPos = _position;
|
||||||
|
int newPos = origPos + count;
|
||||||
|
|
||||||
|
if ((uint)newPos > (uint)Buffer.Length)
|
||||||
|
{
|
||||||
|
_position = Buffer.Length;
|
||||||
|
ThrowHelper.ThrowEndOfFileException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task FinishWriteAsync(Task writeTask, byte[] localBuffer)
|
var span = Buffer.Slice(origPos, count);
|
||||||
{
|
_position = newPos;
|
||||||
try
|
return span;
|
||||||
{
|
|
||||||
await writeTask.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<byte>.Shared.Return(localBuffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ValueTask WriteAsync(this Stream stream, Memory<byte> buffer, CancellationToken cancellationToken = default)
|
public short ReadInt16() => BinaryPrimitives.ReadInt16LittleEndian(InternalRead(sizeof(short)));
|
||||||
{
|
|
||||||
if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> array))
|
|
||||||
{
|
|
||||||
return new ValueTask(stream.WriteAsync(array.Array!, array.Offset, array.Count, cancellationToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
public ushort ReadUInt16() => BinaryPrimitives.ReadUInt16LittleEndian(InternalRead(sizeof(ushort)));
|
||||||
buffer.Span.CopyTo(sharedBuffer);
|
|
||||||
return new ValueTask(FinishWriteAsync(stream.WriteAsync(sharedBuffer, 0, buffer.Length, cancellationToken), sharedBuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Write(this Stream stream, ReadOnlySpan<byte> buffer)
|
public int ReadInt32() => BinaryPrimitives.ReadInt32LittleEndian(InternalRead(sizeof(int)));
|
||||||
{
|
public uint ReadUInt32() => BinaryPrimitives.ReadUInt32LittleEndian(InternalRead(sizeof(uint)));
|
||||||
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
public long ReadInt64() => BinaryPrimitives.ReadInt64LittleEndian(InternalRead(sizeof(long)));
|
||||||
try
|
public ulong ReadUInt64() => BinaryPrimitives.ReadUInt64LittleEndian(InternalRead(sizeof(ulong)));
|
||||||
{
|
public unsafe Half ReadHalf() => BinaryPrimitives.ReadHalfLittleEndian(InternalRead(sizeof(Half)));
|
||||||
buffer.CopyTo(sharedBuffer);
|
public unsafe float ReadSingle() => BinaryPrimitives.ReadSingleLittleEndian(InternalRead(sizeof(float)));
|
||||||
stream.Write(sharedBuffer, 0, buffer.Length);
|
public unsafe double ReadDouble() => BinaryPrimitives.ReadDoubleLittleEndian(InternalRead(sizeof(double)));
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<byte>.Shared.Return(sharedBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Read(this Stream stream, Span<byte> buffer)
|
|
||||||
{
|
|
||||||
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int numRead = stream.Read(sharedBuffer, 0, buffer.Length);
|
|
||||||
if ((uint)numRead > (uint)buffer.Length)
|
|
||||||
{
|
|
||||||
throw new IOException("Stream too long!");
|
|
||||||
}
|
|
||||||
|
|
||||||
new ReadOnlySpan<byte>(sharedBuffer, 0, numRead).CopyTo(buffer);
|
|
||||||
return numRead;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<byte>.Shared.Return(sharedBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Read(this Stream stream, Memory<byte> buffer)
|
|
||||||
{
|
|
||||||
if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> array))
|
|
||||||
{
|
|
||||||
return stream.Read(array.Array!, array.Offset, array.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int numRead = stream.Read(sharedBuffer, 0, buffer.Length);
|
|
||||||
if ((uint)numRead > (uint)buffer.Length)
|
|
||||||
{
|
|
||||||
throw new IOException("Stream too long!");
|
|
||||||
}
|
|
||||||
|
|
||||||
new ReadOnlySpan<byte>(sharedBuffer, 0, numRead).CopyTo(buffer.Span);
|
|
||||||
return numRead;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<byte>.Shared.Return(sharedBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ValueTask<int> ReadAsync(this Stream stream, Memory<byte> buffer, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> array))
|
|
||||||
{
|
|
||||||
return new ValueTask<int>(stream.ReadAsync(array.Array!, array.Offset, array.Count, cancellationToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
|
||||||
return FinishReadAsync(stream.ReadAsync(sharedBuffer, 0, buffer.Length, cancellationToken), sharedBuffer, buffer);
|
|
||||||
|
|
||||||
static async ValueTask<int> FinishReadAsync(Task<int> readTask, byte[] localBuffer, Memory<byte> localDestination)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int result = await readTask.ConfigureAwait(false);
|
|
||||||
new ReadOnlySpan<byte>(localBuffer, 0, result).CopyTo(localDestination.Span);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
ArrayPool<byte>.Shared.Return(localBuffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
22
CodeWalker.Core/Utils/ThrowHelper.cs
Normal file
22
CodeWalker.Core/Utils/ThrowHelper.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CodeWalker.Core.Utils
|
||||||
|
{
|
||||||
|
internal class ThrowHelper
|
||||||
|
{
|
||||||
|
internal static Exception CreateEndOfFileException() =>
|
||||||
|
new EndOfStreamException("Tried to read stream beyond end");
|
||||||
|
|
||||||
|
[DoesNotReturn]
|
||||||
|
internal static void ThrowEndOfFileException()
|
||||||
|
{
|
||||||
|
throw CreateEndOfFileException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SharpDX;
|
using SharpDX;
|
||||||
using Color = SharpDX.Color;
|
using Color = SharpDX.Color;
|
||||||
|
using Half = SharpDX.Half;
|
||||||
|
|
||||||
namespace CodeWalker
|
namespace CodeWalker
|
||||||
{
|
{
|
||||||
@ -86,24 +87,39 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static string GetUTF8Text(byte[] bytes)
|
public static string GetUTF8Text(Span<byte> bytes)
|
||||||
{
|
{
|
||||||
if (bytes == null)
|
if (bytes == null || bytes.Length == 0)
|
||||||
{ return string.Empty; } //file not found..
|
{
|
||||||
var start = 0;
|
return string.Empty;
|
||||||
var length = bytes.Length;
|
} //file not found..
|
||||||
if ((bytes.Length > 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF))
|
if ((bytes.Length > 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF))
|
||||||
{
|
{
|
||||||
start = 3;
|
bytes = bytes.Slice(3);
|
||||||
length = bytes.Length - 3;
|
|
||||||
}
|
}
|
||||||
return Encoding.UTF8.GetString(bytes, start, length);
|
|
||||||
|
if (bytes.Length == 0)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Encoding.UTF8.GetString(bytes);
|
||||||
}
|
}
|
||||||
public static bool Contains(this string source, string toCheck, StringComparison comp)
|
public static bool Contains(this string source, string toCheck, StringComparison comp)
|
||||||
{
|
{
|
||||||
return source?.IndexOf(toCheck, comp) >= 0;
|
return source?.IndexOf(toCheck, comp) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool EndsWithAny(this string str, string searchString)
|
||||||
|
{
|
||||||
|
return str.EndsWith(searchString, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool EndsWithAny(this string str, string searchString, string searchString2)
|
||||||
|
{
|
||||||
|
return str.EndsWith(searchString, StringComparison.OrdinalIgnoreCase) || str.EndsWith(searchString2, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool EndsWithAny(this string str, params string[] strings)
|
public static bool EndsWithAny(this string str, params string[] strings)
|
||||||
{
|
{
|
||||||
foreach(var searchString in strings)
|
foreach(var searchString in strings)
|
||||||
|
@ -33,8 +33,7 @@ namespace CodeWalker.World
|
|||||||
|
|
||||||
List<AudioPlacement> placements = new List<AudioPlacement>();
|
List<AudioPlacement> placements = new List<AudioPlacement>();
|
||||||
|
|
||||||
GameFileCache.AudioDatRelFilesLock.EnterReadLock();
|
if (GameFileCache.AudioDatRelFiles != null)
|
||||||
try
|
|
||||||
{
|
{
|
||||||
foreach (var relfile in GameFileCache.AudioDatRelFiles)
|
foreach (var relfile in GameFileCache.AudioDatRelFiles)
|
||||||
{
|
{
|
||||||
@ -47,10 +46,6 @@ namespace CodeWalker.World
|
|||||||
PlacementsDict[relfile] = placements.ToArray();
|
PlacementsDict[relfile] = placements.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
|
||||||
{
|
|
||||||
GameFileCache.AudioDatRelFilesLock.ExitReadLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
AllItems.AddRange(Zones);
|
AllItems.AddRange(Zones);
|
||||||
AllItems.AddRange(Emitters);
|
AllItems.AddRange(Emitters);
|
||||||
|
@ -44,13 +44,13 @@ namespace CodeWalker.World
|
|||||||
public YmapEntityDef RenderEntity = new YmapEntityDef(); //placeholder entity object for rendering
|
public YmapEntityDef RenderEntity = new YmapEntityDef(); //placeholder entity object for rendering
|
||||||
|
|
||||||
|
|
||||||
public void Init(string name, GameFileCache gfc)
|
public async ValueTask InitAsync(string name, GameFileCache gfc)
|
||||||
{
|
{
|
||||||
var hash = JenkHash.GenHash(name.ToLowerInvariant());
|
var hash = JenkHash.GenHash(name.ToLowerInvariant());
|
||||||
Init(hash, gfc);
|
await InitAsync(hash, gfc);
|
||||||
Name = name;
|
Name = name;
|
||||||
}
|
}
|
||||||
public void Init(MetaHash pedhash, GameFileCache gfc)
|
public async ValueTask InitAsync(MetaHash pedhash, GameFileCache gfc)
|
||||||
{
|
{
|
||||||
|
|
||||||
Name = string.Empty;
|
Name = string.Empty;
|
||||||
@ -106,11 +106,11 @@ namespace CodeWalker.World
|
|||||||
RpfFileEntry clothFile = null;
|
RpfFileEntry clothFile = null;
|
||||||
if (ClothFilesDict?.TryGetValue(pedhash, out clothFile) ?? false)
|
if (ClothFilesDict?.TryGetValue(pedhash, out clothFile) ?? false)
|
||||||
{
|
{
|
||||||
Yld = gfc.GetFileUncached<YldFile>(clothFile);
|
Yld = await gfc.GetFileUncachedAsync<YldFile>(clothFile);
|
||||||
while ((Yld != null) && (!Yld.Loaded))
|
while ((Yld != null) && (!Yld.Loaded))
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);//kinda hacky
|
await Task.Delay(1);//kinda hacky
|
||||||
gfc.TryLoadEnqueue(Yld);
|
await gfc.TryLoadEnqueue(Yld);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,27 +118,27 @@ namespace CodeWalker.World
|
|||||||
|
|
||||||
while ((Ydd != null) && (!Ydd.Loaded))
|
while ((Ydd != null) && (!Ydd.Loaded))
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);//kinda hacky
|
await Task.Delay(1);//kinda hacky
|
||||||
Ydd = gfc.GetYdd(pedhash);
|
Ydd = gfc.GetYdd(pedhash);
|
||||||
}
|
}
|
||||||
while ((Ytd != null) && (!Ytd.Loaded))
|
while ((Ytd != null) && (!Ytd.Loaded))
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);//kinda hacky
|
await Task.Delay(1);//kinda hacky
|
||||||
Ytd = gfc.GetYtd(pedhash);
|
Ytd = gfc.GetYtd(pedhash);
|
||||||
}
|
}
|
||||||
while ((Ycd != null) && (!Ycd.Loaded))
|
while ((Ycd != null) && (!Ycd.Loaded))
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);//kinda hacky
|
await Task.Delay(1);//kinda hacky
|
||||||
Ycd = gfc.GetYcd(ycdhash);
|
Ycd = gfc.GetYcd(ycdhash);
|
||||||
}
|
}
|
||||||
while ((Yed != null) && (!Yed.Loaded))
|
while ((Yed != null) && (!Yed.Loaded))
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);//kinda hacky
|
await Task.Delay(1);//kinda hacky
|
||||||
Yed = gfc.GetYed(yedhash);
|
Yed = gfc.GetYed(yedhash);
|
||||||
}
|
}
|
||||||
while ((Yft != null) && (!Yft.Loaded))
|
while ((Yft != null) && (!Yft.Loaded))
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);//kinda hacky
|
await Task.Delay(1);//kinda hacky
|
||||||
Yft = gfc.GetYft(pedhash);
|
Yft = gfc.GetYft(pedhash);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ namespace CodeWalker.World
|
|||||||
Ycd?.ClipMap?.TryGetValue(cliphash, out cme);
|
Ycd?.ClipMap?.TryGetValue(cliphash, out cme);
|
||||||
AnimClip = cme;
|
AnimClip = cme;
|
||||||
|
|
||||||
var exprhash = JenkHash.GenHash(initdata.ExpressionName.ToLowerInvariant());
|
var exprhash = JenkHash.GenHashLower(initdata.ExpressionName);
|
||||||
Expression expr = null;
|
Expression expr = null;
|
||||||
Yed?.ExprMap?.TryGetValue(exprhash, out expr);
|
Yed?.ExprMap?.TryGetValue(exprhash, out expr);
|
||||||
Expression = expr;
|
Expression = expr;
|
||||||
@ -163,7 +163,7 @@ namespace CodeWalker.World
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void SetComponentDrawable(int index, string name, string tex, GameFileCache gfc)
|
public async ValueTask SetComponentDrawableAsync(int index, string name, string tex, GameFileCache gfc)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
{
|
{
|
||||||
@ -174,7 +174,7 @@ namespace CodeWalker.World
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaHash namehash = JenkHash.GenHash(name.ToLowerInvariant());
|
MetaHash namehash = JenkHash.GenHashLower(name);
|
||||||
Drawable d = null;
|
Drawable d = null;
|
||||||
if (Ydd?.Dict != null)
|
if (Ydd?.Dict != null)
|
||||||
{
|
{
|
||||||
@ -185,11 +185,11 @@ namespace CodeWalker.World
|
|||||||
RpfFileEntry file = null;
|
RpfFileEntry file = null;
|
||||||
if (DrawableFilesDict.TryGetValue(namehash, out file))
|
if (DrawableFilesDict.TryGetValue(namehash, out file))
|
||||||
{
|
{
|
||||||
var ydd = gfc.GetFileUncached<YddFile>(file);
|
var ydd = await gfc.GetFileUncachedAsync<YddFile>(file);
|
||||||
while ((ydd != null) && (!ydd.Loaded))
|
while ((ydd != null) && (!ydd.Loaded))
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);//kinda hacky
|
await Task.Delay(1);//kinda hacky
|
||||||
gfc.TryLoadEnqueue(ydd);
|
await gfc.TryLoadEnqueue(ydd);
|
||||||
}
|
}
|
||||||
if (ydd?.Drawables?.Length > 0)
|
if (ydd?.Drawables?.Length > 0)
|
||||||
{
|
{
|
||||||
@ -209,11 +209,11 @@ namespace CodeWalker.World
|
|||||||
RpfFileEntry file = null;
|
RpfFileEntry file = null;
|
||||||
if (TextureFilesDict.TryGetValue(texhash, out file))
|
if (TextureFilesDict.TryGetValue(texhash, out file))
|
||||||
{
|
{
|
||||||
var ytd = gfc.GetFileUncached<YtdFile>(file);
|
var ytd = await gfc.GetFileUncachedAsync<YtdFile>(file);
|
||||||
while ((ytd != null) && (!ytd.Loaded))
|
while ((ytd != null) && (!ytd.Loaded))
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);//kinda hacky
|
await Task.Delay(1);//kinda hacky
|
||||||
gfc.TryLoadEnqueue(ytd);
|
await gfc.TryLoadEnqueue(ytd);
|
||||||
}
|
}
|
||||||
if (ytd?.TextureDict?.Textures?.data_items.Length > 0)
|
if (ytd?.TextureDict?.Textures?.data_items.Length > 0)
|
||||||
{
|
{
|
||||||
@ -232,11 +232,11 @@ namespace CodeWalker.World
|
|||||||
RpfFileEntry file = null;
|
RpfFileEntry file = null;
|
||||||
if (ClothFilesDict.TryGetValue(namehash, out file))
|
if (ClothFilesDict.TryGetValue(namehash, out file))
|
||||||
{
|
{
|
||||||
var yld = gfc.GetFileUncached<YldFile>(file);
|
var yld = await gfc.GetFileUncachedAsync<YldFile>(file);
|
||||||
while ((yld != null) && (!yld.Loaded))
|
while ((yld != null) && (!yld.Loaded))
|
||||||
{
|
{
|
||||||
Thread.Sleep(1);//kinda hacky
|
await Task.Delay(1);//kinda hacky
|
||||||
gfc.TryLoadEnqueue(yld);
|
await gfc.TryLoadEnqueue(yld);
|
||||||
}
|
}
|
||||||
if (yld?.ClothDictionary?.Clothes?.data_items?.Length > 0)
|
if (yld?.ClothDictionary?.Clothes?.data_items?.Length > 0)
|
||||||
{
|
{
|
||||||
@ -266,7 +266,7 @@ namespace CodeWalker.World
|
|||||||
DrawableNames[index] = name;
|
DrawableNames[index] = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetComponentDrawable(int index, int drawbl, int alt, int tex, GameFileCache gfc)
|
public async ValueTask SetComponentDrawableAsync(int index, int drawbl, int alt, int tex, GameFileCache gfc)
|
||||||
{
|
{
|
||||||
var vi = Ymt?.VariationInfo;
|
var vi = Ymt?.VariationInfo;
|
||||||
if (vi != null)
|
if (vi != null)
|
||||||
@ -279,17 +279,17 @@ namespace CodeWalker.World
|
|||||||
{
|
{
|
||||||
var name = item?.GetDrawableName(alt);
|
var name = item?.GetDrawableName(alt);
|
||||||
var texn = item?.GetTextureName(tex);
|
var texn = item?.GetTextureName(tex);
|
||||||
SetComponentDrawable(index, name, texn, gfc);
|
await SetComponentDrawableAsync(index, name, texn, gfc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadDefaultComponents(GameFileCache gfc)
|
public async ValueTask LoadDefaultComponentsAsync(GameFileCache gfc)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 12; i++)
|
for (int i = 0; i < 12; i++)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(i, 0, 0, 0, gfc);
|
await SetComponentDrawableAsync(i, 0, 0, 0, gfc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net48</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<ApplicationIcon>CWPeds.ico</ApplicationIcon>
|
<ApplicationIcon>CWPeds.ico</ApplicationIcon>
|
||||||
<Copyright>dexyfex</Copyright>
|
<Copyright>dexyfex</Copyright>
|
||||||
@ -10,18 +9,13 @@
|
|||||||
<Authors>dexyfex</Authors>
|
<Authors>dexyfex</Authors>
|
||||||
<AssemblyName>CodeWalker Ped Viewer</AssemblyName>
|
<AssemblyName>CodeWalker Ped Viewer</AssemblyName>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CodeWalker\CodeWalker.csproj" />
|
<ProjectReference Include="..\CodeWalker\CodeWalker.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -1,8 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net48</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<ApplicationIcon>CWRPFExplorer.ico</ApplicationIcon>
|
<ApplicationIcon>CWRPFExplorer.ico</ApplicationIcon>
|
||||||
@ -12,21 +11,16 @@
|
|||||||
<AssemblyName>CodeWalker RPF Explorer</AssemblyName>
|
<AssemblyName>CodeWalker RPF Explorer</AssemblyName>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CodeWalker\CodeWalker.csproj" />
|
<ProjectReference Include="..\CodeWalker\CodeWalker.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -1,17 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net48</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
|
||||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
|
||||||
<PackageReference Include="xunit" Version="2.6.1" />
|
<PackageReference Include="xunit" Version="2.6.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
@ -22,9 +17,7 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj" />
|
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
BIN
CodeWalker.Test/Files/anwblokaal.ytyp
Normal file
BIN
CodeWalker.Test/Files/anwblokaal.ytyp
Normal file
Binary file not shown.
BIN
CodeWalker.Test/Files/raw_key.dat
Normal file
BIN
CodeWalker.Test/Files/raw_key.dat
Normal file
Binary file not shown.
104
CodeWalker.Test/GTACryptTests.cs
Normal file
104
CodeWalker.Test/GTACryptTests.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
using CodeWalker.GameFiles;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace CodeWalker.Test
|
||||||
|
{
|
||||||
|
public class GTACryptTests
|
||||||
|
{
|
||||||
|
private const string RawKey = "sVGBe8yn7a4jqG0Di35DL9kFdd8IxUrIRuAMhRuEHOybRfi3sBMmEzz/ijT4EX4P8BwMOjmghVJi/AGUqqhOQsZdUcvcyOo4phKlPkl+xGX1wafkzNxpRJFdvhImFz+4+glX8Yavo3o76wBWlFfkUXRqGtiLAdTsKtdqgFMalzmnkDZsL7CeFjQONS/3W5ZzS/aikwsOYLYCo/f8QaIemm385HvFDEeLgHvsigxYHd/dyICvpK0bUvhZfz1BUmmHLOlYFKll/HPa7q8KhL/bRT0FblZ0s26INHaIf4tZ3nnWq51YGR1SnddxqDP/L0314KxuI4ou4xmAiu67x+sv+cLxScJc83U1iRhngfn3s4w=";
|
||||||
|
private uint[][] Key;
|
||||||
|
|
||||||
|
private readonly ITestOutputHelper _output;
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(Key))]
|
||||||
|
private void LoadKeys()
|
||||||
|
{
|
||||||
|
var bytes = Convert.FromBase64String(RawKey);
|
||||||
|
|
||||||
|
Key = new uint[17][];
|
||||||
|
var uints = MemoryMarshal.Cast<byte, uint>(bytes);
|
||||||
|
for (int i = 0; i < Key.Length; i++)
|
||||||
|
{
|
||||||
|
Key[i] = uints.Slice(i * 4, 4).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// GTA5Keys.LoadFromPath("C:\\Program Files\\Rockstar Games\\Grand Theft Auto V");
|
||||||
|
|
||||||
|
var rawKey = File.ReadAllBytes(TestFiles.GetFilePath("raw_key.dat"));
|
||||||
|
|
||||||
|
GTA5Keys.LoadPCNGDecryptTable(rawKey.AsSpan());
|
||||||
|
}
|
||||||
|
|
||||||
|
public GTACryptTests(ITestOutputHelper testOutputHelper)
|
||||||
|
{
|
||||||
|
_output = testOutputHelper;
|
||||||
|
LoadKeys();
|
||||||
|
|
||||||
|
|
||||||
|
//File.WriteAllBytes(TestFiles.GetFilePath("raw_key.dat"), rawKeyBytes.ToArray());
|
||||||
|
//var base64Key = Convert.ToBase64String(rawKeyBytes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check, before running tests for decryption, ensure we actually have the correct key loaded in
|
||||||
|
[Fact(DisplayName = "Key should match key which was used to create decryption tests")]
|
||||||
|
public void KeyShouldBeExpectedKey()
|
||||||
|
{
|
||||||
|
// The full key is pretty long, so just check a small part of it
|
||||||
|
var expectedKey = "l15p1+ANbFRRf+S3O0BHuSrwiWt9O4HBcLc7foJtA0v+GB5u0HV9T5V3b4CyFRJQMk9ZSIe+deW172Kp+pu6IAXNOKpWhZROt8Zk/rpK3kHIyq1sUgYwAP1hytlc814Iko0feUc1WpxDtv7SK6Bbi72wrrg/w+P3gz3Rq0vpMsM6EJVZXtpYX9ypFRD0btQoN5wv5k46RG2hjNrVnSijkUq54COuKWY9hMehUhnxTMd1ZE3Q7YHW6+p7phKr+hCTIq9Fej3q5aAIQYIVwcWznSP/l5rU9tkBoNwINbNFwLBoCOtd6FKgRcPstcrvqNC8c87vyUwTQjoCN0hTjJhtQw+78uz3FwCfWln8EfOUpNHEFsUzfGtTIUDPKmVv8pukScA0lELmLDL1PgbIcefpnhZU8C/8MRg5GoiYcItiHbrMSQkiJVU1g1hw+kbNGdvCGKGeJ1SskhkO6yAM4V2+tCCGQy2R9MvO8O1wZi5zLSWKMs9amPvVP6UPfpu0v7BJ8b2ihsmaf4wtCvmSJ3wz1B1y6IluoklEZNSDAt/QwaeARAUcTUOQ2pQnvWD54m6XZ61XtcrjqztqIe0KYFcnTKqqwnO84HxY43S44/9IzI5Bn/iFeOj3b4lLG+1ynj0pbItPE3YdmWemdqossWzG59oDtwnW399WPpMxF5rS02hm/YVVzmAPdYWXc7KvebTdCRFQ9Xm4JY+tULKKE4eGgdgqsV5rcT/q5d4a+vvLaMBbCS7xaVg5vVAvNleeUXcmm4IBiHdNS4difiEbOWlB7tl6Y76BFNf8YQf1rAFOnOST3c2ZH1vu3rhj2BYeCzw+ovUOYsCVYX2+yXoPj+G59NePDbaceHFx0SWvryxaK3J7kSPY6QJypSjZjzxETI4rFH32eJ8BpcaIG8kNU1bi4FkgKKZ6wfE4ZYRR4qRfrHsVLSSYV9VGrmMu8/sxNo3/T2qWjeSOyBrSXHsYCzhWoqOl3IJFHFzLDZL0u9tTZel0NJ8wKYld3PZH0n8RroDW0wyp+BD+UjZIkOZ0IdaRzawAYGoGtOwdA2eas0ZliHwcIjppG9hKkDy6N0CQpBkuLyP/xQpohELyxHYx6yt08pYOuzfPMN2VmasH312jjOhfioq/fxKHlgAeTgTGP8Nktpa2HrkzCvYzH4uo4iRqAzTl+1E2zP0GwrxnKsdvEYSNyL+j5qfOTb+ZqO8kBedjhu6nBcuzedtt253zqIPEJO74Alyp0xbEODmTDuzRBAtV/ED55/ccrbA8FAc1tSmx1aYL4RcEIs8MwiZbuxoMoRLXVGEwZl8f3fnH8MVGF9OOsWsUpyZ4zCYs4TQH5D79fkJVdt6AE0cEnepK+LK8dw==";
|
||||||
|
|
||||||
|
var loadedKey = MemoryMarshal.AsBytes(GTA5Keys.PC_NG_DECRYPT_TABLES[5][5].AsSpan());
|
||||||
|
var loadedKeyBase64 = Convert.ToBase64String(loadedKey);
|
||||||
|
|
||||||
|
Assert.Equal(expectedKey, loadedKeyBase64);
|
||||||
|
|
||||||
|
// This is the key which was just loaded, so these should be equivalent
|
||||||
|
|
||||||
|
var fullKeyBytes = MemoryMarshal.AsBytes(GTA5Keys.PC_NG_DECRYPT_TABLES.SelectMany(p => p).SelectMany(p => p).ToArray().AsSpan());
|
||||||
|
|
||||||
|
var expectedBytes = File.ReadAllBytes(TestFiles.GetFilePath("raw_key.dat"));
|
||||||
|
var loadedBytes = fullKeyBytes.ToArray();
|
||||||
|
|
||||||
|
Assert.Equal(expectedBytes.LongLength, loadedBytes.LongLength);
|
||||||
|
|
||||||
|
// Use manual for loop, equivalent is quite slow compared to this (7 seconds vs 1 second)
|
||||||
|
for (int i = 0; i < loadedBytes.Length; i++)
|
||||||
|
{
|
||||||
|
Assert.Equal(expectedBytes[i], loadedBytes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const string InputData = "6Zemmftaofsb2sEYb3AC9A==";
|
||||||
|
private const string OutputData = "AAAAAAD//38BAAAAGAAAAA==";
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DecryptWithArrayShouldReturnExpectedData()
|
||||||
|
{
|
||||||
|
var data = Convert.FromBase64String(InputData);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
GTACrypto.DecryptNG(data, Key);
|
||||||
|
|
||||||
|
Assert.Equal(OutputData, Convert.ToBase64String(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DecryptWithSpanShouldReturnExpectedData()
|
||||||
|
{
|
||||||
|
var data = Convert.FromBase64String(InputData);
|
||||||
|
GTACrypto.DecryptNG(data.AsSpan(), Key);
|
||||||
|
|
||||||
|
Assert.Equal(OutputData, Convert.ToBase64String(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,11 +4,13 @@ using System.Buffers.Binary;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace CodeWalker.Test
|
namespace CodeWalker.Test
|
||||||
{
|
{
|
||||||
@ -122,6 +124,11 @@ namespace CodeWalker.Test
|
|||||||
|
|
||||||
public class TestBinaryConversions
|
public class TestBinaryConversions
|
||||||
{
|
{
|
||||||
|
private readonly ITestOutputHelper _output;
|
||||||
|
public TestBinaryConversions(ITestOutputHelper testOutputHelper)
|
||||||
|
{
|
||||||
|
_output = testOutputHelper;
|
||||||
|
}
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestConvertData()
|
public void TestConvertData()
|
||||||
{
|
{
|
||||||
@ -442,4 +449,86 @@ namespace CodeWalker.Test
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TestConvertDataArray
|
||||||
|
{
|
||||||
|
private readonly ITestOutputHelper _output;
|
||||||
|
public TestConvertDataArray(ITestOutputHelper output)
|
||||||
|
{
|
||||||
|
_output = output;
|
||||||
|
}
|
||||||
|
private string GetFilePath(string filename)
|
||||||
|
{
|
||||||
|
// Directory we're looking for.
|
||||||
|
var dirToFind = Path.Combine(@"CodeWalker.Test", "Files");
|
||||||
|
|
||||||
|
// Search up directory tree starting at assembly path looking for 'Images' dir.
|
||||||
|
var searchPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var testPath = Path.Combine(searchPath, dirToFind);
|
||||||
|
if (Directory.Exists(testPath))
|
||||||
|
{
|
||||||
|
// Found it!
|
||||||
|
return Path.Combine(testPath, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move up one directory.
|
||||||
|
var newSearchPath = Path.GetFullPath(Path.Combine(searchPath, ".."));
|
||||||
|
if (newSearchPath == searchPath)
|
||||||
|
{
|
||||||
|
// Didn't move up, so we're at the root.
|
||||||
|
throw new FileNotFoundException($"Could not find '{dirToFind}' directory.");
|
||||||
|
}
|
||||||
|
searchPath = newSearchPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TestData = "AAAAAAAAAAAFAAAAAAAAAAUABQAAAAAAAAAAAAAAAAAAAKDAAACgwAAAAMAAAAAAAACgQAAAoEAAAABAAAAAAAAAgD9kViJCAAAAAGAAAAABAAAAAAAAAP////8AAAAABgAAAAAAAAABAAEAAAAAAAAAAAAAAAAABWAAAAAAAAAKAAoAAAAAAAAAAAAAAAAAgPEnwiB/QcIAcFzBAAAAAADgDsL9ke/BHKgswQAAAAAAAIA/yyTUkwAAAABgAAAAAQAAAAEAAAD/////AAAAAAYAAQAAAAAALgAuAAAAAAA=";
|
||||||
|
[Fact]
|
||||||
|
public void ConvertDataArrayShouldReturnSameAsConvertData()
|
||||||
|
{
|
||||||
|
var data = Convert.FromBase64String(TestData);
|
||||||
|
|
||||||
|
var referenceData = MetaTypes.ConvertData<CMloRoomDef>(data);
|
||||||
|
|
||||||
|
var arrayData = MetaTypes.ConvertDataArray<CMloRoomDef>(data, 0, 2);
|
||||||
|
|
||||||
|
var path = GetFilePath("anwblokaal.ytyp");
|
||||||
|
var bytes = File.ReadAllBytes(path);
|
||||||
|
var entry = RpfFile.CreateFileEntry("anwblokaal.ytyp", path, ref bytes);
|
||||||
|
var ytypFile = RpfFile.GetFile<YtypFile>(entry, bytes);
|
||||||
|
|
||||||
|
var rooms = ytypFile.AllArchetypes
|
||||||
|
.Where(p => p is MloArchetype)
|
||||||
|
.Select(p => p as MloArchetype)
|
||||||
|
.SelectMany(p => p.rooms)
|
||||||
|
.Select(p => p.Data);
|
||||||
|
|
||||||
|
var secondRoom = rooms.Last();
|
||||||
|
|
||||||
|
var arr = new byte[Marshal.SizeOf<CMloRoomDef>() * rooms.Count()];
|
||||||
|
//MemoryMarshal.Write(arr.AsSpan(), ref rooms);
|
||||||
|
|
||||||
|
_output.WriteLine(Convert.ToBase64String(MemoryMarshal.AsBytes(rooms.ToArray().AsSpan())));
|
||||||
|
|
||||||
|
// I know the bbMax values don't really make sense here, seems to be a weird ytyp, but it's mostly about testing the serialization, not about using a 100% correct ytyp
|
||||||
|
// And didn't want to include a ytyp from Rockstar Games since that could cause some legal issues down the road
|
||||||
|
// Another possible solution would be to do abest attempt to find the GTA V installed on the user's computer running the tests and use files from there, but this would add complexity and links which could break tests
|
||||||
|
// However this would be more in the scope of implementation testing as it tests the whole chain including encryption which is not wanted here
|
||||||
|
Assert.Equivalent(new SharpDX.Vector3(-41.98584f, -48.3741455f, -13.7773438f), secondRoom.bbMin);
|
||||||
|
Assert.Equivalent(new SharpDX.Vector3(-35.71875f, -29.9462833f, -10.7910423f), secondRoom.bbMax);
|
||||||
|
Assert.Equivalent(new Array_uint(65542, 46), secondRoom.attachedObjects);
|
||||||
|
Assert.Equal(96u, secondRoom.flags);
|
||||||
|
Assert.Equal(1, secondRoom.floorId);
|
||||||
|
Assert.Equivalent(new CharPointer() { Count1 = 10, Count2 = 10, Pointer = 24581 }, secondRoom.name);
|
||||||
|
Assert.Equal(1u, secondRoom.portalCount);
|
||||||
|
Assert.Equal(2480153803, secondRoom.timecycleName.Hash);
|
||||||
|
|
||||||
|
// First room is limbo, so this check isn't that useful, but just make sure, and the following check will compare the entire array anyways
|
||||||
|
Assert.Equivalent(referenceData, rooms.First());
|
||||||
|
|
||||||
|
Assert.Equivalent(arrayData.ToArray(), rooms);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
40
CodeWalker.Test/TestFiles.cs
Normal file
40
CodeWalker.Test/TestFiles.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CodeWalker.Test
|
||||||
|
{
|
||||||
|
internal class TestFiles
|
||||||
|
{
|
||||||
|
public static string GetFilePath(string filename)
|
||||||
|
{
|
||||||
|
// Directory we're looking for.
|
||||||
|
var dirToFind = Path.Combine(@"CodeWalker.Test", "Files");
|
||||||
|
|
||||||
|
// Search up directory tree starting at assembly path looking for 'Images' dir.
|
||||||
|
var searchPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var testPath = Path.Combine(searchPath, dirToFind);
|
||||||
|
if (Directory.Exists(testPath))
|
||||||
|
{
|
||||||
|
// Found it!
|
||||||
|
return Path.Combine(testPath, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move up one directory.
|
||||||
|
var newSearchPath = Path.GetFullPath(Path.Combine(searchPath, ".."));
|
||||||
|
if (newSearchPath == searchPath)
|
||||||
|
{
|
||||||
|
// Didn't move up, so we're at the root.
|
||||||
|
throw new FileNotFoundException($"Could not find '{dirToFind}' directory.");
|
||||||
|
}
|
||||||
|
searchPath = newSearchPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
CodeWalker.Test/TestSpanLineEnumerator.cs
Normal file
31
CodeWalker.Test/TestSpanLineEnumerator.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using CodeWalker.Core.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
|
namespace CodeWalker.Test
|
||||||
|
{
|
||||||
|
public class TestSpanLineEnumerator
|
||||||
|
{
|
||||||
|
private readonly ITestOutputHelper output;
|
||||||
|
public TestSpanLineEnumerator(ITestOutputHelper output)
|
||||||
|
{
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void IteratorShouldSplitLinesCorrectly()
|
||||||
|
{
|
||||||
|
var lines = "kaas\nsaak\nnog\neen\nline".AsSpan();
|
||||||
|
|
||||||
|
foreach(var line in lines.EnumerateSplit('\n'))
|
||||||
|
{
|
||||||
|
output.WriteLine(line.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net48</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<ApplicationIcon>CWVehicles.ico</ApplicationIcon>
|
<ApplicationIcon>CWVehicles.ico</ApplicationIcon>
|
||||||
<Copyright>dexyfex</Copyright>
|
<Copyright>dexyfex</Copyright>
|
||||||
@ -11,18 +10,13 @@
|
|||||||
<AssemblyName>CodeWalker Vehicle Viewer</AssemblyName>
|
<AssemblyName>CodeWalker Vehicle Viewer</AssemblyName>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CodeWalker\CodeWalker.csproj" />
|
<ProjectReference Include="..\CodeWalker\CodeWalker.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -1,24 +1,21 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>net48</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DockPanelSuite.ThemeVS2015" Version="3.0.6" />
|
<PackageReference Include="DockPanelSuite.ThemeVS2015" Version="3.1.0" />
|
||||||
|
<PackageReference Include="HIC.System.Windows.Forms.DataVisualization" Version="1.0.1" />
|
||||||
<PackageReference Include="SharpDX" Version="4.2.0" />
|
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||||
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
|
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -249,22 +249,34 @@ namespace CodeWalker
|
|||||||
ofd.InitialDirectory = fbd.SelectedPath;
|
ofd.InitialDirectory = fbd.SelectedPath;
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
var ns = "System.Windows.Forms";
|
var ns = "MS.Internal.AppModel";
|
||||||
var asmb = Assembly.GetAssembly(typeof(OpenFileDialog));
|
var asmb = Assembly.Load("System.Windows.Forms.Primitives");
|
||||||
var dialogint = GetType(asmb, ns, "FileDialogNative.IFileDialog");
|
//var asmb = Assembly.LoadWithPartialName("PresentationFramework");
|
||||||
|
var dialogint = asmb.GetType("Interop+Shell32+IFileDialog");
|
||||||
|
//var dialogint = GetType(asmb, ns, "IFileDialog");
|
||||||
var dialog = Call(typeof(OpenFileDialog), ofd, "CreateVistaDialog");
|
var dialog = Call(typeof(OpenFileDialog), ofd, "CreateVistaDialog");
|
||||||
Call(typeof(OpenFileDialog), ofd, "OnBeforeVistaDialog", dialog);
|
Call(typeof(OpenFileDialog), ofd, "OnBeforeVistaDialog", dialog);
|
||||||
var options = Convert.ToUInt32(Call(typeof(FileDialog), ofd, "GetOptions"));
|
var options = Convert.ToUInt32(Call(typeof(FileDialog), ofd, "GetOptions"));
|
||||||
options |= Convert.ToUInt32(GetEnumValue(asmb, ns, "FileDialogNative.FOS", "FOS_PICKFOLDERS"));
|
|
||||||
|
var enumValue = GetEnumValue("System.Windows.Forms.Primitives", "Interop+Shell32+FOS", "PICKFOLDERS");
|
||||||
|
options |= Convert.ToUInt32(enumValue);
|
||||||
|
|
||||||
Call(dialogint, dialog, "SetOptions", options);
|
Call(dialogint, dialog, "SetOptions", options);
|
||||||
var pfde = New(asmb, ns, "FileDialog.VistaDialogEvents", ofd);
|
dynamic pfde = New("System.Windows.Forms", "System.Windows.Forms.FileDialog+VistaDialogEvents", ofd);
|
||||||
var parameters = new object[] { pfde, (uint)0 };
|
var parameters = new object[] { pfde, (uint)0 };
|
||||||
Call(dialogint, dialog, "Advise", parameters);
|
Call(dialogint, dialog, "Advise", parameters);
|
||||||
var adviseres = Convert.ToUInt32(parameters[1]);
|
var adviseres = Convert.ToUInt32(parameters[1]);
|
||||||
try { result = Convert.ToInt32(Call(dialogint, dialog, "Show", hWndOwner)); }
|
try {
|
||||||
finally { Call(dialogint, dialog, "Unadvise", adviseres); }
|
result = Convert.ToInt32(Call(dialogint, dialog, "Show", hWndOwner));
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
//pfde.Dispose();
|
||||||
|
Call(dialogint, dialog, "Unadvise", adviseres);
|
||||||
|
}
|
||||||
GC.KeepAlive(pfde);
|
GC.KeepAlive(pfde);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fbd.SelectedPath = ofd.FileName;
|
fbd.SelectedPath = ofd.FileName;
|
||||||
|
|
||||||
return (result == 0) ? DialogResult.OK : DialogResult.Cancel;
|
return (result == 0) ? DialogResult.OK : DialogResult.Cancel;
|
||||||
@ -296,12 +308,33 @@ namespace CodeWalker
|
|||||||
if (mi == null) return null;
|
if (mi == null) return null;
|
||||||
return mi.Invoke(obj, parameters);
|
return mi.Invoke(obj, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static object GetEnumValue(string assemblyName, string typeName, string name)
|
||||||
|
{
|
||||||
|
var type = Type.GetType($"{typeName}, {assemblyName}");
|
||||||
|
var fieldInfo = type.GetField(name);
|
||||||
|
return fieldInfo.GetValue(null);
|
||||||
|
}
|
||||||
|
|
||||||
private static object GetEnumValue(Assembly asmb, string ns, string typeName, string name)
|
private static object GetEnumValue(Assembly asmb, string ns, string typeName, string name)
|
||||||
{
|
{
|
||||||
var type = GetType(asmb, ns, typeName);
|
var type = GetType(asmb, ns, typeName);
|
||||||
var fieldInfo = type.GetField(name);
|
var fieldInfo = type.GetField(name);
|
||||||
return fieldInfo.GetValue(null);
|
return fieldInfo.GetValue(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static object New(string assemblyName, string typeName, params object[] parameters)
|
||||||
|
{
|
||||||
|
var type = Type.GetType($"{typeName}, {assemblyName}");
|
||||||
|
var ctorInfos = type.GetConstructors();
|
||||||
|
foreach (ConstructorInfo ci in ctorInfos)
|
||||||
|
{
|
||||||
|
try { return ci.Invoke(parameters); }
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static object New(Assembly asmb, string ns, string name, params object[] parameters)
|
private static object New(Assembly asmb, string ns, string name, params object[] parameters)
|
||||||
{
|
{
|
||||||
var type = GetType(asmb, ns, name);
|
var type = GetType(asmb, ns, name);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.7.34031.279
|
VisualStudioVersion = 17.7.34031.279
|
||||||
@ -25,7 +25,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeWalker.Vehicles", "Code
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeWalker.Test", "CodeWalker.Test\CodeWalker.Test.csproj", "{067FF87E-CA79-4B29-BCF6-11622999EDC6}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeWalker.Test", "CodeWalker.Test\CodeWalker.Test.csproj", "{067FF87E-CA79-4B29-BCF6-11622999EDC6}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeWalker.Benchmarks", "CodeWalker.Benchmarks\CodeWalker.Benchmarks.csproj", "{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeWalker.Benchmarks", "CodeWalker.Benchmarks\CodeWalker.Benchmarks.csproj", "{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
@ -151,27 +151,6 @@
|
|||||||
<setting name="DLC" serializeAs="String">
|
<setting name="DLC" serializeAs="String">
|
||||||
<value />
|
<value />
|
||||||
</setting>
|
</setting>
|
||||||
<setting name="KeyBindings" serializeAs="Xml">
|
|
||||||
<value>
|
|
||||||
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
|
||||||
<string>Move Forwards: W</string>
|
|
||||||
<string>Move Backwards: S</string>
|
|
||||||
<string>Move Left: A</string>
|
|
||||||
<string>Move Right: D</string>
|
|
||||||
<string>Move Up: R</string>
|
|
||||||
<string>Move Down: F</string>
|
|
||||||
<string>Move Slower / Zoom In: Z</string>
|
|
||||||
<string>Move Faster / Zoom Out: X</string>
|
|
||||||
<string>Toggle Mouse Select: C</string>
|
|
||||||
<string>Toggle Toolbar: T</string>
|
|
||||||
<string>Exit Edit Mode: Q</string>
|
|
||||||
<string>Edit Position: W</string>
|
|
||||||
<string>Edit Rotation: E</string>
|
|
||||||
<string>Edit Scale: R</string>
|
|
||||||
</ArrayOfString>
|
|
||||||
</value>
|
|
||||||
</setting>
|
|
||||||
<setting name="XInputLThumbInvert" serializeAs="String">
|
<setting name="XInputLThumbInvert" serializeAs="String">
|
||||||
<value>True</value>
|
<value>True</value>
|
||||||
</setting>
|
</setting>
|
||||||
@ -250,6 +229,26 @@
|
|||||||
<setting name="AntiAliasing" serializeAs="String">
|
<setting name="AntiAliasing" serializeAs="String">
|
||||||
<value>2</value>
|
<value>2</value>
|
||||||
</setting>
|
</setting>
|
||||||
|
<setting name="KeyBindings" serializeAs="Xml">
|
||||||
|
<value>
|
||||||
|
<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<string>Move Forwards: W</string>
|
||||||
|
<string>Move Backwards: S</string>
|
||||||
|
<string>Move Left: A</string>
|
||||||
|
<string>Move Right: D</string>
|
||||||
|
<string>Move Up: R</string>
|
||||||
|
<string>Move Down: F</string>
|
||||||
|
<string>Move Slower / Zoom In: Z</string>
|
||||||
|
<string>Move Faster / Zoom Out: X</string>
|
||||||
|
<string>Toggle Mouse Select: C</string>
|
||||||
|
<string>Toggle Toolbar: T</string>
|
||||||
|
<string>Exit Edit Mode: Q</string>
|
||||||
|
<string>Edit Position: W</string>
|
||||||
|
<string>Edit Rotation: E</string>
|
||||||
|
<string>Edit Scale: R</string>
|
||||||
|
</ArrayOfString>
|
||||||
|
</value>
|
||||||
|
</setting>
|
||||||
</CodeWalker.Properties.Settings>
|
</CodeWalker.Properties.Settings>
|
||||||
</userSettings>
|
</userSettings>
|
||||||
<runtime>
|
<runtime>
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net48</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<ApplicationIcon>CW.ico</ApplicationIcon>
|
<ApplicationIcon>CW.ico</ApplicationIcon>
|
||||||
@ -10,22 +9,25 @@
|
|||||||
<Company>dexyfex software</Company>
|
<Company>dexyfex software</Company>
|
||||||
<Authors>dexyfex</Authors>
|
<Authors>dexyfex</Authors>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
|
<Nullable>annotations</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
|
<PackageReference Include="DirectXTexNet" Version="1.0.3" />
|
||||||
<PackageReference Include="DirectXTexNet" Version="1.0.1" />
|
|
||||||
<PackageReference Include="DockPanelSuite.ThemeVS2015" Version="3.1.0" />
|
<PackageReference Include="DockPanelSuite.ThemeVS2015" Version="3.1.0" />
|
||||||
<PackageReference Include="FCTB" Version="2.16.24" />
|
<PackageReference Include="FCTB" Version="2.16.24" />
|
||||||
|
<PackageReference Include="HIC.System.Windows.Forms.DataVisualization" Version="1.0.1" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="RequiredMemberAttribute" Version="1.0.0">
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="SharpDX" Version="4.2.0" />
|
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||||
<PackageReference Include="SharpDX.D3DCompiler" Version="4.2.0" />
|
<PackageReference Include="SharpDX.D3DCompiler" Version="4.2.0" />
|
||||||
<PackageReference Include="SharpDX.Direct2D1" Version="4.2.0" />
|
<PackageReference Include="SharpDX.Direct2D1" Version="4.2.0" />
|
||||||
@ -33,18 +35,13 @@
|
|||||||
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
|
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
|
||||||
<PackageReference Include="SharpDX.XAudio2" Version="4.2.0" />
|
<PackageReference Include="SharpDX.XAudio2" Version="4.2.0" />
|
||||||
<PackageReference Include="SharpDX.XInput" Version="4.2.0" />
|
<PackageReference Include="SharpDX.XInput" Version="4.2.0" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
<PackageReference Include="System.Diagnostics.Tracing" Version="4.3.0" />
|
||||||
|
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj" />
|
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj" />
|
||||||
<ProjectReference Include="..\CodeWalker.WinForms\CodeWalker.WinForms.csproj" />
|
<ProjectReference Include="..\CodeWalker.WinForms\CodeWalker.WinForms.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="System.Windows.Forms.DataVisualization" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Update="Properties\Settings.Designer.cs">
|
<Compile Update="Properties\Settings.Designer.cs">
|
||||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||||
@ -52,12 +49,10 @@
|
|||||||
<DependentUpon>Settings.settings</DependentUpon>
|
<DependentUpon>Settings.settings</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Update="Properties\Settings.settings">
|
<None Update="Properties\Settings.settings">
|
||||||
<Generator>PublicSettingsSingleFileGenerator</Generator>
|
<Generator>PublicSettingsSingleFileGenerator</Generator>
|
||||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
@ -8,7 +8,6 @@ using CodeWalker.Core.Utils;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
@ -19,13 +18,10 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
|
||||||
using WeifenLuo.WinFormsUI.Docking;
|
using WeifenLuo.WinFormsUI.Docking;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using static CodeWalker.GameFiles.GameFileCache;
|
using static CodeWalker.GameFiles.GameFileCache;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using CodeWalker.WinForms;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace CodeWalker
|
namespace CodeWalker
|
||||||
{
|
{
|
||||||
@ -34,15 +30,15 @@ namespace CodeWalker
|
|||||||
private volatile bool Ready = false;
|
private volatile bool Ready = false;
|
||||||
private bool IsInited = false;
|
private bool IsInited = false;
|
||||||
|
|
||||||
public static ExploreForm Instance;
|
public static ExploreForm? Instance;
|
||||||
|
|
||||||
private static Dictionary<string, FileTypeInfo> FileTypes;
|
private static Dictionary<string, FileTypeInfo>? FileTypes;
|
||||||
private static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars();
|
private static readonly char[] InvalidFileNameChars = Path.GetInvalidFileNameChars();
|
||||||
|
|
||||||
public MainTreeFolder RootFolder;
|
public MainTreeFolder? RootFolder;
|
||||||
public List<MainTreeFolder> ExtraRootFolders = new List<MainTreeFolder>();
|
public List<MainTreeFolder> ExtraRootFolders = new List<MainTreeFolder>();
|
||||||
public MainTreeFolder CurrentFolder;
|
public MainTreeFolder? CurrentFolder;
|
||||||
public List<MainListItem> CurrentFiles;
|
public List<MainListItem>? CurrentFiles;
|
||||||
private bool FirstRefreshed = false;
|
private bool FirstRefreshed = false;
|
||||||
private List<MainListItem> CopiedFiles = new List<MainListItem>();
|
private List<MainListItem> CopiedFiles = new List<MainListItem>();
|
||||||
|
|
||||||
@ -57,17 +53,17 @@ namespace CodeWalker
|
|||||||
public volatile bool Searching = false;
|
public volatile bool Searching = false;
|
||||||
private MainTreeFolder SearchResults;
|
private MainTreeFolder SearchResults;
|
||||||
|
|
||||||
private List<RpfFile> AllRpfs { get; set; }
|
private List<RpfFile>? AllRpfs { get; set; }
|
||||||
private GameFileCache FileCache { get; set; }
|
private static GameFileCache FileCache => GameFileCacheFactory.Instance;
|
||||||
private object FileCacheSyncRoot = new object();
|
private readonly object FileCacheSyncRoot = new object();
|
||||||
|
|
||||||
public bool EditMode { get; private set; } = false;
|
public bool EditMode { get; private set; } = false;
|
||||||
|
|
||||||
public ThemeBase Theme { get; private set; }
|
public ThemeBase? Theme { get; private set; }
|
||||||
|
|
||||||
public CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
|
public CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
|
||||||
|
|
||||||
public static event Action ForceTreeRefresh;
|
public static event Action? ForceTreeRefresh;
|
||||||
|
|
||||||
static ExploreForm()
|
static ExploreForm()
|
||||||
{
|
{
|
||||||
@ -76,8 +72,11 @@ namespace CodeWalker
|
|||||||
|
|
||||||
public ExploreForm()
|
public ExploreForm()
|
||||||
{
|
{
|
||||||
|
ETWEvents.Log.CreatingForm(nameof(ExploreForm));
|
||||||
Instance = this;
|
Instance = this;
|
||||||
|
SuspendLayout();
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
ResumeLayout();
|
||||||
|
|
||||||
SetTheme(Settings.Default.ExplorerWindowTheme, false);
|
SetTheme(Settings.Default.ExplorerWindowTheme, false);
|
||||||
|
|
||||||
@ -170,11 +169,13 @@ namespace CodeWalker
|
|||||||
var folderPath = folder?.Trim();
|
var folderPath = folder?.Trim();
|
||||||
if (!string.IsNullOrEmpty(folderPath))
|
if (!string.IsNullOrEmpty(folderPath))
|
||||||
{
|
{
|
||||||
var root = new MainTreeFolder();
|
var root = new MainTreeFolder
|
||||||
root.FullPath = folderPath;
|
{
|
||||||
root.Path = folderPath;
|
FullPath = folderPath,
|
||||||
root.Name = Path.GetFileName(Path.GetDirectoryName(folderPath));
|
Path = folderPath,
|
||||||
root.IsExtraFolder = true;
|
Name = Path.GetFileName(Path.GetDirectoryName(folderPath)) ?? folderPath,
|
||||||
|
IsExtraFolder = true
|
||||||
|
};
|
||||||
ExtraRootFolders.Add(root);
|
ExtraRootFolders.Add(root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -185,29 +186,28 @@ namespace CodeWalker
|
|||||||
var extrafolders = new StringBuilder();
|
var extrafolders = new StringBuilder();
|
||||||
foreach (var folder in ExtraRootFolders)
|
foreach (var folder in ExtraRootFolders)
|
||||||
{
|
{
|
||||||
if (extrafolders.Length > 0) extrafolders.Append("\n");
|
extrafolders.AppendLine(folder.FullPath);
|
||||||
extrafolders.Append(folder.FullPath);
|
|
||||||
}
|
}
|
||||||
Settings.Default.RPFExplorerExtraFolders = extrafolders.ToString();
|
Settings.Default.RPFExplorerExtraFolders = extrafolders.ToString();
|
||||||
|
|
||||||
Settings.Default.Save();
|
Settings.Default.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(FileCache))]
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
|
ETWEvents.Log.LoadingForm(nameof(ExploreForm));
|
||||||
//called from ExploreForm_Load
|
//called from ExploreForm_Load
|
||||||
|
|
||||||
// This is probably not necessary now that the GTA folder is checked
|
// This is probably not necessary now that the GTA folder is checked
|
||||||
// in the Program.cs when the game is initiated, but we will leave it
|
// in the Program.cs when the game is initiated, but we will leave it
|
||||||
// here for now to make sure
|
// here for now to make sure
|
||||||
if(!GTAFolder.UpdateGTAFolder(true))
|
if (!GTAFolder.UpdateGTAFolder(true))
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
return;
|
throw new Exception("No GTA Folder found!");
|
||||||
}
|
}
|
||||||
|
|
||||||
FileCache = GameFileCacheFactory.GetInstance();
|
|
||||||
|
|
||||||
new Task(async () =>
|
new Task(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -271,6 +271,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
UpdateStatus?.Invoke("Loading file cache...");
|
UpdateStatus?.Invoke("Loading file cache...");
|
||||||
var allRpfs = AllRpfs;
|
var allRpfs = AllRpfs;
|
||||||
|
|
||||||
FileCache.Init(updateStatus: null, ErrorLog, allRpfs); //inits main dicts and archetypes only...
|
FileCache.Init(updateStatus: null, ErrorLog, allRpfs); //inits main dicts and archetypes only...
|
||||||
|
|
||||||
UpdateStatus?.Invoke("Loading materials...");
|
UpdateStatus?.Invoke("Loading materials...");
|
||||||
@ -299,9 +300,10 @@ namespace CodeWalker
|
|||||||
return FileCache; //return it even though it's probably not inited yet..
|
return FileCache; //return it even though it's probably not inited yet..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(FileTypes))]
|
||||||
public static void InitFileTypes()
|
public static void InitFileTypes()
|
||||||
{
|
{
|
||||||
FileTypes = new Dictionary<string, FileTypeInfo>(StringComparer.OrdinalIgnoreCase);
|
FileTypes ??= new Dictionary<string, FileTypeInfo>(StringComparer.OrdinalIgnoreCase);
|
||||||
InitFileType(".rpf", "Rage Package File", 3);
|
InitFileType(".rpf", "Rage Package File", 3);
|
||||||
InitFileType("", "File", 4);
|
InitFileType("", "File", 4);
|
||||||
InitFileType(".dat", "Data File", 4);
|
InitFileType(".dat", "Data File", 4);
|
||||||
@ -361,15 +363,28 @@ namespace CodeWalker
|
|||||||
InitSubFileType(".dat", "distantlights.dat", "Distant Lights", 6, FileTypeAction.ViewDistantLights);
|
InitSubFileType(".dat", "distantlights.dat", "Distant Lights", 6, FileTypeAction.ViewDistantLights);
|
||||||
InitSubFileType(".dat", "distantlights_hd.dat", "Distant Lights", 6, FileTypeAction.ViewDistantLights);
|
InitSubFileType(".dat", "distantlights_hd.dat", "Distant Lights", 6, FileTypeAction.ViewDistantLights);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(FileTypes))]
|
||||||
|
private static void EnsureFileTypesInitialized()
|
||||||
|
{
|
||||||
|
if (FileTypes is null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"FileTypes are not initialized yet, please ensure {nameof(InitFileTypes)} is called before using FileTypes");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void InitFileType(string ext, string name, int imgidx, FileTypeAction defaultAction = FileTypeAction.ViewHex, bool xmlConvertible = false)
|
private static void InitFileType(string ext, string name, int imgidx, FileTypeAction defaultAction = FileTypeAction.ViewHex, bool xmlConvertible = false)
|
||||||
{
|
{
|
||||||
|
EnsureFileTypesInitialized();
|
||||||
|
FileTypes ??= new Dictionary<string, FileTypeInfo>(StringComparer.OrdinalIgnoreCase);
|
||||||
var ft = new FileTypeInfo(ext, name, imgidx, defaultAction, xmlConvertible);
|
var ft = new FileTypeInfo(ext, name, imgidx, defaultAction, xmlConvertible);
|
||||||
FileTypes[ext] = ft;
|
FileTypes[ext] = ft;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void InitSubFileType(string ext, string subext, string name, int imgidx, FileTypeAction defaultAction = FileTypeAction.ViewHex, bool xmlConvertible = false)
|
private static void InitSubFileType(string ext, string subext, string name, int imgidx, FileTypeAction defaultAction = FileTypeAction.ViewHex, bool xmlConvertible = false)
|
||||||
{
|
{
|
||||||
FileTypeInfo pti = null;
|
EnsureFileTypesInitialized();
|
||||||
if (FileTypes.TryGetValue(ext, out pti))
|
if (FileTypes.TryGetValue(ext, out var pti))
|
||||||
{
|
{
|
||||||
var ft = new FileTypeInfo(subext, name, imgidx, defaultAction, xmlConvertible);
|
var ft = new FileTypeInfo(subext, name, imgidx, defaultAction, xmlConvertible);
|
||||||
pti.AddSubType(ft);
|
pti.AddSubType(ft);
|
||||||
@ -377,6 +392,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
public static FileTypeInfo GetFileType(string fn)
|
public static FileTypeInfo GetFileType(string fn)
|
||||||
{
|
{
|
||||||
|
EnsureFileTypesInitialized();
|
||||||
if (fn.IndexOfAny(InvalidFileNameChars) != -1)
|
if (fn.IndexOfAny(InvalidFileNameChars) != -1)
|
||||||
{
|
{
|
||||||
return FileTypes[""];
|
return FileTypes[""];
|
||||||
@ -402,7 +418,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ft = new FileTypeInfo(ext, ext.Substring(1).ToUpperInvariant() + " File", 4, FileTypeAction.ViewHex, false);
|
ft = new FileTypeInfo(ext, ext[1..].ToUpperInvariant() + " File", 4, FileTypeAction.ViewHex, false);
|
||||||
FileTypes[ft.Extension] = ft; //save it for later!
|
FileTypes[ft.Extension] = ft; //save it for later!
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
@ -461,10 +477,11 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Navigate(MainTreeFolder f)
|
public void Navigate(MainTreeFolder? f)
|
||||||
{
|
{
|
||||||
if (!Ready) return;
|
if (!Ready) return;
|
||||||
if (f == CurrentFolder) return; //already there!
|
if (f == CurrentFolder) return; //already there!
|
||||||
|
ArgumentNullException.ThrowIfNull(f);
|
||||||
if (f.IsSearchResults)
|
if (f.IsSearchResults)
|
||||||
{
|
{
|
||||||
AddMainTreeViewRoot(f); //add the current search result node
|
AddMainTreeViewRoot(f); //add the current search result node
|
||||||
@ -477,8 +494,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
foreach (TreeNode tn in MainTreeView.Nodes)
|
foreach (TreeNode tn in MainTreeView.Nodes)
|
||||||
{
|
{
|
||||||
var tnf = tn.Tag as MainTreeFolder;
|
if ((tn != sr) && (tn.Tag is MainTreeFolder tnf) && (tnf.IsSearchResults))
|
||||||
if ((tn != sr) && (tnf != null) && (tnf.IsSearchResults))
|
|
||||||
{
|
{
|
||||||
MainTreeView.Nodes.Remove(tn); //remove existing search result node
|
MainTreeView.Nodes.Remove(tn); //remove existing search result node
|
||||||
break;
|
break;
|
||||||
@ -494,7 +510,7 @@ namespace CodeWalker
|
|||||||
hierarchy.Add(pf);
|
hierarchy.Add(pf);
|
||||||
pf = pf.Parent;
|
pf = pf.Parent;
|
||||||
}
|
}
|
||||||
TreeNode n = null;
|
TreeNode? n = null;
|
||||||
for (int i = hierarchy.Count - 1; i >= 0; i--)
|
for (int i = hierarchy.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
n = FindTreeNode(hierarchy[i], n);
|
n = FindTreeNode(hierarchy[i], n);
|
||||||
@ -516,9 +532,10 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
if (!Ready) return;
|
if (!Ready) return;
|
||||||
var pathl = path.Replace('/', '\\');
|
var pathl = path.Replace('/', '\\');
|
||||||
if ((CurrentFolder != null) && (CurrentFolder.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase))) return; //already there
|
if ((CurrentFolder != null) && (CurrentFolder.Path.Equals(path, StringComparison.InvariantCultureIgnoreCase)))
|
||||||
|
return; //already there
|
||||||
var hierarchy = pathl.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
var hierarchy = pathl.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
TreeNode n = MainTreeView.Nodes[0];// FindTreeNode("gta v", null);
|
TreeNode? n = MainTreeView.Nodes[0];// FindTreeNode("gta v", null);
|
||||||
if (!string.IsNullOrEmpty(path))
|
if (!string.IsNullOrEmpty(path))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < hierarchy.Length; i++)
|
for (int i = 0; i < hierarchy.Length; i++)
|
||||||
@ -565,13 +582,13 @@ namespace CodeWalker
|
|||||||
EditModeButton.Enabled = true;
|
EditModeButton.Enabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GoUp(MainTreeFolder toFolder = null)
|
public void GoUp(MainTreeFolder? toFolder = null)
|
||||||
{
|
{
|
||||||
var fld = (toFolder == null) ? CurrentFolder?.Parent : toFolder;
|
var fld = (toFolder == null) ? CurrentFolder?.Parent : toFolder;
|
||||||
if (fld == null) return;
|
if (fld == null) return;
|
||||||
Navigate(fld);
|
Navigate(fld);
|
||||||
}
|
}
|
||||||
public void GoBack(MainTreeFolder toFolder = null)
|
public void GoBack(MainTreeFolder? toFolder = null)
|
||||||
{
|
{
|
||||||
if (BackSteps.Count == 0) return;
|
if (BackSteps.Count == 0) return;
|
||||||
var s = BackSteps.Pop();
|
var s = BackSteps.Pop();
|
||||||
@ -586,7 +603,7 @@ namespace CodeWalker
|
|||||||
HistoryNavigating = false;
|
HistoryNavigating = false;
|
||||||
UpdateHistoryUI();
|
UpdateHistoryUI();
|
||||||
}
|
}
|
||||||
public void GoForward(MainTreeFolder toFolder = null)
|
public void GoForward(MainTreeFolder? toFolder = null)
|
||||||
{
|
{
|
||||||
if (ForwardSteps.Count == 0) return;
|
if (ForwardSteps.Count == 0) return;
|
||||||
var s = ForwardSteps.Pop();
|
var s = ForwardSteps.Pop();
|
||||||
@ -611,6 +628,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
var button = UpButton.DropDownItems.Add(pf.GetToolText());
|
var button = UpButton.DropDownItems.Add(pf.GetToolText());
|
||||||
button.Tag = pf;
|
button.Tag = pf;
|
||||||
|
|
||||||
button.Click += UpListButton_Click;
|
button.Click += UpListButton_Click;
|
||||||
pf = pf.Parent;
|
pf = pf.Parent;
|
||||||
if (i >= 10) break;
|
if (i >= 10) break;
|
||||||
@ -709,7 +727,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TreeNode FindTreeNode(MainTreeFolder f, TreeNode parent)
|
private TreeNode? FindTreeNode(MainTreeFolder f, TreeNode? parent)
|
||||||
{
|
{
|
||||||
var tnc = (parent != null) ? parent.Nodes : MainTreeView.Nodes;
|
var tnc = (parent != null) ? parent.Nodes : MainTreeView.Nodes;
|
||||||
foreach (TreeNode node in tnc)
|
foreach (TreeNode node in tnc)
|
||||||
@ -721,7 +739,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
private TreeNode FindTreeNode(string text, TreeNode parent)
|
private TreeNode? FindTreeNode(string text, TreeNode? parent)
|
||||||
{
|
{
|
||||||
var tnc = (parent != null) ? parent.Nodes : MainTreeView.Nodes;
|
var tnc = (parent != null) ? parent.Nodes : MainTreeView.Nodes;
|
||||||
foreach (TreeNode node in tnc)
|
foreach (TreeNode node in tnc)
|
||||||
@ -735,7 +753,8 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[MemberNotNull(nameof(RootFolder))]
|
||||||
|
[MemberNotNull(nameof(AllRpfs))]
|
||||||
private async Task RefreshMainTreeView()
|
private async Task RefreshMainTreeView()
|
||||||
{
|
{
|
||||||
using var _ = new DisposableTimer("RefreshMainTreeView");
|
using var _ = new DisposableTimer("RefreshMainTreeView");
|
||||||
@ -747,15 +766,18 @@ namespace CodeWalker
|
|||||||
UpdateStatus?.Invoke("Scanning...");
|
UpdateStatus?.Invoke("Scanning...");
|
||||||
|
|
||||||
|
|
||||||
var root = new MainTreeFolder();
|
var root = new MainTreeFolder
|
||||||
root.FullPath = GTAFolder.GetCurrentGTAFolderWithTrailingSlash();
|
{
|
||||||
root.Path = "";
|
FullPath = GTAFolder.GetCurrentGTAFolderWithTrailingSlash(),
|
||||||
root.Name = "GTA V";
|
Path = "",
|
||||||
|
Name = "GTA V"
|
||||||
|
};
|
||||||
RootFolder = root;
|
RootFolder = root;
|
||||||
|
|
||||||
var tasks = new List<Task<TreeNode>>();
|
var tasks = new List<Task<TreeNode>>
|
||||||
|
{
|
||||||
tasks.Add(Task.Run(() => RefreshMainTreeViewRoot(root, true)));
|
Task.Run(() => RefreshMainTreeViewRoot(root, true))
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
var remFolders = new List<MainTreeFolder>();
|
var remFolders = new List<MainTreeFolder>();
|
||||||
@ -791,6 +813,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
BeginInvoke(() =>
|
BeginInvoke(() =>
|
||||||
{
|
{
|
||||||
|
SuspendLayout();
|
||||||
MainTreeView.BeginUpdate();
|
MainTreeView.BeginUpdate();
|
||||||
ClearMainTreeView();
|
ClearMainTreeView();
|
||||||
|
|
||||||
@ -799,6 +822,7 @@ namespace CodeWalker
|
|||||||
Ready = true;
|
Ready = true;
|
||||||
|
|
||||||
MainTreeView.EndUpdate();
|
MainTreeView.EndUpdate();
|
||||||
|
ResumeLayout();
|
||||||
MainTreeViewRefreshComplete();
|
MainTreeViewRefreshComplete();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -889,6 +913,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
if (rpf.LastException != null) //incase of corrupted rpf (or renamed NG encrypted RPF)
|
if (rpf.LastException != null) //incase of corrupted rpf (or renamed NG encrypted RPF)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine(rpf.LastException);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1141,29 +1166,35 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
private MainTreeFolder CreateRpfTreeFolder(RpfFile rpf, string relpath, string fullpath)
|
private MainTreeFolder CreateRpfTreeFolder(RpfFile rpf, string relpath, string fullpath)
|
||||||
{
|
{
|
||||||
var node = new MainTreeFolder();
|
var node = new MainTreeFolder
|
||||||
node.RpfFile = rpf;
|
{
|
||||||
node.RpfFolder = rpf.Root;
|
RpfFile = rpf,
|
||||||
node.Name = rpf.Name;
|
RpfFolder = rpf.Root,
|
||||||
node.Path = relpath;
|
Name = rpf.Name,
|
||||||
node.FullPath = fullpath;
|
Path = relpath,
|
||||||
|
FullPath = fullpath,
|
||||||
|
};
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
private MainTreeFolder CreateRpfDirTreeFolder(RpfDirectoryEntry dir, string relpath, string fullpath)
|
private MainTreeFolder CreateRpfDirTreeFolder(RpfDirectoryEntry dir, string relpath, string fullpath)
|
||||||
{
|
{
|
||||||
var node = new MainTreeFolder();
|
var node = new MainTreeFolder
|
||||||
node.RpfFolder = dir;
|
{
|
||||||
node.Name = dir.Name;
|
RpfFolder = dir,
|
||||||
node.Path = relpath;
|
Name = dir.Name,
|
||||||
node.FullPath = fullpath;
|
Path = relpath,
|
||||||
|
FullPath = fullpath,
|
||||||
|
};
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
private MainTreeFolder CreateRootDirTreeFolder(string name, string path, string fullpath)
|
private MainTreeFolder CreateRootDirTreeFolder(string name, string path, string fullpath)
|
||||||
{
|
{
|
||||||
var node = new MainTreeFolder();
|
var node = new MainTreeFolder
|
||||||
node.Name = name;
|
{
|
||||||
node.Path = path;
|
Name = name,
|
||||||
node.FullPath = fullpath;
|
Path = path,
|
||||||
|
FullPath = fullpath,
|
||||||
|
};
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
private void RenameTreeFolder(MainTreeFolder f, string newname)
|
private void RenameTreeFolder(MainTreeFolder f, string newname)
|
||||||
@ -1299,6 +1330,8 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
ForceTreeRefresh?.Invoke();
|
ForceTreeRefresh?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void RefreshMainListView()
|
private void RefreshMainListView()
|
||||||
{
|
{
|
||||||
MainListView.VirtualListSize = 0;
|
MainListView.VirtualListSize = 0;
|
||||||
@ -1377,11 +1410,13 @@ namespace CodeWalker
|
|||||||
SearchGlobalButton.Checked = true;
|
SearchGlobalButton.Checked = true;
|
||||||
SearchFilterButton.Checked = false;
|
SearchFilterButton.Checked = false;
|
||||||
|
|
||||||
SearchResults = new MainTreeFolder();
|
SearchResults = new MainTreeFolder
|
||||||
SearchResults.Name = "Search Results: " + text;
|
{
|
||||||
SearchResults.Path = SearchResults.Name;
|
Name = "Search Results: " + text,
|
||||||
SearchResults.IsSearchResults = true;
|
Path = "Search Results: " + text,
|
||||||
SearchResults.SearchTerm = text;
|
IsSearchResults = true,
|
||||||
|
SearchTerm = text,
|
||||||
|
};
|
||||||
|
|
||||||
Navigate(SearchResults);
|
Navigate(SearchResults);
|
||||||
|
|
||||||
@ -1389,7 +1424,7 @@ namespace CodeWalker
|
|||||||
MainListView.SetSortIcon(SortColumnIndex, SortDirection);
|
MainListView.SetSortIcon(SortColumnIndex, SortDirection);
|
||||||
MainListView.VirtualListSize = 0;
|
MainListView.VirtualListSize = 0;
|
||||||
|
|
||||||
CurrentFiles.Clear();
|
CurrentFiles?.Clear();
|
||||||
|
|
||||||
UpdateStatus?.Invoke("Searching...");
|
UpdateStatus?.Invoke("Searching...");
|
||||||
|
|
||||||
@ -1401,7 +1436,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
Cursor = Cursors.WaitCursor;
|
Cursor = Cursors.WaitCursor;
|
||||||
|
|
||||||
var resultcount = RootFolder.Search(term, this);
|
var resultcount = RootFolder?.Search(term, this) ?? 0;
|
||||||
|
|
||||||
foreach(var extraFolder in ExtraRootFolders)
|
foreach(var extraFolder in ExtraRootFolders)
|
||||||
{
|
{
|
||||||
@ -1436,7 +1471,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void AddSearchResult(MainListItem item)
|
public void AddSearchResult(MainListItem? item)
|
||||||
{
|
{
|
||||||
if (SearchResults == null) return;
|
if (SearchResults == null) return;
|
||||||
if (SearchResults.ListItems != CurrentFiles) return;
|
if (SearchResults.ListItems != CurrentFiles) return;
|
||||||
@ -2416,7 +2451,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
File.WriteAllText(Path.Combine(CurrentFolder.FullPath, "texture_usage.json"), JsonConvert.SerializeObject(textures.Values.OrderBy(p => p.Count), new JsonSerializerSettings { Formatting = Newtonsoft.Json.Formatting.Indented }));
|
File.WriteAllText(Path.Combine(CurrentFolder.FullPath, "texture_usage.json"), System.Text.Json.JsonSerializer.Serialize(textures.Values.OrderBy(p => p.Count), new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));
|
||||||
|
|
||||||
var shaders = data.Values.ToList();
|
var shaders = data.Values.ToList();
|
||||||
shaders.Sort((a, b) => { return b.GeomCount.CompareTo(a.GeomCount); });
|
shaders.Sort((a, b) => { return b.GeomCount.CompareTo(a.GeomCount); });
|
||||||
@ -3691,11 +3726,13 @@ namespace CodeWalker
|
|||||||
if (folder.FullPath == folderPath) return;
|
if (folder.FullPath == folderPath) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var root = new MainTreeFolder();
|
var root = new MainTreeFolder
|
||||||
root.FullPath = folderPath;
|
{
|
||||||
root.Path = folderPath;
|
FullPath = folderPath,
|
||||||
root.Name = Path.GetFileName(Path.GetDirectoryName(folderPath));
|
Path = folderPath,
|
||||||
root.IsExtraFolder = true;
|
Name = Path.GetFileName(Path.GetDirectoryName(folderPath)),
|
||||||
|
IsExtraFolder = true,
|
||||||
|
};
|
||||||
ExtraRootFolders.Add(root);
|
ExtraRootFolders.Add(root);
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
@ -4586,13 +4623,13 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void ToolsBinSearchMenu_Click(object sender, EventArgs e)
|
private void ToolsBinSearchMenu_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
BinarySearchForm f = new BinarySearchForm(GetFileCache());
|
BinarySearchForm f = new BinarySearchForm();
|
||||||
f.Show(this);
|
f.Show(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToolsAudioExplorerMenu_Click(object sender, EventArgs e)
|
private void ToolsAudioExplorerMenu_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
AudioExplorerForm f = new AudioExplorerForm(GetFileCache());
|
AudioExplorerForm f = new AudioExplorerForm();
|
||||||
f.Show(this);
|
f.Show(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4604,7 +4641,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void ToolsJenkIndMenu_Click(object sender, EventArgs e)
|
private void ToolsJenkIndMenu_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
JenkIndForm f = new JenkIndForm(GetFileCache());
|
JenkIndForm f = new JenkIndForm();
|
||||||
f.Show(this);
|
f.Show(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4632,9 +4669,9 @@ namespace CodeWalker
|
|||||||
|
|
||||||
public class MainTreeFolder
|
public class MainTreeFolder
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public required string Name { get; set; }
|
||||||
|
|
||||||
private string _nameLower;
|
private string? _nameLower;
|
||||||
public string NameLower
|
public string NameLower
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -4646,20 +4683,20 @@ namespace CodeWalker
|
|||||||
_nameLower = value;
|
_nameLower = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public string Path { get; set; }
|
public required string Path { get; set; }
|
||||||
public string FullPath { get; set; }
|
public string? FullPath { get; set; }
|
||||||
public RpfFile RpfFile { get; set; }
|
public RpfFile? RpfFile { get; set; }
|
||||||
public RpfDirectoryEntry RpfFolder { get; set; }
|
public RpfDirectoryEntry? RpfFolder { get; set; }
|
||||||
public HashSet<string> Files { get; set; }
|
public HashSet<string>? Files { get; set; }
|
||||||
private object filesLock = new object();
|
private object filesLock = new object();
|
||||||
public MainTreeFolder Parent { get; set; }
|
public MainTreeFolder? Parent { get; set; }
|
||||||
public List<MainTreeFolder> Children { get; set; }
|
public List<MainTreeFolder>? Children { get; set; }
|
||||||
private object childrenLock = new object();
|
private readonly object childrenLock = new object();
|
||||||
public List<MainListItem> ListItems { get; set; }
|
public List<MainListItem>? ListItems { get; set; }
|
||||||
public TreeNode TreeNode { get; set; }
|
public TreeNode? TreeNode { get; set; }
|
||||||
public bool IsSearchResults { get; set; }
|
public bool IsSearchResults { get; set; } = false;
|
||||||
public string SearchTerm { get; set; }
|
public string? SearchTerm { get; set; }
|
||||||
public bool IsExtraFolder { get; set; }
|
public bool IsExtraFolder { get; set; } = false;
|
||||||
|
|
||||||
public void AddFile(string file)
|
public void AddFile(string file)
|
||||||
{
|
{
|
||||||
|
@ -401,7 +401,7 @@ namespace CodeWalker.Forms
|
|||||||
{
|
{
|
||||||
Stream wavStream = audio.GetWavStream();
|
Stream wavStream = audio.GetWavStream();
|
||||||
FileStream stream = File.Create(saveFileDialog.FileName);
|
FileStream stream = File.Create(saveFileDialog.FileName);
|
||||||
wavStream.CopyToFast(stream);
|
wavStream.CopyTo(stream);
|
||||||
stream.Close();
|
stream.Close();
|
||||||
wavStream.Close();
|
wavStream.Close();
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ namespace CodeWalker.Forms
|
|||||||
List<VertexTypePC> gridVerts = new List<VertexTypePC>();
|
List<VertexTypePC> gridVerts = new List<VertexTypePC>();
|
||||||
object gridSyncRoot = new object();
|
object gridSyncRoot = new object();
|
||||||
|
|
||||||
GameFileCache gameFileCache = null;
|
GameFileCache gameFileCache => GameFileCacheFactory.Instance;
|
||||||
Archetype currentArchetype = null;
|
Archetype currentArchetype = null;
|
||||||
bool updateArchetypeStatus = true;
|
bool updateArchetypeStatus = true;
|
||||||
|
|
||||||
@ -134,8 +134,6 @@ namespace CodeWalker.Forms
|
|||||||
if (this.DesignMode) return;
|
if (this.DesignMode) return;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
gameFileCache = GameFileCacheFactory.GetInstance();
|
|
||||||
|
|
||||||
if (ExploreForm.Instance == null)
|
if (ExploreForm.Instance == null)
|
||||||
{
|
{
|
||||||
gameFileCache.EnableDlc = false;
|
gameFileCache.EnableDlc = false;
|
||||||
@ -2310,7 +2308,7 @@ namespace CodeWalker.Forms
|
|||||||
Input.KeyDown(e, enablemove);
|
Input.KeyDown(e, enablemove);
|
||||||
|
|
||||||
var k = e.KeyCode;
|
var k = e.KeyCode;
|
||||||
var kb = Input.keyBindings;
|
var kb = Input.KeyBindings;
|
||||||
bool ctrl = Input.CtrlPressed;
|
bool ctrl = Input.CtrlPressed;
|
||||||
bool shift = Input.ShiftPressed;
|
bool shift = Input.ShiftPressed;
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ namespace CodeWalker.Forms
|
|||||||
return false;//what are we even doing here?
|
return false;//what are we even doing here?
|
||||||
case MetaFormat.AudioRel:
|
case MetaFormat.AudioRel:
|
||||||
var rel = XmlRel.GetRel(doc);
|
var rel = XmlRel.GetRel(doc);
|
||||||
if ((rel?.RelDatasSorted == null) || (rel.RelDatasSorted.Length == 0))
|
if ((rel?.RelDatas == null) || (rel.RelDatas.Length == 0))
|
||||||
{
|
{
|
||||||
MessageBox.Show("Schema not supported.", "Cannot import REL XML");
|
MessageBox.Show("Schema not supported.", "Cannot import REL XML");
|
||||||
return false;
|
return false;
|
||||||
|
@ -10,7 +10,6 @@ using System.Drawing.Imaging;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Remoting.Channels;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
@ -11,18 +11,25 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public static class GameFileCacheFactory
|
public static class GameFileCacheFactory
|
||||||
{
|
{
|
||||||
public static GameFileCache _instance = null;
|
public static GameFileCache? _instance;
|
||||||
public static GameFileCache GetInstance()
|
|
||||||
|
public static GameFileCache Instance
|
||||||
{
|
{
|
||||||
if (_instance == null)
|
get
|
||||||
|
{
|
||||||
|
if (_instance is null)
|
||||||
{
|
{
|
||||||
var s = Settings.Default;
|
var s = Settings.Default;
|
||||||
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
|
_instance = new GameFileCache(s.CacheSize, s.CacheTime, GTAFolder.CurrentGTAFolder, s.DLC, s.EnableMods, s.ExcludeFolders, Settings.Default.Key);
|
||||||
_instance = new GameFileCache(s.CacheSize, s.CacheTime, GTAFolder.CurrentGTAFolder, s.DLC, s.EnableMods, s.ExcludeFolders);
|
|
||||||
GTAFolder.OnGTAFolderChanged += _instance.SetGtaFolder;
|
GTAFolder.OnGTAFolderChanged += _instance.SetGtaFolder;
|
||||||
}
|
}
|
||||||
return _instance;
|
return _instance;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
public static GameFileCache GetInstance()
|
||||||
|
{
|
||||||
|
return Instance;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -752,7 +752,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void LoadPed()
|
public async ValueTask LoadPedAsync()
|
||||||
{
|
{
|
||||||
var pedname = PedNameComboBox.Text;
|
var pedname = PedNameComboBox.Text;
|
||||||
var pedhash = JenkHash.GenHash(pedname.ToLowerInvariant());
|
var pedhash = JenkHash.GenHash(pedname.ToLowerInvariant());
|
||||||
@ -765,7 +765,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
DetailsPropertyGrid.SelectedObject = null;
|
DetailsPropertyGrid.SelectedObject = null;
|
||||||
|
|
||||||
SelectedPed.Init(pedname, GameFileCache);
|
await SelectedPed.InitAsync(pedname, GameFileCache);
|
||||||
|
|
||||||
LoadModel(SelectedPed.Yft, pedchange);
|
LoadModel(SelectedPed.Yft, pedchange);
|
||||||
|
|
||||||
@ -839,14 +839,14 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetComponentDrawable(int index, object comboObj)
|
private async ValueTask SetComponentDrawableAsync(int index, object comboObj)
|
||||||
{
|
{
|
||||||
|
|
||||||
var comboItem = comboObj as ComponentComboItem;
|
var comboItem = comboObj as ComponentComboItem;
|
||||||
var name = comboItem?.DrawableName;
|
var name = comboItem?.DrawableName;
|
||||||
var tex = comboItem?.TextureName;
|
var tex = comboItem?.TextureName;
|
||||||
|
|
||||||
SelectedPed.SetComponentDrawable(index, name, tex, GameFileCache);
|
await SelectedPed.SetComponentDrawableAsync(index, name, tex, GameFileCache);
|
||||||
|
|
||||||
UpdateModelsUI();
|
UpdateModelsUI();
|
||||||
}
|
}
|
||||||
@ -916,10 +916,15 @@ namespace CodeWalker
|
|||||||
private void SelectClip(string name)
|
private void SelectClip(string name)
|
||||||
{
|
{
|
||||||
MetaHash cliphash = JenkHash.GenHash(name);
|
MetaHash cliphash = JenkHash.GenHash(name);
|
||||||
ClipMapEntry cme = null;
|
if (SelectedPed.Ycd?.ClipMap?.TryGetValue(cliphash, out var cme) ?? false)
|
||||||
SelectedPed.Ycd?.ClipMap?.TryGetValue(cliphash, out cme);
|
{
|
||||||
SelectedPed.AnimClip = cme;
|
SelectedPed.AnimClip = cme;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SelectedPed.AnimClip = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1209,7 +1214,7 @@ namespace CodeWalker
|
|||||||
Input.KeyDown(e, enablemove);
|
Input.KeyDown(e, enablemove);
|
||||||
|
|
||||||
var k = e.KeyCode;
|
var k = e.KeyCode;
|
||||||
var kb = Input.keyBindings;
|
var kb = Input.KeyBindings;
|
||||||
bool ctrl = Input.CtrlPressed;
|
bool ctrl = Input.CtrlPressed;
|
||||||
bool shift = Input.ShiftPressed;
|
bool shift = Input.ShiftPressed;
|
||||||
|
|
||||||
@ -1576,71 +1581,71 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void PedNameComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void PedNameComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (!GameFileCache.IsInited) return;
|
if (!GameFileCache.IsInited) return;
|
||||||
|
|
||||||
LoadPed();
|
await LoadPedAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompHeadComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompHeadComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(0, CompHeadComboBox.SelectedItem);
|
await SetComponentDrawableAsync(0, CompHeadComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompBerdComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompBerdComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(1, CompBerdComboBox.SelectedItem);
|
await SetComponentDrawableAsync(1, CompBerdComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompHairComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompHairComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(2, CompHairComboBox.SelectedItem);
|
await SetComponentDrawableAsync(2, CompHairComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompUpprComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompUpprComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(3, CompUpprComboBox.SelectedItem);
|
await SetComponentDrawableAsync(3, CompUpprComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompLowrComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompLowrComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(4, CompLowrComboBox.SelectedItem);
|
await SetComponentDrawableAsync(4, CompLowrComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompHandComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompHandComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(5, CompHandComboBox.SelectedItem);
|
await SetComponentDrawableAsync(5, CompHandComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompFeetComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompFeetComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(6, CompFeetComboBox.SelectedItem);
|
await SetComponentDrawableAsync(6, CompFeetComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompTeefComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompTeefComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(7, CompTeefComboBox.SelectedItem);
|
await SetComponentDrawableAsync(7, CompTeefComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompAccsComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompAccsComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(8, CompAccsComboBox.SelectedItem);
|
await SetComponentDrawableAsync(8, CompAccsComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompTaskComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompTaskComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(9, CompTaskComboBox.SelectedItem);
|
await SetComponentDrawableAsync(9, CompTaskComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompDeclComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompDeclComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(10, CompDeclComboBox.SelectedItem);
|
await SetComponentDrawableAsync(10, CompDeclComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompJbibComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
private async void CompJbibComboBox_SelectedIndexChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetComponentDrawable(11, CompJbibComboBox.SelectedItem);
|
await SetComponentDrawableAsync(11, CompJbibComboBox.SelectedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClipDictComboBox_TextChanged(object sender, EventArgs e)
|
private void ClipDictComboBox_TextChanged(object sender, EventArgs e)
|
||||||
|
@ -16,18 +16,16 @@ using System.Threading.Tasks;
|
|||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Windows.Shell;
|
using System.Windows.Shell;
|
||||||
|
|
||||||
namespace CodeWalker
|
namespace CodeWalker;
|
||||||
|
static class Program
|
||||||
{
|
{
|
||||||
static class Program
|
|
||||||
{
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
public static extern bool AllocConsole();
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main entry point for the application.
|
/// The main entry point for the application.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||||
ConsoleWindow.Hide();
|
ConsoleWindow.Hide();
|
||||||
@ -36,8 +34,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
Console.WriteLine($"Unhandeled exception occured: {e.Exception}");
|
Console.WriteLine($"Unhandeled exception occured: {e.Exception}");
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
|
||||||
bool menumode = false;
|
bool menumode = false;
|
||||||
bool explorermode = false;
|
bool explorermode = false;
|
||||||
bool projectmode = false;
|
bool projectmode = false;
|
||||||
@ -84,7 +81,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EnsureJumpList();
|
Task.Run(EnsureJumpList);
|
||||||
|
|
||||||
//Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
//Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
@ -221,8 +218,9 @@ namespace CodeWalker
|
|||||||
Settings.Default.JumpListInitialised = true;
|
Settings.Default.JumpListInitialised = true;
|
||||||
Settings.Default.Save();
|
Settings.Default.Save();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{ }
|
{
|
||||||
|
Console.WriteLine($"Initializing console failed {ex}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
59
CodeWalker/Properties/Settings.Designer.cs
generated
59
CodeWalker/Properties/Settings.Designer.cs
generated
@ -8,9 +8,6 @@
|
|||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace CodeWalker.Properties {
|
namespace CodeWalker.Properties {
|
||||||
|
|
||||||
|
|
||||||
@ -590,34 +587,6 @@ namespace CodeWalker.Properties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
|
||||||
[global::System.Configuration.DefaultSettingValueAttribute(@"<?xml version=""1.0"" encoding=""utf-16""?>
|
|
||||||
<ArrayOfString xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
|
|
||||||
<string>Move Forwards: W</string>
|
|
||||||
<string>Move Backwards: S</string>
|
|
||||||
<string>Move Left: A</string>
|
|
||||||
<string>Move Right: D</string>
|
|
||||||
<string>Move Up: R</string>
|
|
||||||
<string>Move Down: F</string>
|
|
||||||
<string>Move Slower / Zoom In: Z</string>
|
|
||||||
<string>Move Faster / Zoom Out: X</string>
|
|
||||||
<string>Toggle Mouse Select: C</string>
|
|
||||||
<string>Toggle Toolbar: T</string>
|
|
||||||
<string>Exit Edit Mode: Q</string>
|
|
||||||
<string>Edit Position: W</string>
|
|
||||||
<string>Edit Rotation: E</string>
|
|
||||||
<string>Edit Scale: R</string>
|
|
||||||
</ArrayOfString>")]
|
|
||||||
public global::System.Collections.Specialized.StringCollection KeyBindings {
|
|
||||||
get {
|
|
||||||
return ((global::System.Collections.Specialized.StringCollection)(this["KeyBindings"]));
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
this["KeyBindings"] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||||
@ -929,5 +898,33 @@ namespace CodeWalker.Properties {
|
|||||||
this["AntiAliasing"] = value;
|
this["AntiAliasing"] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Configuration.DefaultSettingValueAttribute(@"<?xml version=""1.0"" encoding=""utf-16""?>
|
||||||
|
<ArrayOfString xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"">
|
||||||
|
<string>Move Forwards: W</string>
|
||||||
|
<string>Move Backwards: S</string>
|
||||||
|
<string>Move Left: A</string>
|
||||||
|
<string>Move Right: D</string>
|
||||||
|
<string>Move Up: R</string>
|
||||||
|
<string>Move Down: F</string>
|
||||||
|
<string>Move Slower / Zoom In: Z</string>
|
||||||
|
<string>Move Faster / Zoom Out: X</string>
|
||||||
|
<string>Toggle Mouse Select: C</string>
|
||||||
|
<string>Toggle Toolbar: T</string>
|
||||||
|
<string>Exit Edit Mode: Q</string>
|
||||||
|
<string>Edit Position: W</string>
|
||||||
|
<string>Edit Rotation: E</string>
|
||||||
|
<string>Edit Scale: R</string>
|
||||||
|
</ArrayOfString>")]
|
||||||
|
public global::System.Collections.Specialized.StringCollection KeyBindings {
|
||||||
|
get {
|
||||||
|
return ((global::System.Collections.Specialized.StringCollection)(this["KeyBindings"]));
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
this["KeyBindings"] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,25 +143,6 @@
|
|||||||
<Setting Name="DLC" Type="System.String" Scope="User">
|
<Setting Name="DLC" Type="System.String" Scope="User">
|
||||||
<Value Profile="(Default)" />
|
<Value Profile="(Default)" />
|
||||||
</Setting>
|
</Setting>
|
||||||
<Setting Name="KeyBindings" Type="System.Collections.Specialized.StringCollection" Scope="User">
|
|
||||||
<Value Profile="(Default)"><?xml version="1.0" encoding="utf-16"?>
|
|
||||||
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
|
||||||
<string>Move Forwards: W</string>
|
|
||||||
<string>Move Backwards: S</string>
|
|
||||||
<string>Move Left: A</string>
|
|
||||||
<string>Move Right: D</string>
|
|
||||||
<string>Move Up: R</string>
|
|
||||||
<string>Move Down: F</string>
|
|
||||||
<string>Move Slower / Zoom In: Z</string>
|
|
||||||
<string>Move Faster / Zoom Out: X</string>
|
|
||||||
<string>Toggle Mouse Select: C</string>
|
|
||||||
<string>Toggle Toolbar: T</string>
|
|
||||||
<string>Exit Edit Mode: Q</string>
|
|
||||||
<string>Edit Position: W</string>
|
|
||||||
<string>Edit Rotation: E</string>
|
|
||||||
<string>Edit Scale: R</string>
|
|
||||||
</ArrayOfString></Value>
|
|
||||||
</Setting>
|
|
||||||
<Setting Name="XInputLThumbInvert" Type="System.Boolean" Scope="User">
|
<Setting Name="XInputLThumbInvert" Type="System.Boolean" Scope="User">
|
||||||
<Value Profile="(Default)">True</Value>
|
<Value Profile="(Default)">True</Value>
|
||||||
</Setting>
|
</Setting>
|
||||||
@ -240,5 +221,24 @@
|
|||||||
<Setting Name="AntiAliasing" Type="System.Int32" Scope="User">
|
<Setting Name="AntiAliasing" Type="System.Int32" Scope="User">
|
||||||
<Value Profile="(Default)">2</Value>
|
<Value Profile="(Default)">2</Value>
|
||||||
</Setting>
|
</Setting>
|
||||||
|
<Setting Name="KeyBindings" Type="System.Collections.Specialized.StringCollection" Scope="User">
|
||||||
|
<Value Profile="(Default)"><?xml version="1.0" encoding="utf-16"?>
|
||||||
|
<ArrayOfString xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||||
|
<string>Move Forwards: W</string>
|
||||||
|
<string>Move Backwards: S</string>
|
||||||
|
<string>Move Left: A</string>
|
||||||
|
<string>Move Right: D</string>
|
||||||
|
<string>Move Up: R</string>
|
||||||
|
<string>Move Down: F</string>
|
||||||
|
<string>Move Slower / Zoom In: Z</string>
|
||||||
|
<string>Move Faster / Zoom Out: X</string>
|
||||||
|
<string>Toggle Mouse Select: C</string>
|
||||||
|
<string>Toggle Toolbar: T</string>
|
||||||
|
<string>Exit Edit Mode: Q</string>
|
||||||
|
<string>Edit Position: W</string>
|
||||||
|
<string>Edit Rotation: E</string>
|
||||||
|
<string>Edit Scale: R</string>
|
||||||
|
</ArrayOfString></Value>
|
||||||
|
</Setting>
|
||||||
</Settings>
|
</Settings>
|
||||||
</SettingsFile>
|
</SettingsFile>
|
@ -57,7 +57,7 @@ namespace CodeWalker.Rendering
|
|||||||
{
|
{
|
||||||
//SharpDX.Configuration.EnableObjectTracking = true;
|
//SharpDX.Configuration.EnableObjectTracking = true;
|
||||||
|
|
||||||
SwapChainDescription scd = new SwapChainDescription()
|
var scd = new SwapChainDescription()
|
||||||
{
|
{
|
||||||
BufferCount = 2,
|
BufferCount = 2,
|
||||||
Flags = SwapChainFlags.None,
|
Flags = SwapChainFlags.None,
|
||||||
|
@ -14,15 +14,14 @@ namespace CodeWalker.Tools
|
|||||||
{
|
{
|
||||||
public partial class AudioExplorerForm : Form
|
public partial class AudioExplorerForm : Form
|
||||||
{
|
{
|
||||||
private GameFileCache GameFileCache { get; set; }
|
private static GameFileCache GameFileCache { get => GameFileCacheFactory.Instance; }
|
||||||
|
|
||||||
private List<string> NameComboItems = new List<string>();
|
private List<string> NameComboItems = new List<string>();
|
||||||
private Dictionary<string, RelData> NameComboLookup = new Dictionary<string, RelData>();
|
private Dictionary<string, RelData> NameComboLookup = new Dictionary<string, RelData>();
|
||||||
|
|
||||||
|
|
||||||
public AudioExplorerForm(GameFileCache gfc)
|
public AudioExplorerForm()
|
||||||
{
|
{
|
||||||
GameFileCache = gfc;
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
LoadDropDowns();
|
LoadDropDowns();
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,12 @@ namespace CodeWalker.Tools
|
|||||||
private volatile bool InProgress = false;
|
private volatile bool InProgress = false;
|
||||||
private volatile bool AbortOperation = false;
|
private volatile bool AbortOperation = false;
|
||||||
|
|
||||||
private GameFileCache FileCache = null;
|
private static GameFileCache FileCache => GameFileCacheFactory.Instance;
|
||||||
private RpfManager RpfMan = null;
|
private static RpfManager RpfMan => FileCache.RpfMan;
|
||||||
|
|
||||||
|
|
||||||
public BinarySearchForm(GameFileCache cache = null)
|
public BinarySearchForm()
|
||||||
{
|
{
|
||||||
FileCache = cache;
|
|
||||||
RpfMan = cache?.RpfMan;
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,12 +35,11 @@ namespace CodeWalker.Tools
|
|||||||
DataTextBox.SetTabStopWidth(3);
|
DataTextBox.SetTabStopWidth(3);
|
||||||
|
|
||||||
|
|
||||||
if (RpfMan == null || !RpfMan.IsInited)
|
if (!RpfMan.IsInited)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
|
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
|
||||||
RpfMan ??= RpfManager.GetInstance();
|
|
||||||
RpfMan.Init(GTAFolder.CurrentGTAFolder, UpdateStatus, UpdateStatus, false, false);
|
RpfMan.Init(GTAFolder.CurrentGTAFolder, UpdateStatus, UpdateStatus, false, false);
|
||||||
RPFScanComplete();
|
RPFScanComplete();
|
||||||
});
|
});
|
||||||
|
@ -43,7 +43,9 @@ namespace CodeWalker.Tools
|
|||||||
private void BrowseForm_Load(object sender, EventArgs e)
|
private void BrowseForm_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var info = DetailsPropertyGrid.GetType().GetProperty("Controls");
|
var info = DetailsPropertyGrid.GetType().GetProperty("Controls");
|
||||||
var collection = info.GetValue(DetailsPropertyGrid, null) as Control.ControlCollection;
|
var collection = info?.GetValue(DetailsPropertyGrid, null) as Control.ControlCollection;
|
||||||
|
if (collection is not null)
|
||||||
|
{
|
||||||
foreach (var control in collection)
|
foreach (var control in collection)
|
||||||
{
|
{
|
||||||
var ctyp = control.GetType();
|
var ctyp = control.GetType();
|
||||||
@ -54,6 +56,8 @@ namespace CodeWalker.Tools
|
|||||||
prop.SetValue(control, 4.0); //somehow this sets the width of the property grid's label column...
|
prop.SetValue(control, 4.0); //somehow this sets the width of the property grid's label column...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FolderTextBox.Text = GTAFolder.CurrentGTAFolder;
|
FolderTextBox.Text = GTAFolder.CurrentGTAFolder;
|
||||||
DataHexLineCombo.Text = "16";
|
DataHexLineCombo.Text = "16";
|
||||||
@ -120,11 +124,7 @@ namespace CodeWalker.Tools
|
|||||||
|
|
||||||
string[] allfiles = Directory.GetFiles(searchpath, "*.rpf", SearchOption.AllDirectories);
|
string[] allfiles = Directory.GetFiles(searchpath, "*.rpf", SearchOption.AllDirectories);
|
||||||
|
|
||||||
uint totrpfs = 0;
|
var counts = new FileCounts();
|
||||||
uint totfiles = 0;
|
|
||||||
uint totfolders = 0;
|
|
||||||
uint totresfiles = 0;
|
|
||||||
uint totbinfiles = 0;
|
|
||||||
|
|
||||||
foreach (string rpfpath in allfiles)
|
foreach (string rpfpath in allfiles)
|
||||||
{
|
{
|
||||||
@ -139,22 +139,16 @@ namespace CodeWalker.Tools
|
|||||||
|
|
||||||
UpdateStatus("Scanning " + rf.Name + "...");
|
UpdateStatus("Scanning " + rf.Name + "...");
|
||||||
|
|
||||||
rf.ScanStructure(UpdateStatus, UpdateStatus);
|
counts += rf.ScanStructure(UpdateStatus, UpdateStatus);
|
||||||
|
|
||||||
totrpfs += rf.GrandTotalRpfCount;
|
|
||||||
totfiles += rf.GrandTotalFileCount;
|
|
||||||
totfolders += rf.GrandTotalFolderCount;
|
|
||||||
totresfiles += rf.GrandTotalResourceCount;
|
|
||||||
totbinfiles += rf.GrandTotalBinaryFileCount;
|
|
||||||
|
|
||||||
AddScannedFile(rf, null, true);
|
AddScannedFile(rf, null, true);
|
||||||
|
|
||||||
RootFiles.Add(rf);
|
RootFiles.Add(rf);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateStatus(string.Format("Scan complete. {0} RPF files, {1} total files, {2} total folders, {3} resources, {4} binary files.", totrpfs, totfiles, totfolders, totresfiles, totbinfiles));
|
UpdateStatus(string.Format("Scan complete. {0} RPF files, {1} total files, {2} total folders, {3} resources, {4} binary files.", counts.Rpfs, counts.Files, counts.Folders, counts.Resources, counts.BinaryFiles));
|
||||||
InProgress = false;
|
InProgress = false;
|
||||||
TotalFileCount = (int)totfiles;
|
TotalFileCount = (int)counts.Files;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -739,12 +733,11 @@ namespace CodeWalker.Tools
|
|||||||
errcount++;
|
errcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
totbytes += file.ExtractedByteCount;
|
|
||||||
curfile++;
|
curfile++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UpdateStatus("Test complete. " + errcount.ToString() + " problems encountered, " + totbytes.ToString() + " total bytes extracted.");
|
UpdateStatus("Test complete. " + errcount.ToString() + " problems encountered");
|
||||||
InProgress = false;
|
InProgress = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@ namespace CodeWalker.Tools
|
|||||||
{
|
{
|
||||||
Dictionary<uint, string> extraStrings = new Dictionary<uint, string>();
|
Dictionary<uint, string> extraStrings = new Dictionary<uint, string>();
|
||||||
|
|
||||||
|
private static GameFileCache GameFileCache => GameFileCacheFactory.Instance;
|
||||||
|
|
||||||
|
public JenkIndForm()
|
||||||
public JenkIndForm(GameFileCache gameFileCache = null)
|
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
@ -32,16 +32,15 @@ namespace CodeWalker.Tools
|
|||||||
MainPanel.Enabled = false;
|
MainPanel.Enabled = false;
|
||||||
Cursor = Cursors.WaitCursor;
|
Cursor = Cursors.WaitCursor;
|
||||||
|
|
||||||
if ((gameFileCache == null) || (gameFileCache.IsInited == false))
|
if (!GameFileCache.IsInited)
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
|
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
|
||||||
GameFileCache gfc = GameFileCacheFactory.GetInstance();
|
GameFileCache.DoFullStringIndex = true;
|
||||||
gfc.DoFullStringIndex = true;
|
GameFileCache.Init(UpdateStatus, UpdateStatus);
|
||||||
gfc.Init(UpdateStatus, UpdateStatus);
|
|
||||||
IndexBuildComplete();
|
IndexBuildComplete();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@ -58,8 +57,8 @@ namespace CodeWalker.Tools
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
UpdateStatus("Loading strings...");
|
UpdateStatus("Loading strings...");
|
||||||
gameFileCache.DoFullStringIndex = true;
|
GameFileCache.DoFullStringIndex = true;
|
||||||
await gameFileCache.InitStringDictsAsync();
|
await GameFileCache.InitStringDictsAsync();
|
||||||
IndexBuildComplete();
|
IndexBuildComplete();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -9,6 +9,7 @@ using CodeWalker.Properties;
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using CodeWalker.GameFiles;
|
using CodeWalker.GameFiles;
|
||||||
using CodeWalker.Utils;
|
using CodeWalker.Utils;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace CodeWalker
|
namespace CodeWalker
|
||||||
{
|
{
|
||||||
@ -16,7 +17,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
private static string currentGTAFolder = Settings.Default.GTAFolder;
|
private static string currentGTAFolder = Settings.Default.GTAFolder;
|
||||||
|
|
||||||
public static event Action<string> OnGTAFolderChanged;
|
public static event Action<string>? OnGTAFolderChanged;
|
||||||
public static string CurrentGTAFolder { get => currentGTAFolder; private set
|
public static string CurrentGTAFolder { get => currentGTAFolder; private set
|
||||||
{
|
{
|
||||||
if (currentGTAFolder == value) return;
|
if (currentGTAFolder == value) return;
|
||||||
@ -24,9 +25,9 @@ namespace CodeWalker
|
|||||||
OnGTAFolderChanged?.Invoke(currentGTAFolder);
|
OnGTAFolderChanged?.Invoke(currentGTAFolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static bool ValidateGTAFolder(string folder, out string failReason)
|
public static bool ValidateGTAFolder([NotNullWhen(true)] string? folder, out string failReason)
|
||||||
{
|
{
|
||||||
failReason = "";
|
failReason = string.Empty;
|
||||||
|
|
||||||
if(string.IsNullOrWhiteSpace(folder))
|
if(string.IsNullOrWhiteSpace(folder))
|
||||||
{
|
{
|
||||||
@ -49,7 +50,7 @@ namespace CodeWalker
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool ValidateGTAFolder(string folder) => ValidateGTAFolder(folder, out string reason);
|
public static bool ValidateGTAFolder([NotNullWhen(true)] string? folder) => ValidateGTAFolder(folder, out string reason);
|
||||||
|
|
||||||
public static bool IsCurrentGTAFolderValid() => ValidateGTAFolder(CurrentGTAFolder);
|
public static bool IsCurrentGTAFolderValid() => ValidateGTAFolder(CurrentGTAFolder);
|
||||||
|
|
||||||
@ -60,11 +61,11 @@ namespace CodeWalker
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
string origFolder = CurrentGTAFolder;
|
var origFolder = CurrentGTAFolder;
|
||||||
string folder = CurrentGTAFolder;
|
var folder = CurrentGTAFolder;
|
||||||
SelectFolderForm f = new SelectFolderForm();
|
SelectFolderForm f = new SelectFolderForm();
|
||||||
|
|
||||||
string autoFolder = AutoDetectFolder(out string source);
|
var autoFolder = AutoDetectFolder(out string? source);
|
||||||
if (autoFolder != null && MessageBox.Show($"Auto-detected game folder \"{autoFolder}\" from {source}.\n\nContinue with auto-detected folder?", "Auto-detected game folder", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
|
if (autoFolder != null && MessageBox.Show($"Auto-detected game folder \"{autoFolder}\" from {source}.\n\nContinue with auto-detected folder?", "Auto-detected game folder", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
|
||||||
{
|
{
|
||||||
f.SelectedFolder = autoFolder;
|
f.SelectedFolder = autoFolder;
|
||||||
@ -76,22 +77,23 @@ namespace CodeWalker
|
|||||||
folder = f.SelectedFolder;
|
folder = f.SelectedFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
string failReason;
|
if (ValidateGTAFolder(folder, out string? failReason))
|
||||||
if(ValidateGTAFolder(folder, out failReason))
|
|
||||||
{
|
{
|
||||||
SetGTAFolder(folder);
|
SetGTAFolder(folder);
|
||||||
if(folder != origFolder)
|
if (folder != origFolder)
|
||||||
{
|
{
|
||||||
MessageBox.Show($"Successfully changed GTA Folder to \"{folder}\"", "Set GTA Folder", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
MessageBox.Show($"Successfully changed GTA Folder to \"{folder}\"", "Set GTA Folder", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var tryAgain = MessageBox.Show($"Folder \"{folder}\" is not a valid GTA folder:\n\n{failReason}\n\nDo you want to try choosing a different folder?", "Unable to set GTA Folder", MessageBoxButtons.RetryCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
|
var tryAgain = MessageBox.Show($"Folder \"{folder}\" is not a valid GTA folder:\n\n{failReason}\n\nDo you want to try choosing a different folder?", "Unable to set GTA Folder", MessageBoxButtons.RetryCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
|
||||||
if(tryAgain == DialogResult.Retry)
|
if (tryAgain == DialogResult.Retry)
|
||||||
{
|
{
|
||||||
return UpdateGTAFolder(false);
|
return UpdateGTAFolder(false);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -123,9 +125,9 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
|
|
||||||
RegistryKey baseKey32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
|
RegistryKey baseKey32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
|
||||||
string steamPathValue = baseKey32.OpenSubKey(@"Software\Rockstar Games\GTAV")?.GetValue("InstallFolderSteam") as string;
|
string? steamPathValue = baseKey32.OpenSubKey(@"Software\Rockstar Games\GTAV")?.GetValue("InstallFolderSteam") as string;
|
||||||
string retailPathValue = baseKey32.OpenSubKey(@"Software\Rockstar Games\Grand Theft Auto V")?.GetValue("InstallFolder") as string;
|
string? retailPathValue = baseKey32.OpenSubKey(@"Software\Rockstar Games\Grand Theft Auto V")?.GetValue("InstallFolder") as string;
|
||||||
string oivPathValue = Registry.CurrentUser.OpenSubKey(@"Software\NewTechnologyStudio\OpenIV.exe\BrowseForFolder")?.GetValue("game_path_Five_pc") as string;
|
string? oivPathValue = Registry.CurrentUser.OpenSubKey(@"Software\NewTechnologyStudio\OpenIV.exe\BrowseForFolder")?.GetValue("game_path_Five_pc") as string;
|
||||||
|
|
||||||
if(steamPathValue?.EndsWith("\\GTAV") == true)
|
if(steamPathValue?.EndsWith("\\GTAV") == true)
|
||||||
{
|
{
|
||||||
@ -150,7 +152,7 @@ namespace CodeWalker
|
|||||||
return matches.Count > 0;
|
return matches.Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string AutoDetectFolder(out string source)
|
public static string? AutoDetectFolder(out string? source)
|
||||||
{
|
{
|
||||||
source = null;
|
source = null;
|
||||||
|
|
||||||
@ -164,7 +166,7 @@ namespace CodeWalker
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string AutoDetectFolder() => AutoDetectFolder(out string _);
|
public static string? AutoDetectFolder() => AutoDetectFolder(out string? _);
|
||||||
|
|
||||||
public static void UpdateSettings()
|
public static void UpdateSettings()
|
||||||
{
|
{
|
||||||
|
@ -42,7 +42,18 @@ namespace CodeWalker
|
|||||||
public volatile bool kbjump = false;
|
public volatile bool kbjump = false;
|
||||||
public volatile bool kbmoving = false;
|
public volatile bool kbmoving = false;
|
||||||
|
|
||||||
public KeyBindings keyBindings = new KeyBindings(Settings.Default.KeyBindings);
|
private KeyBindings keyBindings;
|
||||||
|
public KeyBindings KeyBindings
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return keyBindings ??= new KeyBindings(Settings.Default.KeyBindings);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
keyBindings = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public bool CtrlPressed = false;
|
public bool CtrlPressed = false;
|
||||||
public bool ShiftPressed = false;
|
public bool ShiftPressed = false;
|
||||||
@ -127,13 +138,13 @@ namespace CodeWalker
|
|||||||
//WASD move...
|
//WASD move...
|
||||||
if (enablemove)
|
if (enablemove)
|
||||||
{
|
{
|
||||||
if (k == keyBindings.MoveForward) kbmovefwd = true;
|
if (k == KeyBindings.MoveForward) kbmovefwd = true;
|
||||||
if (k == keyBindings.MoveBackward) kbmovebck = true;
|
if (k == KeyBindings.MoveBackward) kbmovebck = true;
|
||||||
if (k == keyBindings.MoveLeft) kbmovelft = true;
|
if (k == KeyBindings.MoveLeft) kbmovelft = true;
|
||||||
if (k == keyBindings.MoveRight) kbmovergt = true;
|
if (k == KeyBindings.MoveRight) kbmovergt = true;
|
||||||
if (k == keyBindings.MoveUp) kbmoveup = true;
|
if (k == KeyBindings.MoveUp) kbmoveup = true;
|
||||||
if (k == keyBindings.MoveDown) kbmovedn = true;
|
if (k == KeyBindings.MoveDown) kbmovedn = true;
|
||||||
if (k == keyBindings.Jump) kbjump = true;
|
if (k == KeyBindings.Jump) kbjump = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
kbmoving = kbmovefwd || kbmovebck || kbmovelft || kbmovergt || kbmoveup || kbmovedn || kbjump;
|
kbmoving = kbmovefwd || kbmovebck || kbmovelft || kbmovergt || kbmoveup || kbmovedn || kbjump;
|
||||||
@ -146,13 +157,13 @@ namespace CodeWalker
|
|||||||
ShiftPressed = (e.Modifiers & Keys.Shift) > 0;
|
ShiftPressed = (e.Modifiers & Keys.Shift) > 0;
|
||||||
|
|
||||||
var k = e.KeyCode;
|
var k = e.KeyCode;
|
||||||
if (k == keyBindings.MoveForward) kbmovefwd = false;
|
if (k == KeyBindings.MoveForward) kbmovefwd = false;
|
||||||
if (k == keyBindings.MoveBackward) kbmovebck = false;
|
if (k == KeyBindings.MoveBackward) kbmovebck = false;
|
||||||
if (k == keyBindings.MoveLeft) kbmovelft = false;
|
if (k == KeyBindings.MoveLeft) kbmovelft = false;
|
||||||
if (k == keyBindings.MoveRight) kbmovergt = false;
|
if (k == KeyBindings.MoveRight) kbmovergt = false;
|
||||||
if (k == keyBindings.MoveUp) kbmoveup = false;
|
if (k == KeyBindings.MoveUp) kbmoveup = false;
|
||||||
if (k == keyBindings.MoveDown) kbmovedn = false;
|
if (k == KeyBindings.MoveDown) kbmovedn = false;
|
||||||
if (k == keyBindings.Jump) kbjump = false;
|
if (k == KeyBindings.Jump) kbjump = false;
|
||||||
|
|
||||||
kbmoving = kbmovefwd || kbmovebck || kbmovelft || kbmovergt || kbmoveup || kbmovedn || kbjump;
|
kbmoving = kbmovefwd || kbmovebck || kbmovelft || kbmovergt || kbmoveup || kbmovedn || kbjump;
|
||||||
|
|
||||||
@ -263,6 +274,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
public KeyBindings(StringCollection sc)
|
public KeyBindings(StringCollection sc)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine("Creating KeyBindings");
|
||||||
foreach (string s in sc)
|
foreach (string s in sc)
|
||||||
{
|
{
|
||||||
string[] parts = s.Split(':');
|
string[] parts = s.Split(':');
|
||||||
|
@ -1041,7 +1041,7 @@ namespace CodeWalker
|
|||||||
Input.KeyDown(e, enablemove);
|
Input.KeyDown(e, enablemove);
|
||||||
|
|
||||||
var k = e.KeyCode;
|
var k = e.KeyCode;
|
||||||
var kb = Input.keyBindings;
|
var kb = Input.KeyBindings;
|
||||||
bool ctrl = Input.CtrlPressed;
|
bool ctrl = Input.CtrlPressed;
|
||||||
bool shift = Input.ShiftPressed;
|
bool shift = Input.ShiftPressed;
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ namespace CodeWalker.World
|
|||||||
public partial class CutsceneForm : Form
|
public partial class CutsceneForm : Form
|
||||||
{
|
{
|
||||||
private WorldForm WorldForm;
|
private WorldForm WorldForm;
|
||||||
private GameFileCache GameFileCache;
|
private GameFileCache GameFileCache => GameFileCacheFactory.Instance;
|
||||||
private AudioDatabase AudioDatabase;
|
private AudioDatabase AudioDatabase;
|
||||||
|
|
||||||
private Cutscene Cutscene = null;
|
private Cutscene Cutscene = null;
|
||||||
@ -43,7 +43,6 @@ namespace CodeWalker.World
|
|||||||
public CutsceneForm(WorldForm worldForm)
|
public CutsceneForm(WorldForm worldForm)
|
||||||
{
|
{
|
||||||
WorldForm = worldForm;
|
WorldForm = worldForm;
|
||||||
GameFileCache = WorldForm.GameFileCache;
|
|
||||||
AudioDatabase = new AudioDatabase();
|
AudioDatabase = new AudioDatabase();
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
@ -105,7 +104,7 @@ namespace CodeWalker.World
|
|||||||
private void SelectCutscene(CutsceneDropdownItem dditem)
|
private void SelectCutscene(CutsceneDropdownItem dditem)
|
||||||
{
|
{
|
||||||
Cursor = Cursors.WaitCursor;
|
Cursor = Cursors.WaitCursor;
|
||||||
Task.Run(() =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
CutFile cutFile = null;
|
CutFile cutFile = null;
|
||||||
Cutscene cutscene = null;
|
Cutscene cutscene = null;
|
||||||
@ -125,7 +124,7 @@ namespace CodeWalker.World
|
|||||||
GameFileCache.RpfMan.LoadFile(cutFile, entry);
|
GameFileCache.RpfMan.LoadFile(cutFile, entry);
|
||||||
|
|
||||||
cutscene = new Cutscene();
|
cutscene = new Cutscene();
|
||||||
cutscene.Init(cutFile, GameFileCache, WorldForm, AudioDatabase);
|
await cutscene.InitAsync(cutFile, GameFileCache, WorldForm, AudioDatabase);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -473,7 +472,7 @@ namespace CodeWalker.World
|
|||||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class Cutscene
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class Cutscene
|
||||||
{
|
{
|
||||||
public CutFile CutFile { get; set; } = null;
|
public CutFile CutFile { get; set; } = null;
|
||||||
private GameFileCache GameFileCache = null;
|
private GameFileCache GameFileCache => GameFileCacheFactory.Instance;
|
||||||
private WorldForm WorldForm = null;
|
private WorldForm WorldForm = null;
|
||||||
private AudioDatabase AudioDB = null;
|
private AudioDatabase AudioDB = null;
|
||||||
|
|
||||||
@ -516,10 +515,9 @@ namespace CodeWalker.World
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void Init(CutFile cutFile, GameFileCache gfc, WorldForm wf, AudioDatabase adb)
|
public async ValueTask InitAsync(CutFile cutFile, GameFileCache gfc, WorldForm wf, AudioDatabase adb)
|
||||||
{
|
{
|
||||||
CutFile = cutFile;
|
CutFile = cutFile;
|
||||||
GameFileCache = gfc;
|
|
||||||
WorldForm = wf;
|
WorldForm = wf;
|
||||||
AudioDB = adb;
|
AudioDB = adb;
|
||||||
|
|
||||||
@ -539,7 +537,7 @@ namespace CodeWalker.World
|
|||||||
|
|
||||||
|
|
||||||
LoadYcds();
|
LoadYcds();
|
||||||
CreateSceneObjects();
|
await CreateSceneObjectsAsync();
|
||||||
RaiseEvents(0.0f);
|
RaiseEvents(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1164,9 +1162,9 @@ namespace CodeWalker.World
|
|||||||
int drbl = args.iDrawable;
|
int drbl = args.iDrawable;
|
||||||
int texx = args.iTexture;
|
int texx = args.iTexture;
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
cso.Ped.SetComponentDrawable(comp, drbl, 0, texx, GameFileCache);
|
await cso.Ped.SetComponentDrawableAsync(comp, drbl, 0, texx, GameFileCache);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1262,7 +1260,7 @@ namespace CodeWalker.World
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void CreateSceneObjects()
|
private async ValueTask CreateSceneObjectsAsync()
|
||||||
{
|
{
|
||||||
SceneObjects = new Dictionary<int, CutsceneObject>();
|
SceneObjects = new Dictionary<int, CutsceneObject>();
|
||||||
|
|
||||||
@ -1274,7 +1272,7 @@ namespace CodeWalker.World
|
|||||||
foreach (var obj in Objects.Values)
|
foreach (var obj in Objects.Values)
|
||||||
{
|
{
|
||||||
var sobj = new CutsceneObject();
|
var sobj = new CutsceneObject();
|
||||||
sobj.Init(obj, GameFileCache, AudioDB);
|
await sobj.InitAsync(obj, GameFileCache, AudioDB);
|
||||||
SceneObjects[sobj.ObjectID] = sobj;
|
SceneObjects[sobj.ObjectID] = sobj;
|
||||||
|
|
||||||
if (sobj.AnimHash != 0)
|
if (sobj.AnimHash != 0)
|
||||||
@ -1320,7 +1318,7 @@ namespace CodeWalker.World
|
|||||||
public bool Enabled { get; set; } = false;
|
public bool Enabled { get; set; } = false;
|
||||||
|
|
||||||
|
|
||||||
public void Init(CutObject obj, GameFileCache gfc, AudioDatabase adb)
|
public async ValueTask InitAsync(CutObject obj, GameFileCache gfc, AudioDatabase adb)
|
||||||
{
|
{
|
||||||
CutObject = obj;
|
CutObject = obj;
|
||||||
ObjectID = obj?.iObjectId ?? -1;
|
ObjectID = obj?.iObjectId ?? -1;
|
||||||
@ -1345,7 +1343,7 @@ namespace CodeWalker.World
|
|||||||
}
|
}
|
||||||
else if (obj is CutPedModelObject ped)
|
else if (obj is CutPedModelObject ped)
|
||||||
{
|
{
|
||||||
InitPed(ped, gfc);
|
await InitPedAsync(ped, gfc);
|
||||||
}
|
}
|
||||||
else if (obj is CutPropModelObject prop)
|
else if (obj is CutPropModelObject prop)
|
||||||
{
|
{
|
||||||
@ -1506,12 +1504,12 @@ namespace CodeWalker.World
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitPed(CutPedModelObject ped, GameFileCache gfc)
|
private async ValueTask InitPedAsync(CutPedModelObject ped, GameFileCache gfc)
|
||||||
{
|
{
|
||||||
|
|
||||||
Ped = new Ped();
|
Ped = new Ped();
|
||||||
Ped.Init(ped.StreamingName, gfc);
|
await Ped.InitAsync(ped.StreamingName, gfc);
|
||||||
Ped.LoadDefaultComponents(gfc);
|
await Ped.LoadDefaultComponentsAsync(gfc);
|
||||||
|
|
||||||
//if (ped.StreamingName == JenkHash.GenHash("player_zero"))
|
//if (ped.StreamingName == JenkHash.GenHash("player_zero"))
|
||||||
//{
|
//{
|
||||||
|
@ -27,7 +27,13 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
public Form Form { get { return this; } } //for DXForm/DXManager use
|
public Form Form { get { return this; } } //for DXForm/DXManager use
|
||||||
|
|
||||||
public Renderer Renderer { get; set; }
|
public Renderer Renderer {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return renderer ??= new Renderer(this, GameFileCache);
|
||||||
|
}
|
||||||
|
set => renderer = value;
|
||||||
|
}
|
||||||
public object RenderSyncRoot { get { return Renderer.RenderSyncRoot; } }
|
public object RenderSyncRoot { get { return Renderer.RenderSyncRoot; } }
|
||||||
|
|
||||||
volatile bool formopen = false;
|
volatile bool formopen = false;
|
||||||
@ -36,23 +42,31 @@ namespace CodeWalker
|
|||||||
volatile bool initialised = false;
|
volatile bool initialised = false;
|
||||||
|
|
||||||
Stopwatch frametimer = new Stopwatch();
|
Stopwatch frametimer = new Stopwatch();
|
||||||
Space space = new Space();
|
Space space;
|
||||||
Camera camera;
|
Camera camera;
|
||||||
Timecycle timecycle;
|
Timecycle timecycle;
|
||||||
Weather weather;
|
Weather weather;
|
||||||
Clouds clouds;
|
Clouds clouds;
|
||||||
Water water = new Water();
|
|
||||||
Trains trains = new Trains();
|
private Water water;
|
||||||
Scenarios scenarios = new Scenarios();
|
Water Water { get => water ??= new Water(); }
|
||||||
PopZones popzones = new PopZones();
|
private Trains trains;
|
||||||
Heightmaps heightmaps = new Heightmaps();
|
Trains Trains { get => trains ??= new Trains(); }
|
||||||
Watermaps watermaps = new Watermaps();
|
private Scenarios scenarios;
|
||||||
AudioZones audiozones = new AudioZones();
|
Scenarios Scenarios { get => scenarios ??= new Scenarios(); }
|
||||||
|
private PopZones popZones;
|
||||||
|
PopZones PopZones { get => popZones ??= new PopZones(); }
|
||||||
|
private Heightmaps heightmaps;
|
||||||
|
Heightmaps Heightmaps { get => heightmaps ??= new Heightmaps(); }
|
||||||
|
private Watermaps watermaps;
|
||||||
|
Watermaps Watermaps { get => watermaps ??= new Watermaps(); }
|
||||||
|
private AudioZones audioZones;
|
||||||
|
AudioZones AudioZones { get => audioZones ??= new AudioZones(); }
|
||||||
|
|
||||||
public CancellationTokenSource CancellationTokenSource { get; } = new CancellationTokenSource();
|
public CancellationTokenSource CancellationTokenSource { get; } = new CancellationTokenSource();
|
||||||
public CancellationToken CancellationToken;
|
public CancellationToken CancellationToken;
|
||||||
|
|
||||||
public Space Space { get { return space; } }
|
public Space Space { get => space ??= new Space(); }
|
||||||
|
|
||||||
bool MouseLButtonDown = false;
|
bool MouseLButtonDown = false;
|
||||||
bool MouseRButtonDown = false;
|
bool MouseRButtonDown = false;
|
||||||
@ -70,8 +84,9 @@ namespace CodeWalker
|
|||||||
Vector3 prevworldpos = new Vector3(0, 0, 100); //also the start pos
|
Vector3 prevworldpos = new Vector3(0, 0, 100); //also the start pos
|
||||||
|
|
||||||
|
|
||||||
public GameFileCache GameFileCache { get => gameFileCache; }
|
private GameFileCache gameFileCache;
|
||||||
GameFileCache gameFileCache = GameFileCacheFactory.GetInstance();
|
public GameFileCache GameFileCache { get => gameFileCache ??= GameFileCacheFactory.GetInstance(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
WorldControlMode ControlMode = WorldControlMode.Free;
|
WorldControlMode ControlMode = WorldControlMode.Free;
|
||||||
@ -91,8 +106,11 @@ namespace CodeWalker
|
|||||||
bool ControlBrushEnabled;
|
bool ControlBrushEnabled;
|
||||||
//float ControlBrushRadius;
|
//float ControlBrushRadius;
|
||||||
|
|
||||||
Entity camEntity = new Entity();
|
private Entity camEntity;
|
||||||
PedEntity pedEntity = new PedEntity();
|
private PedEntity pedEntity;
|
||||||
|
|
||||||
|
Entity CamEntity { get => camEntity ??= new Entity(); }
|
||||||
|
PedEntity PedEntity { get => pedEntity ??= new PedEntity(); }
|
||||||
|
|
||||||
|
|
||||||
bool iseditmode = false;
|
bool iseditmode = false;
|
||||||
@ -216,10 +234,17 @@ namespace CodeWalker
|
|||||||
|
|
||||||
public WorldForm()
|
public WorldForm()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Task.Run(() => {
|
||||||
|
if (!GameFileCache.IsInited)
|
||||||
|
{
|
||||||
|
GameFileCache.Init();
|
||||||
|
}
|
||||||
|
});
|
||||||
CancellationToken = CancellationTokenSource.Token;
|
CancellationToken = CancellationTokenSource.Token;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Renderer = new Renderer(this, gameFileCache);
|
Renderer = new Renderer(this, GameFileCache);
|
||||||
camera = Renderer.camera;
|
camera = Renderer.camera;
|
||||||
timecycle = Renderer.timecycle;
|
timecycle = Renderer.timecycle;
|
||||||
weather = Renderer.weather;
|
weather = Renderer.weather;
|
||||||
@ -228,20 +253,15 @@ namespace CodeWalker
|
|||||||
CurMouseHit.WorldForm = this;
|
CurMouseHit.WorldForm = this;
|
||||||
LastMouseHit.WorldForm = this;
|
LastMouseHit.WorldForm = this;
|
||||||
PrevMouseHit.WorldForm = this;
|
PrevMouseHit.WorldForm = this;
|
||||||
|
|
||||||
if (!gameFileCache.IsInited)
|
|
||||||
{
|
|
||||||
Task.Run(() => gameFileCache.Init());
|
|
||||||
}
|
|
||||||
|
|
||||||
initedOk = Renderer.Init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void Init()
|
private async ValueTask Init()
|
||||||
{
|
{
|
||||||
//called from WorldForm_Load
|
//called from WorldForm_Load
|
||||||
|
|
||||||
|
initedOk = Renderer.Init();
|
||||||
|
|
||||||
if (!initedOk)
|
if (!initedOk)
|
||||||
{
|
{
|
||||||
Close();
|
Close();
|
||||||
@ -365,11 +385,11 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
camera.FollowEntity = camEntity;
|
camera.FollowEntity = CamEntity;
|
||||||
camEntity.Position = (startupviewmode!=2) ? prevworldpos : Vector3.Zero;
|
CamEntity.Position = (startupviewmode!=2) ? prevworldpos : Vector3.Zero;
|
||||||
camEntity.Orientation = Quaternion.LookAtLH(Vector3.Zero, Vector3.Up, Vector3.ForwardLH);
|
CamEntity.Orientation = Quaternion.LookAtLH(Vector3.Zero, Vector3.Up, Vector3.ForwardLH);
|
||||||
|
|
||||||
space.AddPersistentEntity(pedEntity);
|
Space.AddPersistentEntity(PedEntity);
|
||||||
|
|
||||||
|
|
||||||
LoadSettings();
|
LoadSettings();
|
||||||
@ -413,11 +433,10 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
Renderer.BuffersResized(w, h);
|
Renderer.BuffersResized(w, h);
|
||||||
|
|
||||||
if (WindowState == FormWindowState.Minimized && gameFileCache.IsInited)
|
if (WindowState == FormWindowState.Minimized && GameFileCache.IsInited)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Clearing cache");
|
Console.WriteLine("Clearing cache");
|
||||||
gameFileCache.Clear();
|
GameFileCache.Clear();
|
||||||
gameFileCache.IsInited = true;
|
|
||||||
//GC.Collect();
|
//GC.Collect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -445,7 +464,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
UpdateControlInputs(elapsed);
|
UpdateControlInputs(elapsed);
|
||||||
|
|
||||||
space.Update(elapsed);
|
Space.Update(elapsed);
|
||||||
|
|
||||||
if (CutsceneForm != null)
|
if (CutsceneForm != null)
|
||||||
{
|
{
|
||||||
@ -597,7 +616,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
Vector3 movewvec = camera.ViewInvQuaternion.Multiply(movevec);
|
Vector3 movewvec = camera.ViewInvQuaternion.Multiply(movevec);
|
||||||
camEntity.Position += movewvec;
|
CamEntity.Position += movewvec;
|
||||||
|
|
||||||
MapViewDragX = 0;
|
MapViewDragX = 0;
|
||||||
MapViewDragY = 0;
|
MapViewDragY = 0;
|
||||||
@ -682,9 +701,9 @@ namespace CodeWalker
|
|||||||
|
|
||||||
movexy *= (1.0f + (Math.Min(Math.Max(Input.xblt, 0.0f), 1.0f) * 15.0f)); //boost with left trigger
|
movexy *= (1.0f + (Math.Min(Math.Max(Input.xblt, 0.0f), 1.0f) * 15.0f)); //boost with left trigger
|
||||||
|
|
||||||
pedEntity.ControlMovement = movexy;
|
PedEntity.ControlMovement = movexy;
|
||||||
pedEntity.ControlJump = Input.kbjump || Input.ControllerButtonPressed(GamepadButtonFlags.X);
|
PedEntity.ControlJump = Input.kbjump || Input.ControllerButtonPressed(GamepadButtonFlags.X);
|
||||||
pedEntity.ControlBoost = Input.ShiftPressed || Input.ControllerButtonPressed(GamepadButtonFlags.A | GamepadButtonFlags.RightShoulder | GamepadButtonFlags.LeftShoulder);
|
PedEntity.ControlBoost = Input.ShiftPressed || Input.ControllerButtonPressed(GamepadButtonFlags.A | GamepadButtonFlags.RightShoulder | GamepadButtonFlags.LeftShoulder);
|
||||||
|
|
||||||
|
|
||||||
//Vector3 pedfwd = pedEntity.Orientation.Multiply(Vector3.UnitZ);
|
//Vector3 pedfwd = pedEntity.Orientation.Multiply(Vector3.UnitZ);
|
||||||
@ -725,9 +744,9 @@ namespace CodeWalker
|
|||||||
|
|
||||||
if (renderworld)
|
if (renderworld)
|
||||||
{
|
{
|
||||||
space.GetVisibleYmaps(camera, hour, weathertype, renderworldVisibleYmapDict);
|
Space.GetVisibleYmaps(camera, hour, weathertype, renderworldVisibleYmapDict);
|
||||||
|
|
||||||
spaceEnts = space.TemporaryEntities;
|
spaceEnts = Space.TemporaryEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ProjectForm != null)
|
if (ProjectForm != null)
|
||||||
@ -808,12 +827,12 @@ namespace CodeWalker
|
|||||||
//enqueue collision meshes for rendering - from the world grid
|
//enqueue collision meshes for rendering - from the world grid
|
||||||
|
|
||||||
collisionitems.Clear();
|
collisionitems.Clear();
|
||||||
space.GetVisibleBounds(camera, collisionmeshrange, collisionmeshlayers, collisionitems);
|
Space.GetVisibleBounds(camera, collisionmeshrange, collisionmeshlayers, collisionitems);
|
||||||
|
|
||||||
collisionybns.Clear();
|
collisionybns.Clear();
|
||||||
foreach (var item in collisionitems)
|
foreach (var item in collisionitems)
|
||||||
{
|
{
|
||||||
YbnFile ybn = gameFileCache.GetYbn(item.Name);
|
YbnFile ybn = GameFileCache.GetYbn(item.Name);
|
||||||
if ((ybn != null) && (ybn.Loaded))
|
if ((ybn != null) && (ybn.Loaded))
|
||||||
{
|
{
|
||||||
collisionybns.Add(ybn);
|
collisionybns.Add(ybn);
|
||||||
@ -825,7 +844,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
if (mlo.Archetype == null) return;
|
if (mlo.Archetype == null) return;
|
||||||
var hash = mlo.Archetype.Hash;
|
var hash = mlo.Archetype.Hash;
|
||||||
YbnFile ybn = gameFileCache.GetYbn(hash);
|
YbnFile ybn = GameFileCache.GetYbn(hash);
|
||||||
if ((ybn != null) && (ybn.Loaded))
|
if ((ybn != null) && (ybn.Loaded))
|
||||||
{
|
{
|
||||||
collisioninteriors[mlo] = ybn;
|
collisioninteriors[mlo] = ybn;
|
||||||
@ -858,17 +877,17 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void RenderWorldWaterQuads()
|
private void RenderWorldWaterQuads()
|
||||||
{
|
{
|
||||||
var quads = RenderWorldBaseWaterQuads(water.WaterQuads, MapSelectionMode.WaterQuad);
|
var quads = RenderWorldBaseWaterQuads(Water.WaterQuads, MapSelectionMode.WaterQuad);
|
||||||
Renderer.RenderWaterQuads(quads);
|
Renderer.RenderWaterQuads(quads);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderWorldWaterCalmingQuads() => RenderWorldBaseWaterQuads(water.CalmingQuads, MapSelectionMode.CalmingQuad);
|
private void RenderWorldWaterCalmingQuads() => RenderWorldBaseWaterQuads(Water.CalmingQuads, MapSelectionMode.CalmingQuad);
|
||||||
|
|
||||||
private void RenderWorldWaterWaveQuads() => RenderWorldBaseWaterQuads(water.WaveQuads, MapSelectionMode.WaveQuad);
|
private void RenderWorldWaterWaveQuads() => RenderWorldBaseWaterQuads(Water.WaveQuads, MapSelectionMode.WaveQuad);
|
||||||
|
|
||||||
private List<T> RenderWorldBaseWaterQuads<T>(IEnumerable<T> quads, MapSelectionMode requiredMode) where T : BaseWaterQuad
|
private List<T> RenderWorldBaseWaterQuads<T>(IEnumerable<T> quads, MapSelectionMode requiredMode) where T : BaseWaterQuad
|
||||||
{
|
{
|
||||||
List<T> renderwaterquadlist = water.GetVisibleQuads<T>(camera, quads);
|
List<T> renderwaterquadlist = Water.GetVisibleQuads<T>(camera, quads);
|
||||||
|
|
||||||
ProjectForm?.GetVisibleWaterQuads<T>(camera, renderwaterquadlist);
|
ProjectForm?.GetVisibleWaterQuads<T>(camera, renderwaterquadlist);
|
||||||
|
|
||||||
@ -881,7 +900,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
renderpathynds.Clear();
|
renderpathynds.Clear();
|
||||||
|
|
||||||
space.GetVisibleYnds(camera, renderpathynds);
|
Space.GetVisibleYnds(camera, renderpathynds);
|
||||||
|
|
||||||
if (ProjectForm != null)
|
if (ProjectForm != null)
|
||||||
{
|
{
|
||||||
@ -895,10 +914,10 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void RenderWorldTrainTracks()
|
private void RenderWorldTrainTracks()
|
||||||
{
|
{
|
||||||
if (!trains.Inited) return;
|
if (!Trains.Inited) return;
|
||||||
|
|
||||||
rendertraintracklist.Clear();
|
rendertraintracklist.Clear();
|
||||||
rendertraintracklist.AddRange(trains.TrainTracks);
|
rendertraintracklist.AddRange(Trains.TrainTracks);
|
||||||
|
|
||||||
if (ProjectForm != null)
|
if (ProjectForm != null)
|
||||||
{
|
{
|
||||||
@ -914,7 +933,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
|
|
||||||
rendernavmeshynvs.Clear();
|
rendernavmeshynvs.Clear();
|
||||||
space.GetVisibleYnvs(camera, collisionmeshrange, rendernavmeshynvs);
|
Space.GetVisibleYnvs(camera, collisionmeshrange, rendernavmeshynvs);
|
||||||
|
|
||||||
if (ProjectForm != null)
|
if (ProjectForm != null)
|
||||||
{
|
{
|
||||||
@ -930,10 +949,10 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void RenderWorldScenarios()
|
private void RenderWorldScenarios()
|
||||||
{
|
{
|
||||||
if (!scenarios.Inited) return;
|
if (!Scenarios.Inited) return;
|
||||||
|
|
||||||
renderscenariolist.Clear();
|
renderscenariolist.Clear();
|
||||||
renderscenariolist.AddRange(scenarios.ScenarioRegions);
|
renderscenariolist.AddRange(Scenarios.ScenarioRegions);
|
||||||
|
|
||||||
if (ProjectForm != null)
|
if (ProjectForm != null)
|
||||||
{
|
{
|
||||||
@ -947,7 +966,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void RenderWorldPopZones()
|
private void RenderWorldPopZones()
|
||||||
{
|
{
|
||||||
if (!popzones.Inited) return;
|
if (!PopZones.Inited) return;
|
||||||
|
|
||||||
//renderpopzonelist.Clear();
|
//renderpopzonelist.Clear();
|
||||||
//renderpopzonelist.AddRange(popzones.Groups.Values);
|
//renderpopzonelist.AddRange(popzones.Groups.Values);
|
||||||
@ -957,12 +976,12 @@ namespace CodeWalker
|
|||||||
//ProjectForm.GetVisiblePopZones(camera, renderpopzonelist);
|
//ProjectForm.GetVisiblePopZones(camera, renderpopzonelist);
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer.RenderPopZones(popzones);
|
Renderer.RenderPopZones(PopZones);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderWorldHeightmaps()
|
private void RenderWorldHeightmaps()
|
||||||
{
|
{
|
||||||
if (!heightmaps.Inited) return;
|
if (!Heightmaps.Inited) return;
|
||||||
|
|
||||||
//renderheightmaplist.Clear();
|
//renderheightmaplist.Clear();
|
||||||
//renderheightmaplist.AddRange(heightmaps.Heightmaps);
|
//renderheightmaplist.AddRange(heightmaps.Heightmaps);
|
||||||
@ -972,12 +991,12 @@ namespace CodeWalker
|
|||||||
//ProjectForm.GetVisibleHeightmaps(camera, renderheightmaplist);
|
//ProjectForm.GetVisibleHeightmaps(camera, renderheightmaplist);
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer.RenderBasePath(heightmaps);
|
Renderer.RenderBasePath(Heightmaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderWorldWatermaps()
|
private void RenderWorldWatermaps()
|
||||||
{
|
{
|
||||||
if (!watermaps.Inited) return;
|
if (!Watermaps.Inited) return;
|
||||||
|
|
||||||
//renderwatermaplist.Clear();
|
//renderwatermaplist.Clear();
|
||||||
//renderwatermaplist.AddRange(watermaps.Watermaps);
|
//renderwatermaplist.AddRange(watermaps.Watermaps);
|
||||||
@ -987,12 +1006,12 @@ namespace CodeWalker
|
|||||||
//ProjectForm.GetVisibleWatermaps(camera, renderwatermaplist);
|
//ProjectForm.GetVisibleWatermaps(camera, renderwatermaplist);
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer.RenderBasePath(watermaps);
|
Renderer.RenderBasePath(Watermaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderWorldAudioZones()
|
private void RenderWorldAudioZones()
|
||||||
{
|
{
|
||||||
if (!audiozones.Inited) return;
|
if (!AudioZones.Inited) return;
|
||||||
|
|
||||||
renderaudfilelist.Clear();
|
renderaudfilelist.Clear();
|
||||||
renderaudfilelist.AddRange(GameFileCache.AudioDatRelFiles);
|
renderaudfilelist.AddRange(GameFileCache.AudioDatRelFiles);
|
||||||
@ -1003,7 +1022,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderaudplacementslist.Clear();
|
renderaudplacementslist.Clear();
|
||||||
audiozones.GetPlacements(renderaudfilelist, renderaudplacementslist);
|
AudioZones.GetPlacements(renderaudfilelist, renderaudplacementslist);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1125,7 +1144,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
hash = JenkHash.GenHash(modelname);
|
hash = JenkHash.GenHash(modelname);
|
||||||
}
|
}
|
||||||
Archetype arche = gameFileCache.GetArchetype(hash);
|
Archetype arche = GameFileCache.GetArchetype(hash);
|
||||||
|
|
||||||
Archetype selarch = null;
|
Archetype selarch = null;
|
||||||
DrawableBase seldrwbl = null;
|
DrawableBase seldrwbl = null;
|
||||||
@ -1139,7 +1158,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
YmapFile ymap = gameFileCache.GetYmap(hash);
|
YmapFile ymap = GameFileCache.GetYmap(hash);
|
||||||
if (ymap != null)
|
if (ymap != null)
|
||||||
{
|
{
|
||||||
Renderer.RenderYmap(ymap);
|
Renderer.RenderYmap(ymap);
|
||||||
@ -1147,7 +1166,7 @@ namespace CodeWalker
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
//not a ymap... see if it's a ydr or yft
|
//not a ymap... see if it's a ydr or yft
|
||||||
YdrFile ydr = gameFileCache.GetYdr(hash);
|
YdrFile ydr = GameFileCache.GetYdr(hash);
|
||||||
if (ydr != null)
|
if (ydr != null)
|
||||||
{
|
{
|
||||||
if (ydr.Loaded)
|
if (ydr.Loaded)
|
||||||
@ -1159,7 +1178,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
YftFile yft = gameFileCache.GetYft(hash);
|
YftFile yft = GameFileCache.GetYft(hash);
|
||||||
if (yft != null)
|
if (yft != null)
|
||||||
{
|
{
|
||||||
if (yft.Loaded)
|
if (yft.Loaded)
|
||||||
@ -1186,7 +1205,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
if ((selarch != null) && (seldrwbl == null))
|
if ((selarch != null) && (seldrwbl == null))
|
||||||
{
|
{
|
||||||
seldrwbl = gameFileCache.TryGetDrawable(selarch);
|
seldrwbl = GameFileCache.TryGetDrawable(selarch);
|
||||||
}
|
}
|
||||||
|
|
||||||
//select this item for viewing by the UI...
|
//select this item for viewing by the UI...
|
||||||
@ -1209,7 +1228,7 @@ namespace CodeWalker
|
|||||||
foreach (string lod in ymaplist)
|
foreach (string lod in ymaplist)
|
||||||
{
|
{
|
||||||
uint hash = JenkHash.GenHash(lod);
|
uint hash = JenkHash.GenHash(lod);
|
||||||
YmapFile ymap = gameFileCache.GetYmap(hash);
|
YmapFile ymap = GameFileCache.GetYmap(hash);
|
||||||
Renderer.RenderYmap(ymap);
|
Renderer.RenderYmap(ymap);
|
||||||
|
|
||||||
UpdateMouseHits(ymap);
|
UpdateMouseHits(ymap);
|
||||||
@ -1763,13 +1782,13 @@ namespace CodeWalker
|
|||||||
float downlimit = 20.0f;
|
float downlimit = 20.0f;
|
||||||
Ray ray = new Ray(p, new Vector3(0, 0, -1.0f));
|
Ray ray = new Ray(p, new Vector3(0, 0, -1.0f));
|
||||||
ray.Position.Z += 0.1f;
|
ray.Position.Z += 0.1f;
|
||||||
SpaceRayIntersectResult hit = space.RayIntersect(ray, downlimit);
|
SpaceRayIntersectResult hit = Space.RayIntersect(ray, downlimit);
|
||||||
if (hit.Hit)
|
if (hit.Hit)
|
||||||
{
|
{
|
||||||
return hit.Position;
|
return hit.Position;
|
||||||
}
|
}
|
||||||
ray.Position.Z += uplimit;
|
ray.Position.Z += uplimit;
|
||||||
hit = space.RayIntersect(ray, downlimit);
|
hit = Space.RayIntersect(ray, downlimit);
|
||||||
if (hit.Hit)
|
if (hit.Hit)
|
||||||
{
|
{
|
||||||
return hit.Position;
|
return hit.Position;
|
||||||
@ -1928,12 +1947,12 @@ namespace CodeWalker
|
|||||||
ynd.UpdateAllNodePositions();
|
ynd.UpdateAllNodePositions();
|
||||||
ynd.BuildBVH();
|
ynd.BuildBVH();
|
||||||
|
|
||||||
space.BuildYndData(ynd);
|
Space.BuildYndData(ynd);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ynd.UpdateAllNodePositions();
|
ynd.UpdateAllNodePositions();
|
||||||
space.BuildYndVerts(ynd, selection);
|
Space.BuildYndVerts(ynd, selection);
|
||||||
}
|
}
|
||||||
//lock (Renderer.RenderSyncRoot)
|
//lock (Renderer.RenderSyncRoot)
|
||||||
{
|
{
|
||||||
@ -1948,7 +1967,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
public YndNode GetPathNodeFromSpace(ushort areaid, ushort nodeid)
|
public YndNode GetPathNodeFromSpace(ushort areaid, ushort nodeid)
|
||||||
{
|
{
|
||||||
return space.NodeGrid.GetYndNode(areaid, nodeid);
|
return Space.NodeGrid.GetYndNode(areaid, nodeid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateCollisionBoundsGraphics(Bounds b)
|
public void UpdateCollisionBoundsGraphics(Bounds b)
|
||||||
@ -2080,7 +2099,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
public void UpdateAudioPlacementGraphics(RelFile rel)
|
public void UpdateAudioPlacementGraphics(RelFile rel)
|
||||||
{
|
{
|
||||||
audiozones.PlacementsDict.Remove(rel); //should cause a rebuild to add/remove items
|
AudioZones.PlacementsDict.Remove(rel); //should cause a rebuild to add/remove items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2136,12 +2155,12 @@ namespace CodeWalker
|
|||||||
|
|
||||||
public void SetKeyBindings(KeyBindings kb)
|
public void SetKeyBindings(KeyBindings kb)
|
||||||
{
|
{
|
||||||
Input.keyBindings = kb.Copy();
|
Input.KeyBindings = kb.Copy();
|
||||||
UpdateToolbarShortcutsText();
|
UpdateToolbarShortcutsText();
|
||||||
}
|
}
|
||||||
private void UpdateToolbarShortcutsText()
|
private void UpdateToolbarShortcutsText()
|
||||||
{
|
{
|
||||||
var kb = Input.keyBindings;
|
var kb = Input.KeyBindings;
|
||||||
ToolbarSelectButton.ToolTipText = string.Format("Select objects / Exit edit mode ({0}, {1})", kb.ToggleMouseSelect, kb.ExitEditMode);
|
ToolbarSelectButton.ToolTipText = string.Format("Select objects / Exit edit mode ({0}, {1})", kb.ToggleMouseSelect, kb.ExitEditMode);
|
||||||
ToolbarMoveButton.ToolTipText = string.Format("Move ({0})", kb.EditPosition);
|
ToolbarMoveButton.ToolTipText = string.Format("Move ({0})", kb.EditPosition);
|
||||||
ToolbarRotateButton.ToolTipText = string.Format("Rotate ({0})", kb.EditRotation);
|
ToolbarRotateButton.ToolTipText = string.Format("Rotate ({0})", kb.EditRotation);
|
||||||
@ -2246,7 +2265,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void SpawnTestEntity(bool cameraCenter = false)
|
private void SpawnTestEntity(bool cameraCenter = false)
|
||||||
{
|
{
|
||||||
if (!space.Inited) return;
|
if (!Space.Inited) return;
|
||||||
|
|
||||||
Vector3 dir = (cameraCenter ? camera.ViewDirection : camera.MouseRay.Direction);
|
Vector3 dir = (cameraCenter ? camera.ViewDirection : camera.MouseRay.Direction);
|
||||||
Vector3 ofs = (cameraCenter ? Vector3.Zero : camera.MouseRay.Position);
|
Vector3 ofs = (cameraCenter ? Vector3.Zero : camera.MouseRay.Position);
|
||||||
@ -2290,7 +2309,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
lock (Renderer.RenderSyncRoot)
|
lock (Renderer.RenderSyncRoot)
|
||||||
{
|
{
|
||||||
space.AddTemporaryEntity(e);
|
Space.AddTemporaryEntity(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2318,13 +2337,13 @@ namespace CodeWalker
|
|||||||
|
|
||||||
if (isfree && !wasfree)
|
if (isfree && !wasfree)
|
||||||
{
|
{
|
||||||
camEntity.Position = pedEntity.Position;
|
CamEntity.Position = PedEntity.Position;
|
||||||
|
|
||||||
pedEntity.Enabled = false;
|
PedEntity.Enabled = false;
|
||||||
|
|
||||||
Renderer.timerunning = false;
|
Renderer.timerunning = false;
|
||||||
|
|
||||||
camera.SetFollowEntity(camEntity);
|
camera.SetFollowEntity(CamEntity);
|
||||||
camera.TargetDistance = 1.0f; //default?
|
camera.TargetDistance = 1.0f; //default?
|
||||||
camera.Smoothness = Settings.Default.CameraSmoothing;
|
camera.Smoothness = Settings.Default.CameraSmoothing;
|
||||||
|
|
||||||
@ -2332,13 +2351,13 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
else if (!isfree && wasfree)
|
else if (!isfree && wasfree)
|
||||||
{
|
{
|
||||||
pedEntity.Position = camEntity.Position;
|
PedEntity.Position = CamEntity.Position;
|
||||||
pedEntity.Velocity = Vector3.Zero;
|
PedEntity.Velocity = Vector3.Zero;
|
||||||
pedEntity.Enabled = true;
|
PedEntity.Enabled = true;
|
||||||
|
|
||||||
Renderer.timerunning = true;
|
Renderer.timerunning = true;
|
||||||
|
|
||||||
camera.SetFollowEntity(pedEntity.CameraEntity);
|
camera.SetFollowEntity(PedEntity.CameraEntity);
|
||||||
camera.TargetDistance = 0.01f; //1cm
|
camera.TargetDistance = 0.01f; //1cm
|
||||||
camera.Smoothness = 20.0f;
|
camera.Smoothness = 20.0f;
|
||||||
|
|
||||||
@ -2403,19 +2422,19 @@ namespace CodeWalker
|
|||||||
public SpaceRayIntersectResult GetSpaceMouseRay()
|
public SpaceRayIntersectResult GetSpaceMouseRay()
|
||||||
{
|
{
|
||||||
SpaceRayIntersectResult ret = new SpaceRayIntersectResult();
|
SpaceRayIntersectResult ret = new SpaceRayIntersectResult();
|
||||||
if (space.Inited && space.BoundsStore != null)
|
if (Space.Inited && Space.BoundsStore != null)
|
||||||
{
|
{
|
||||||
Ray mray = new Ray();
|
Ray mray = new Ray();
|
||||||
mray.Position = camera.MouseRay.Position + camera.Position;
|
mray.Position = camera.MouseRay.Position + camera.Position;
|
||||||
mray.Direction = camera.MouseRay.Direction;
|
mray.Direction = camera.MouseRay.Direction;
|
||||||
return space.RayIntersect(mray, float.MaxValue, collisionmeshlayers);
|
return Space.RayIntersect(mray, float.MaxValue, collisionmeshlayers);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpaceRayIntersectResult Raycast(Ray ray)
|
public SpaceRayIntersectResult Raycast(Ray ray)
|
||||||
{
|
{
|
||||||
return space.RayIntersect(ray, float.MaxValue, collisionmeshlayers);
|
return Space.RayIntersect(ray, float.MaxValue, collisionmeshlayers);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateMouseHits()
|
private void UpdateMouseHits()
|
||||||
@ -3503,7 +3522,7 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
if ((mhitv.Archetype != null) && (mhitv.Drawable == null))
|
if ((mhitv.Archetype != null) && (mhitv.Drawable == null))
|
||||||
{
|
{
|
||||||
mhitv.Drawable = gameFileCache.TryGetDrawable(mhitv.Archetype); //no drawable given.. try to get it from the cache.. if it's not there, drawable info won't display...
|
mhitv.Drawable = GameFileCache.TryGetDrawable(mhitv.Archetype); //no drawable given.. try to get it from the cache.. if it's not there, drawable info won't display...
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldnode = SelectedItem.PathNode;
|
var oldnode = SelectedItem.PathNode;
|
||||||
@ -4212,43 +4231,43 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
|
|
||||||
UpdateStatus("Loading timecycles...");
|
UpdateStatus("Loading timecycles...");
|
||||||
timecycle.Init(gameFileCache, UpdateStatus);
|
timecycle.Init(GameFileCache, UpdateStatus);
|
||||||
timecycle.SetTime(Renderer.timeofday);
|
timecycle.SetTime(Renderer.timeofday);
|
||||||
|
|
||||||
UpdateStatus("Loading materials...");
|
UpdateStatus("Loading materials...");
|
||||||
BoundsMaterialTypes.Init(gameFileCache);
|
BoundsMaterialTypes.Init(GameFileCache);
|
||||||
|
|
||||||
UpdateStatus("Loading weather...");
|
UpdateStatus("Loading weather...");
|
||||||
weather.Init(gameFileCache, UpdateStatus, timecycle);
|
weather.Init(GameFileCache, UpdateStatus, timecycle);
|
||||||
UpdateWeatherTypesComboBox(weather);
|
UpdateWeatherTypesComboBox(weather);
|
||||||
|
|
||||||
UpdateStatus("Loading clouds...");
|
UpdateStatus("Loading clouds...");
|
||||||
clouds.Init(gameFileCache, UpdateStatus, weather);
|
clouds.Init(GameFileCache, UpdateStatus, weather);
|
||||||
UpdateCloudTypesComboBox(clouds);
|
UpdateCloudTypesComboBox(clouds);
|
||||||
|
|
||||||
UpdateStatus("Loading water...");
|
UpdateStatus("Loading water...");
|
||||||
water.Init(gameFileCache, UpdateStatus);
|
Water.Init(GameFileCache, UpdateStatus);
|
||||||
|
|
||||||
UpdateStatus("Loading trains...");
|
UpdateStatus("Loading trains...");
|
||||||
trains.Init(gameFileCache, UpdateStatus);
|
Trains.Init(GameFileCache, UpdateStatus);
|
||||||
|
|
||||||
UpdateStatus("Loading scenarios...");
|
UpdateStatus("Loading scenarios...");
|
||||||
scenarios.Init(gameFileCache, UpdateStatus, timecycle);
|
Scenarios.Init(GameFileCache, UpdateStatus, timecycle);
|
||||||
|
|
||||||
UpdateStatus("Loading popzones...");
|
UpdateStatus("Loading popzones...");
|
||||||
popzones.Init(gameFileCache, UpdateStatus);
|
PopZones.Init(GameFileCache, UpdateStatus);
|
||||||
|
|
||||||
UpdateStatus("Loading heightmaps...");
|
UpdateStatus("Loading heightmaps...");
|
||||||
heightmaps.Init(gameFileCache, UpdateStatus);
|
Heightmaps.Init(GameFileCache, UpdateStatus);
|
||||||
|
|
||||||
UpdateStatus("Loading watermaps...");
|
UpdateStatus("Loading watermaps...");
|
||||||
watermaps.Init(gameFileCache, UpdateStatus);
|
Watermaps.Init(GameFileCache, UpdateStatus);
|
||||||
|
|
||||||
UpdateStatus("Loading audio zones...");
|
UpdateStatus("Loading audio zones...");
|
||||||
audiozones.Init(gameFileCache, UpdateStatus);
|
AudioZones.Init(GameFileCache, UpdateStatus);
|
||||||
|
|
||||||
UpdateStatus("Loading world...");
|
UpdateStatus("Loading world...");
|
||||||
space.Init(gameFileCache, UpdateStatus);
|
Space.Init(GameFileCache, UpdateStatus);
|
||||||
|
|
||||||
UpdateStatus("World loaded");
|
UpdateStatus("World loaded");
|
||||||
|
|
||||||
@ -4264,7 +4283,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
lock (Renderer.RenderSyncRoot)
|
lock (Renderer.RenderSyncRoot)
|
||||||
{
|
{
|
||||||
if (gameFileCache.SetDlcLevel(dlc, enable))
|
if (GameFileCache.SetDlcLevel(dlc, enable))
|
||||||
{
|
{
|
||||||
LoadWorld();
|
LoadWorld();
|
||||||
}
|
}
|
||||||
@ -4283,9 +4302,9 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
lock (Renderer.RenderSyncRoot)
|
lock (Renderer.RenderSyncRoot)
|
||||||
{
|
{
|
||||||
if (gameFileCache.SetModsEnabled(enable))
|
if (GameFileCache.SetModsEnabled(enable))
|
||||||
{
|
{
|
||||||
UpdateDlcListComboBox(gameFileCache.DlcNameList);
|
UpdateDlcListComboBox(GameFileCache.DlcNameList);
|
||||||
|
|
||||||
LoadWorld();
|
LoadWorld();
|
||||||
}
|
}
|
||||||
@ -4326,18 +4345,18 @@ namespace CodeWalker
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gameFileCache.UpdateStatus += UpdateStatus;
|
GameFileCache.UpdateStatus += UpdateStatus;
|
||||||
gameFileCache.ErrorLog += LogError;
|
GameFileCache.ErrorLog += LogError;
|
||||||
while (gameFileCache.IsIniting)
|
while (GameFileCache.IsIniting)
|
||||||
{
|
{
|
||||||
await Task.Delay(0);
|
await Task.Delay(0);
|
||||||
}
|
}
|
||||||
if (!gameFileCache.IsInited)
|
if (!GameFileCache.IsInited)
|
||||||
{
|
{
|
||||||
gameFileCache.Init();
|
GameFileCache.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateDlcListComboBox(gameFileCache.DlcNameList);
|
UpdateDlcListComboBox(GameFileCache.DlcNameList);
|
||||||
|
|
||||||
EnableCacheDependentUI();
|
EnableCacheDependentUI();
|
||||||
|
|
||||||
@ -4351,7 +4370,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
EnableDLCModsUI();
|
EnableDLCModsUI();
|
||||||
|
|
||||||
Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -4373,13 +4392,13 @@ namespace CodeWalker
|
|||||||
Console.WriteLine("Renderer ContentThread stopped");
|
Console.WriteLine("Renderer ContentThread stopped");
|
||||||
});
|
});
|
||||||
|
|
||||||
Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (formopen && !IsDisposed && !CancellationToken.IsCancellationRequested) //main asset loop
|
while (formopen && !IsDisposed && !CancellationToken.IsCancellationRequested) //main asset loop
|
||||||
{
|
{
|
||||||
bool fcItemsPending = gameFileCache.ContentThreadProc();
|
bool fcItemsPending = GameFileCache.ContentThreadProc();
|
||||||
|
|
||||||
if (!fcItemsPending)
|
if (!fcItemsPending)
|
||||||
{
|
{
|
||||||
@ -4413,6 +4432,8 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private Stopwatch lastStatusUpdate = Stopwatch.StartNew();
|
private Stopwatch lastStatusUpdate = Stopwatch.StartNew();
|
||||||
private TimeSpan updateInterval = TimeSpan.FromSeconds(0.05);
|
private TimeSpan updateInterval = TimeSpan.FromSeconds(0.05);
|
||||||
|
private Renderer renderer;
|
||||||
|
|
||||||
private void UpdateStatus(string text)
|
private void UpdateStatus(string text)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -4527,13 +4548,13 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
DlcLevelComboBox.Items.Add(dlcname);
|
DlcLevelComboBox.Items.Add(dlcname);
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(gameFileCache.SelectedDlc))
|
if (string.IsNullOrEmpty(GameFileCache.SelectedDlc))
|
||||||
{
|
{
|
||||||
DlcLevelComboBox.SelectedIndex = dlcnames.Count - 1;
|
DlcLevelComboBox.SelectedIndex = dlcnames.Count - 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int idx = DlcLevelComboBox.FindString(gameFileCache.SelectedDlc);
|
int idx = DlcLevelComboBox.FindString(GameFileCache.SelectedDlc);
|
||||||
DlcLevelComboBox.SelectedIndex = (idx > 0) ? idx : (dlcnames.Count - 1);
|
DlcLevelComboBox.SelectedIndex = (idx > 0) ? idx : (dlcnames.Count - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4806,7 +4827,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
EnableModsCheckBox.Checked = s.EnableMods;
|
EnableModsCheckBox.Checked = s.EnableMods;
|
||||||
DlcLevelComboBox.Text = s.DLC;
|
DlcLevelComboBox.Text = s.DLC;
|
||||||
gameFileCache.SelectedDlc = s.DLC;
|
GameFileCache.SelectedDlc = s.DLC;
|
||||||
EnableDlcCheckBox.Checked = !string.IsNullOrEmpty(s.DLC);
|
EnableDlcCheckBox.Checked = !string.IsNullOrEmpty(s.DLC);
|
||||||
}
|
}
|
||||||
private void SaveSettings()
|
private void SaveSettings()
|
||||||
@ -4849,8 +4870,8 @@ namespace CodeWalker
|
|||||||
s.Clouds = CloudsComboBox.Text;
|
s.Clouds = CloudsComboBox.Text;
|
||||||
|
|
||||||
//additional settings from gamefilecache...
|
//additional settings from gamefilecache...
|
||||||
s.EnableMods = gameFileCache.EnableMods;
|
s.EnableMods = GameFileCache.EnableMods;
|
||||||
s.DLC = gameFileCache.EnableDlc ? gameFileCache.SelectedDlc : "";
|
s.DLC = GameFileCache.EnableDlc ? GameFileCache.SelectedDlc : "";
|
||||||
|
|
||||||
s.Save();
|
s.Save();
|
||||||
}
|
}
|
||||||
@ -6045,9 +6066,10 @@ namespace CodeWalker
|
|||||||
CameraPositionTextBox.Text = FloatUtil.GetVector3StringFormat(camera.Position, "0.##");
|
CameraPositionTextBox.Text = FloatUtil.GetVector3StringFormat(camera.Position, "0.##");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WorldForm_Load(object sender, EventArgs e)
|
private bool isRenderedLoaded = false;
|
||||||
|
private async void WorldForm_Load(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Init();
|
await Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WorldForm_FormClosing(object sender, FormClosingEventArgs e)
|
private void WorldForm_FormClosing(object sender, FormClosingEventArgs e)
|
||||||
@ -6379,7 +6401,7 @@ namespace CodeWalker
|
|||||||
Input.KeyDown(e, enablemove);
|
Input.KeyDown(e, enablemove);
|
||||||
|
|
||||||
var k = e.KeyCode;
|
var k = e.KeyCode;
|
||||||
var kb = Input.keyBindings;
|
var kb = Input.KeyBindings;
|
||||||
bool ctrl = Input.CtrlPressed;
|
bool ctrl = Input.CtrlPressed;
|
||||||
bool shift = Input.ShiftPressed;
|
bool shift = Input.ShiftPressed;
|
||||||
|
|
||||||
@ -6977,7 +6999,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void ToolsMenuAudioExplorer_Click(object sender, EventArgs e)
|
private void ToolsMenuAudioExplorer_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
AudioExplorerForm f = new AudioExplorerForm(gameFileCache);
|
AudioExplorerForm f = new AudioExplorerForm();
|
||||||
f.Show(this);
|
f.Show(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6988,7 +7010,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void ToolsMenuBinarySearch_Click(object sender, EventArgs e)
|
private void ToolsMenuBinarySearch_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
BinarySearchForm f = new BinarySearchForm(gameFileCache);
|
BinarySearchForm f = new BinarySearchForm();
|
||||||
f.Show(this);
|
f.Show(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7000,7 +7022,7 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void ToolsMenuJenkInd_Click(object sender, EventArgs e)
|
private void ToolsMenuJenkInd_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
JenkIndForm f = new JenkIndForm(gameFileCache);
|
JenkIndForm f = new JenkIndForm();
|
||||||
f.Show();
|
f.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7934,6 +7956,10 @@ namespace CodeWalker
|
|||||||
|
|
||||||
private void AntiAliasingTrackBar_ValueChanged(object sender, EventArgs e)
|
private void AntiAliasingTrackBar_ValueChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (AntiAliasingTrackBar.Value == Settings.Default.AntiAliasing)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
Settings.Default.AntiAliasing = AntiAliasingTrackBar.Value;
|
Settings.Default.AntiAliasing = AntiAliasingTrackBar.Value;
|
||||||
Settings.Default.Save();
|
Settings.Default.Save();
|
||||||
AntiAliasingValue.Text = Settings.Default.AntiAliasing.ToString();
|
AntiAliasingValue.Text = Settings.Default.AntiAliasing.ToString();
|
||||||
|
Loading…
Reference in New Issue
Block a user