mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-16 20:17:30 +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.Environments;
|
||||
using BenchmarkDotNet.Jobs;
|
||||
using CodeWalker.Core.Utils;
|
||||
using CodeWalker.GameFiles;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace CodeWalker.Benchmarks
|
||||
{
|
||||
[MemoryDiagnoser]
|
||||
[Config(typeof(JitsConfig))]
|
||||
public class Benchmarks
|
||||
{
|
||||
private class JitsConfig : ManualConfig
|
||||
{
|
||||
public JitsConfig()
|
||||
{
|
||||
AddJob(Job.Default.WithJit(Jit.RyuJit).WithPlatform(Platform.X64));
|
||||
}
|
||||
}
|
||||
public static string markup = @"<CVehicleModelInfo__InitDataList>
|
||||
public const string markup = @"<CVehicleModelInfo__InitDataList>
|
||||
<residentTxd>vehshare</residentTxd>
|
||||
<residentAnims />
|
||||
<InitDatas>
|
||||
@ -179,22 +177,39 @@ namespace CodeWalker.Benchmarks
|
||||
[GlobalSetup]
|
||||
public void Setup()
|
||||
{
|
||||
data = Encoding.UTF8.GetBytes(markup);
|
||||
fileEntry = RpfFile.CreateFileEntry("kaas.meta", "saak.meta", ref data);
|
||||
data = new byte[2048];
|
||||
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)]
|
||||
public void RunLoad()
|
||||
//[Benchmark(Baseline = true)]
|
||||
//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();
|
||||
vehiclesFileExpected.LoadOld(data, fileEntry);
|
||||
GTACrypto.DecryptNG(data.AsSpan(), "kaas", 2048);
|
||||
}
|
||||
|
||||
[Benchmark]
|
||||
public void RunLoadNew()
|
||||
public void DecryptNG()
|
||||
{
|
||||
var vehiclesFile = new VehiclesFile();
|
||||
vehiclesFile.Load(data, fileEntry);
|
||||
GTACrypto.DecryptNG(data, "kaas", 2048);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,201 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<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')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}</ProjectGuid>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>CodeWalker.Benchmarks</RootNamespace>
|
||||
<AssemblyName>CodeWalker.Benchmarks</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<AssemblyTitle>CodeWalker.Benchmarks</AssemblyTitle>
|
||||
<Product>CodeWalker.Benchmarks</Product>
|
||||
<Copyright>Copyright © 2023</Copyright>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</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>
|
||||
<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" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj">
|
||||
<Project>{FF6B9F41-14BE-474E-9ED0-549C3BEB7E00}</Project>
|
||||
<Name>CodeWalker.Core</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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>
|
||||
<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>
|
@ -2,15 +2,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static System.Reflection.Metadata.BlobBuilder;
|
||||
|
||||
namespace CodeWalker.Benchmarks
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
|
||||
|
||||
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>();
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,6 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
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: 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
|
||||
[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">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Nullable>annotations</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
|
||||
<PackageReference Include="DirectXTexNet" Version="1.0.1" />
|
||||
<PackageReference Include="directxtex_desktop_win10" Version="2023.3.30.1" />
|
||||
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
|
||||
<PackageReference Include="DirectXTexNet" Version="1.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||
<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.Mathematics" Version="4.2.0" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||
<PackageReference Include="System.Diagnostics.Tracing" Version="4.3.0" />
|
||||
<PackageReference Include="System.Memory" Version="4.5.5" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\magic.dat" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
</Project>
|
@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using TC = System.ComponentModel.TypeConverterAttribute;
|
||||
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
||||
using System.Xml;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
@ -39,12 +40,12 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public Dictionary<uint, AwcStream> StreamDict { get; set; }
|
||||
|
||||
|
||||
static public void Decrypt_RSXXTEA(byte[] data, uint[] key)
|
||||
static public void Decrypt_RSXXTEA(Span<byte> data, uint[] key)
|
||||
{
|
||||
// Rockstar's modified version of XXTEA
|
||||
uint[] blocks = new uint[data.Length / 4];
|
||||
Buffer.BlockCopy(data, 0, blocks, 0, data.Length);
|
||||
var blocks = MemoryMarshal.Cast<byte, uint>(data);
|
||||
//[] blocks = new uint[data.Length / 4];
|
||||
//Buffer.BlockCopy(data, 0, blocks, 0, data.Length);
|
||||
|
||||
int block_count = blocks.Length;
|
||||
uint a, b = blocks[0], i;
|
||||
@ -60,7 +61,7 @@ namespace CodeWalker.GameFiles
|
||||
i -= 0x9E3779B9;
|
||||
} 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)
|
||||
@ -1171,15 +1172,13 @@ namespace CodeWalker.GameFiles
|
||||
for (int b = 0; b < bcount; b++)
|
||||
{
|
||||
int srcoff = b * bsize;
|
||||
int mcsoff = (b < ocount) ? (int)SeekTableChunk.SeekTable[b] : 0;
|
||||
int blen = Math.Max(Math.Min(bsize, DataChunk.Data.Length - srcoff), 0);
|
||||
var bdat = new byte[blen];
|
||||
Buffer.BlockCopy(DataChunk.Data, srcoff, bdat, 0, blen);
|
||||
int sampleOffset = (b < ocount) ? (int)SeekTableChunk.SeekTable[b] : 0;
|
||||
int dataBlockLength = Math.Max(Math.Min(bsize, DataChunk.Data.Length - srcoff), 0);
|
||||
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);
|
||||
}
|
||||
StreamBlocks = blist.ToArray();
|
||||
@ -2712,19 +2711,20 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
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;
|
||||
ChannelCount = channelInfo?.ChannelCount ?? 0;
|
||||
ChannelInfo = channelInfo;
|
||||
|
||||
using (var ms = new MemoryStream(data))
|
||||
{
|
||||
var r = new DataReader(ms, endianess);
|
||||
Read(r);
|
||||
}
|
||||
using var ms = new MemoryStream(data, offset, dataLength);
|
||||
|
||||
var r = new DataReader(ms, endianess);
|
||||
Read(r);
|
||||
}
|
||||
|
||||
public void Read(DataReader r)
|
||||
@ -2744,7 +2744,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
|
||||
var padc = (0x800 - (r.Position % 0x800)) % 0x800;
|
||||
var padb = r.ReadBytes((int)padc);
|
||||
r.Position += padc;
|
||||
|
||||
foreach (var channel in Channels)
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
@ -31,25 +32,30 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
FileEntry = entry;
|
||||
|
||||
MemoryStream ms = new MemoryStream(data);
|
||||
BinaryReader br = new BinaryReader(ms);
|
||||
using MemoryStream ms = new MemoryStream(data);
|
||||
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++)
|
||||
{
|
||||
//read version string.
|
||||
byte b = data[i];
|
||||
if (b == 0) break;
|
||||
sb.Append((char)b);
|
||||
if (b == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
charArr[i] = (char)b;
|
||||
length++;
|
||||
}
|
||||
Version = sb.ToString().Replace("[VERSION]", "").Replace("\r", "").Replace("\n", "");
|
||||
sb.Clear();
|
||||
Version = new string(charArr.Slice(0, length)).Replace("[VERSION]", "").Replace("\r", "").Replace("\n", "");
|
||||
length = 0;
|
||||
int lastn = 0;
|
||||
int lspos = 0;
|
||||
uint structcount = 0;
|
||||
uint modlen;
|
||||
bool indates = false;
|
||||
List<string> lines = new List<string>();
|
||||
var dates = new List<CacheFileDate>();
|
||||
var allMapNodes = new List<MapDataStoreNode>();
|
||||
var allCInteriorProxies = new List<CInteriorProxy>();
|
||||
@ -62,9 +68,8 @@ namespace CodeWalker.GameFiles
|
||||
if (b == 0xA)
|
||||
{
|
||||
lastn = i;
|
||||
string line = sb.ToString();
|
||||
lines.Add(line);
|
||||
switch (line)
|
||||
string line = new string(charArr.Slice(0, length));
|
||||
switch (charArr.Slice(0, length))
|
||||
{
|
||||
case "<fileDates>":
|
||||
indates = true;
|
||||
@ -125,11 +130,12 @@ namespace CodeWalker.GameFiles
|
||||
break;
|
||||
}
|
||||
|
||||
sb.Clear();
|
||||
length = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append((char)b);
|
||||
charArr[length] = (char)b;
|
||||
length++;
|
||||
}
|
||||
}
|
||||
FileDates = dates.ToArray();
|
||||
|
@ -55,7 +55,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
using (MemoryStream ms = new MemoryStream(data))
|
||||
{
|
||||
DataReader r = new DataReader(ms, Endianess.LittleEndian);
|
||||
DataReader r = new DataReader(ms);
|
||||
|
||||
Read(r);
|
||||
};
|
||||
|
@ -16,6 +16,7 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
[TC(typeof(EXP))] public class PedsFile : GameFile, PackedFile
|
||||
{
|
||||
private static XmlNameTable cachedNameTable = new System.Xml.NameTable();
|
||||
public PsoFile Pso { 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)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -5,6 +5,7 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
@ -15,7 +16,7 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
public class VehiclesFile : GameFile, PackedFile
|
||||
{
|
||||
|
||||
private static XmlNameTable cachedNameTable = new NameTable();
|
||||
|
||||
public string ResidentTxd { 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 xmlReader = XmlReader.Create(textReader);
|
||||
using var xmlReader = XmlReader.Create(textReader, new XmlReaderSettings { NameTable = cachedNameTable });
|
||||
|
||||
while (xmlReader.Read())
|
||||
{
|
||||
@ -838,30 +839,27 @@ namespace CodeWalker.GameFiles
|
||||
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);
|
||||
if (ldarr == null) return null;
|
||||
var floats = stackalloc float[ldarr.Length];
|
||||
Span<float> floats = stackalloc float[ldarr.Length];
|
||||
var i = 0;
|
||||
foreach (var ldstr in ldarr)
|
||||
{
|
||||
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;
|
||||
i++;
|
||||
}
|
||||
floats[i] = f;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (i == 0) return null;
|
||||
|
||||
var result = new float[i];
|
||||
|
||||
Marshal.Copy((IntPtr)floats, result, 0, i);
|
||||
floats.Slice(0, i).CopyTo(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -3285,13 +3285,16 @@ namespace CodeWalker.GameFiles
|
||||
public class YmapOccludeModel : BasePathData
|
||||
{
|
||||
public OccludeModel _OccludeModel;
|
||||
|
||||
public OccludeModel OccludeModel { get { return _OccludeModel; } set { _OccludeModel = value; } }
|
||||
|
||||
public YmapFile Ymap { get; set; }
|
||||
|
||||
public byte[] Data { get; set; }
|
||||
public Vector3[] Vertices { get; set; }
|
||||
public byte[] Indices { get; set; }
|
||||
private int vertexCount;
|
||||
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 YmapOccludeModelTriangle[] Triangles { get; set; }
|
||||
@ -3321,12 +3324,12 @@ namespace CodeWalker.GameFiles
|
||||
var vptr = _OccludeModel.verts;
|
||||
var dataSize = _OccludeModel.dataSize;
|
||||
var indicesOffset = _OccludeModel.numVertsInBytes;
|
||||
var vertexCount = indicesOffset / 12;
|
||||
vertexCount = indicesOffset / 12;
|
||||
var indexCount = (int)(dataSize - indicesOffset);// / 4;
|
||||
Data = MetaTypes.GetByteArray(meta, vptr, dataSize);
|
||||
Vertices = MetaTypes.ConvertDataArray<Vector3>(Data, 0, vertexCount).ToArray();
|
||||
Indices = new byte[indexCount];
|
||||
Buffer.BlockCopy(Data, indicesOffset, Indices, 0, indexCount);
|
||||
//Vertices = MetaTypes.ConvertDataArray<Vector3>(Data, 0, vertexCount).ToArray();
|
||||
//Indices = new byte[indexCount];
|
||||
//Buffer.BlockCopy(Data, indicesOffset, Indices, 0, indexCount);
|
||||
BuildTriangles();
|
||||
}
|
||||
|
||||
@ -3362,10 +3365,11 @@ namespace CodeWalker.GameFiles
|
||||
//create vertices and indices arrays from Triangles
|
||||
if (Triangles == null)
|
||||
{
|
||||
Vertices = null;
|
||||
Indices = null;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var vdict = new Dictionary<Vector3, byte>();
|
||||
var verts = new List<Vector3>();
|
||||
var inds = new List<byte>();
|
||||
@ -3391,21 +3395,40 @@ namespace CodeWalker.GameFiles
|
||||
inds.Add(ensureVert(tri.Corner2));
|
||||
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()
|
||||
{
|
||||
//create Data from vertices and indices arrays
|
||||
if (Vertices == null) return;
|
||||
if (Indices == null) return;
|
||||
var dlen = (Vertices.Length * 12) + (Indices.Length * 1);
|
||||
var d = new byte[dlen];
|
||||
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 dlen = (Vertices.Length * Vector3.SizeInBytes) + (Indices.Length * 1);
|
||||
if (dlen != Data.Length)
|
||||
{
|
||||
throw new InvalidOperationException("Size mismatch in YmapOccludeModel BuildData");
|
||||
}
|
||||
//var d = new byte[dlen];
|
||||
//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 max = new Vector3(float.MinValue);
|
||||
for (int i = 0; i < Vertices.Length; i++)
|
||||
@ -3418,8 +3441,8 @@ namespace CodeWalker.GameFiles
|
||||
_OccludeModel.Unused0 = min.X;
|
||||
_OccludeModel.Unused1 = max.X;
|
||||
_OccludeModel.dataSize = (uint)dlen;
|
||||
_OccludeModel.numVertsInBytes = (ushort)vbytes.Length;
|
||||
_OccludeModel.numTris = (ushort)((ibytes.Length / 3) + 32768);//is this actually a flag lurking..?
|
||||
_OccludeModel.numVertsInBytes = (ushort)(vertexCount * Vector3.SizeInBytes);
|
||||
_OccludeModel.numTris = (ushort)((Indices.Length / 3) + 32768);//is this actually a flag lurking..?
|
||||
//_OccludeModel.flags = ...
|
||||
}
|
||||
|
||||
@ -3462,7 +3485,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
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))
|
||||
{
|
||||
DataReader r = new DataReader(ms, Endianess.LittleEndian);
|
||||
DataReader r = new DataReader(ms);
|
||||
|
||||
Read(r);
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
using CodeWalker.Core.Utils;
|
||||
using CodeWalker.World;
|
||||
using Dasync.Collections;
|
||||
using SharpDX;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
@ -92,15 +90,15 @@ namespace CodeWalker.GameFiles
|
||||
public Dictionary<MetaHash, Dictionary<MetaHash, RpfFileEntry>> PedClothDicts { get; set; }
|
||||
|
||||
|
||||
public List<RelFile> AudioDatRelFiles = new List<RelFile>();
|
||||
public Dictionary<MetaHash, RelData> AudioConfigDict = new Dictionary<MetaHash, RelData>();
|
||||
public Dictionary<MetaHash, RelData> AudioSpeechDict = new Dictionary<MetaHash, RelData>();
|
||||
public Dictionary<MetaHash, RelData> AudioSynthsDict = new Dictionary<MetaHash, RelData>();
|
||||
public Dictionary<MetaHash, RelData> AudioMixersDict = new Dictionary<MetaHash, RelData>();
|
||||
public Dictionary<MetaHash, RelData> AudioCurvesDict = new Dictionary<MetaHash, RelData>();
|
||||
public Dictionary<MetaHash, RelData> AudioCategsDict = new Dictionary<MetaHash, RelData>();
|
||||
public Dictionary<MetaHash, RelData> AudioSoundsDict = new Dictionary<MetaHash, RelData>();
|
||||
public Dictionary<MetaHash, RelData> AudioGameDict = new Dictionary<MetaHash, RelData>();
|
||||
public List<RelFile> AudioDatRelFiles;
|
||||
public Dictionary<MetaHash, RelData> AudioConfigDict;
|
||||
public Dictionary<MetaHash, RelData> AudioSpeechDict;
|
||||
public Dictionary<MetaHash, RelData> AudioSynthsDict;
|
||||
public Dictionary<MetaHash, RelData> AudioMixersDict;
|
||||
public Dictionary<MetaHash, RelData> AudioCurvesDict;
|
||||
public Dictionary<MetaHash, RelData> AudioCategsDict;
|
||||
public Dictionary<MetaHash, RelData> AudioSoundsDict;
|
||||
public Dictionary<MetaHash, RelData> AudioGameDict;
|
||||
|
||||
|
||||
|
||||
@ -122,6 +120,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
private string GTAFolder;
|
||||
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
|
||||
SelectedDlc = dlc;
|
||||
@ -165,19 +164,19 @@ namespace CodeWalker.GameFiles
|
||||
EnableMods = mods;
|
||||
GTAFolder = folder;
|
||||
ExcludeFolders = excludeFolders;
|
||||
Key = key;
|
||||
}
|
||||
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
IsInited = false;
|
||||
//IsInited = false;
|
||||
|
||||
mainCache.Clear();
|
||||
|
||||
textureLookup.Clear();
|
||||
//textureLookup.Clear();
|
||||
|
||||
while (requestQueue.TryDequeue(out _))
|
||||
{ } //empty the old queue out...
|
||||
requestQueue.Clear();
|
||||
}
|
||||
|
||||
public void SetGtaFolder(string folder)
|
||||
@ -204,6 +203,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
if (RpfMan == null)
|
||||
{
|
||||
GTA5Keys.LoadFromPath(GTAFolder, Key);
|
||||
//EnableDlc = !string.IsNullOrEmpty(SelectedDlc);
|
||||
|
||||
RpfMan = RpfManager.GetInstance();
|
||||
@ -280,6 +280,8 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ArgumentNullException.ThrowIfNull(allRpfs, nameof(allRpfs));
|
||||
IsIniting = true;
|
||||
try
|
||||
{
|
||||
@ -378,7 +380,7 @@ namespace CodeWalker.GameFiles
|
||||
DlcPaths.Clear();
|
||||
if ((dlclistxml == null) || (dlclistxml.DocumentElement == null))
|
||||
{
|
||||
ErrorLog("InitDlcList: Couldn't load " + dlclistpath + ".");
|
||||
ErrorLog?.Invoke("InitDlcList: Couldn't load " + dlclistpath + ".");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -442,7 +444,9 @@ namespace CodeWalker.GameFiles
|
||||
RpfFile dlcfile;
|
||||
dlcDict2.TryGetValue(dlcname, out dlcfile);
|
||||
if (dlcfile == null)
|
||||
{ continue; }
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var dlcpath = dlcfile.Path + "\\";
|
||||
var files = updrpffile.GetFiles(relpath, true);
|
||||
foreach (var file in files)
|
||||
@ -1052,7 +1056,11 @@ namespace CodeWalker.GameFiles
|
||||
YmapDict ??= new Dictionary<uint, RpfFileEntry>(4600);
|
||||
YbnDict ??= new Dictionary<uint, RpfFileEntry>(8800);
|
||||
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)
|
||||
{
|
||||
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};");
|
||||
}
|
||||
|
||||
private void InitManifestDicts(bool force = true)
|
||||
private async ValueTask InitManifestDicts(bool force = true)
|
||||
{
|
||||
UpdateStatus?.Invoke("Loading manifests...");
|
||||
using var _ = new DisposableTimer("InitManifestDicts");
|
||||
AllManifests = new List<YmfFile>(2000);
|
||||
hdtexturelookup = new Dictionary<MetaHash, MetaHash>(24000);
|
||||
AllManifests ??= new List<YmfFile>(2000);
|
||||
hdtexturelookup ??= new Dictionary<MetaHash, MetaHash>(24000);
|
||||
AllManifests.Clear();
|
||||
hdtexturelookup.Clear();
|
||||
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..
|
||||
foreach (RpfEntry entry in file.AllEntries)
|
||||
{
|
||||
@ -1101,11 +1113,14 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
try
|
||||
{
|
||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||
YmfFile ymffile = RpfMan.GetFile<YmfFile>(entry);
|
||||
UpdateStatus?.Invoke(entry.Path);
|
||||
YmfFile ymffile = await RpfMan.GetFileAsync<YmfFile>(entry).ConfigureAwait(false);
|
||||
if (ymffile != null)
|
||||
{
|
||||
AllManifests.Add(ymffile);
|
||||
lock(AllManifests)
|
||||
{
|
||||
AllManifests.Add(ymffile);
|
||||
}
|
||||
|
||||
if (ymffile.HDTxdAssetBindings != null)
|
||||
{
|
||||
@ -1114,7 +1129,10 @@ namespace CodeWalker.GameFiles
|
||||
var b = ymffile.HDTxdAssetBindings[i];
|
||||
var targetasset = JenkHash.GenHashLower(b.targetAsset.ToString());
|
||||
var hdtxd = JenkHash.GenHashLower(b.HDTxd.ToString());
|
||||
hdtexturelookup[targetasset] = hdtxd;
|
||||
lock(hdtexturelookup)
|
||||
{
|
||||
hdtexturelookup[targetasset] = hdtxd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1127,7 +1145,7 @@ namespace CodeWalker.GameFiles
|
||||
Console.WriteLine(errstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
Console.WriteLine($"hdtexturelookup: {hdtexturelookup.Count}; AllManifests: {AllManifests.Count};");
|
||||
}
|
||||
@ -1159,7 +1177,7 @@ namespace CodeWalker.GameFiles
|
||||
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)
|
||||
{
|
||||
@ -1228,7 +1246,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Couldn't find {node.Name} in YmapDict");
|
||||
//Console.WriteLine($"Couldn't find {node.Name} in YmapDict");
|
||||
} //ymap not found...
|
||||
}
|
||||
}
|
||||
@ -1249,17 +1267,11 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
CacheDatFile maincache = null;
|
||||
maincache = loadCacheFile("common.rpf\\data\\gta5_cache_y.dat", true);
|
||||
if (EnableDlc)
|
||||
{
|
||||
maincache = loadCacheFile("update\\update.rpf\\common\\data\\gta5_cache_y.dat", false);
|
||||
if (maincache == null)
|
||||
{
|
||||
maincache = loadCacheFile("update\\update2.rpf\\common\\data\\gta5_cache_y.dat", true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
maincache = loadCacheFile("common.rpf\\data\\gta5_cache_y.dat", true);
|
||||
maincache = loadCacheFile("update\\update2.rpf\\common\\data\\gta5_cache_y.dat", true);
|
||||
}
|
||||
|
||||
|
||||
@ -1311,7 +1323,8 @@ namespace CodeWalker.GameFiles
|
||||
// }
|
||||
//}, maxDegreeOfParallelism: 8);
|
||||
|
||||
await allYtypes.ParallelForEachAsync(async (file) =>
|
||||
|
||||
await Parallel.ForEachAsync(allYtypes, async (file, cancellationToken) =>
|
||||
{
|
||||
foreach (var entry in file.AllEntries)
|
||||
{
|
||||
@ -1323,6 +1336,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
ErrorLog(entry.Path + ": " + ex.ToString());
|
||||
}
|
||||
}
|
||||
@ -1707,7 +1721,10 @@ namespace CodeWalker.GameFiles
|
||||
if (file.Name.Equals(name + ".yld", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
pedClotsDict ??= ensureDict(allPedClothDicts, hash);
|
||||
pedClotsDict[file.ShortNameHash] = file;
|
||||
lock(pedClotsDict)
|
||||
{
|
||||
pedClotsDict[file.ShortNameHash] = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1733,17 +1750,26 @@ namespace CodeWalker.GameFiles
|
||||
if (file.IsExtension(".ydd"))
|
||||
{
|
||||
pedDrwDicts ??= ensureDict(allPedDrwDicts, hash);
|
||||
pedDrwDicts[file.ShortNameHash] = file;
|
||||
lock(pedDrwDicts)
|
||||
{
|
||||
pedDrwDicts[file.ShortNameHash] = file;
|
||||
}
|
||||
}
|
||||
else if (file.IsExtension(".ytd"))
|
||||
{
|
||||
pedTextDicts ??= ensureDict(allPedTexDicts, hash);
|
||||
pedTextDicts[file.ShortNameHash] = file;
|
||||
lock(pedTextDicts)
|
||||
{
|
||||
pedTextDicts[file.ShortNameHash] = file;
|
||||
}
|
||||
}
|
||||
else if (file.IsExtension(".yld"))
|
||||
{
|
||||
pedClotsDict ??= ensureDict(allPedClothDicts, hash);
|
||||
pedClotsDict[file.ShortNameHash] = file;
|
||||
lock(pedClotsDict)
|
||||
{
|
||||
pedClotsDict[file.ShortNameHash] = file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1914,7 +1940,8 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
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);
|
||||
if (relfile == null)
|
||||
@ -2134,7 +2161,7 @@ namespace CodeWalker.GameFiles
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
throw ex;
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
@ -2201,7 +2228,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
if (!ydr.Loaded && !ydr.LoadQueued)
|
||||
{
|
||||
TryLoadEnqueue(ydr);
|
||||
_ = TryLoadEnqueue(ydr);
|
||||
}
|
||||
return ydr;
|
||||
}
|
||||
@ -2233,7 +2260,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
if (!ydd.Loaded && !ydd.LoadQueued)
|
||||
{
|
||||
TryLoadEnqueue(ydd);
|
||||
_ = TryLoadEnqueue(ydd);
|
||||
}
|
||||
return ydd;
|
||||
}
|
||||
@ -2298,7 +2325,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
if (!ymap.Loaded && !ymap.LoadQueued)
|
||||
{
|
||||
TryLoadEnqueue(ymap);
|
||||
_ = TryLoadEnqueue(ymap);
|
||||
}
|
||||
return ymap;
|
||||
}
|
||||
@ -2331,7 +2358,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
if (!yft.Loaded && !yft.LoadQueued)
|
||||
{
|
||||
TryLoadEnqueue(yft);
|
||||
_ = TryLoadEnqueue(yft);
|
||||
}
|
||||
return yft;
|
||||
}
|
||||
@ -2360,7 +2387,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
if (!ybn.Loaded && !ybn.LoadQueued)
|
||||
{
|
||||
TryLoadEnqueue(ybn);
|
||||
_ = TryLoadEnqueue(ybn);
|
||||
}
|
||||
return ybn;
|
||||
}
|
||||
@ -2389,7 +2416,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
if (!ycd.Loaded && !ycd.LoadQueued)
|
||||
{
|
||||
TryLoadEnqueue(ycd);
|
||||
_ = TryLoadEnqueue(ycd);
|
||||
}
|
||||
return ycd;
|
||||
}
|
||||
@ -2418,7 +2445,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
if (!yed.Loaded && !yed.LoadQueued)
|
||||
{
|
||||
TryLoadEnqueue(yed);
|
||||
_ = TryLoadEnqueue(yed);
|
||||
}
|
||||
return yed;
|
||||
}
|
||||
@ -2447,7 +2474,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
if (!ynv.Loaded && !ynv.LoadQueued)
|
||||
{
|
||||
TryLoadEnqueue(ynv);
|
||||
_ = TryLoadEnqueue(ynv);
|
||||
}
|
||||
return ynv;
|
||||
}
|
||||
@ -2539,12 +2566,19 @@ namespace CodeWalker.GameFiles
|
||||
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()
|
||||
{
|
||||
var f = new T();
|
||||
f.RpfFileEntry = e;
|
||||
TryLoadEnqueue(f);
|
||||
_ = TryLoadEnqueue(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
@ -2623,7 +2657,7 @@ namespace CodeWalker.GameFiles
|
||||
req.LoadQueued = false;
|
||||
req.Loaded = false;
|
||||
Console.WriteLine(e);
|
||||
TryLoadEnqueue(req);
|
||||
_ = TryLoadEnqueue(req);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -114,9 +114,6 @@ namespace CodeWalker.GameFiles
|
||||
(ulong)this.NamePointer // offset
|
||||
);
|
||||
|
||||
if (!string.IsNullOrEmpty(Name))
|
||||
{ }
|
||||
|
||||
//Strings = MetaTypes.GetStrings(this);
|
||||
|
||||
#if DEBUG
|
||||
@ -549,7 +546,7 @@ namespace CodeWalker.GameFiles
|
||||
public override void Read(ResourceDataReader reader, params object[] parameters)
|
||||
{
|
||||
// read structure data
|
||||
this.StructureNameHash = (MetaName)reader.ReadInt32();
|
||||
this.StructureNameHash = (MetaName)reader.ReadInt32();
|
||||
this.DataLength = reader.ReadInt32();
|
||||
this.DataPointer = reader.ReadInt64();
|
||||
|
||||
|
@ -11,6 +11,7 @@ using TC = System.ComponentModel.TypeConverterAttribute;
|
||||
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
||||
using CodeWalker.World;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
@ -1454,40 +1455,13 @@ namespace CodeWalker.GameFiles
|
||||
if (items == null) return null;
|
||||
|
||||
return MemoryMarshal.AsBytes(items.AsSpan()).ToArray();
|
||||
}
|
||||
|
||||
//var size = Marshal.SizeOf(typeof(T)) * items.Length;
|
||||
//var b = new byte[size];
|
||||
//GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
||||
//var h = handle.AddrOfPinnedObject();
|
||||
//Marshal.Copy(h, b, 0, size);
|
||||
//handle.Free();
|
||||
//return b;
|
||||
public static Span<byte> ConvertArrayToBytes<T>(Span<T> items) where T : struct
|
||||
{
|
||||
if (items == null) return null;
|
||||
|
||||
//var size = Marshal.SizeOf(typeof(T)) * items.Length;
|
||||
//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;
|
||||
return MemoryMarshal.AsBytes(items);
|
||||
}
|
||||
|
||||
|
||||
@ -1561,7 +1535,10 @@ namespace CodeWalker.GameFiles
|
||||
var ptr = ptrs[i];
|
||||
var offset = ptr.Offset;
|
||||
var block = meta.GetBlock(ptr.BlockID);
|
||||
if (block == null) continue;
|
||||
if (block == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//if (blocktype == 0)
|
||||
//{ blocktype = block.StructureNameHash; }
|
||||
@ -1569,9 +1546,13 @@ namespace CodeWalker.GameFiles
|
||||
//{ } //not all the same type..!
|
||||
|
||||
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))
|
||||
{ continue; }
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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
|
||||
{
|
||||
if (count == 0) return null;
|
||||
if (count == 0)
|
||||
return null;
|
||||
|
||||
T[] items = new T[count];
|
||||
int itemsize = Marshal.SizeOf(typeof(T));
|
||||
@ -1593,7 +1575,9 @@ namespace CodeWalker.GameFiles
|
||||
uint ptroffset = (uint)((pointer >> 12) & 0xFFFFF);
|
||||
var ptrblock = (ptrindex < meta.DataBlocks.Count) ? meta.DataBlocks[(int)ptrindex] : null;
|
||||
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 itemoffset = byteoffset / itemsize;
|
||||
@ -1608,25 +1592,30 @@ namespace CodeWalker.GameFiles
|
||||
itemcount = itemsleft;
|
||||
} //don't try to read too many items..
|
||||
|
||||
|
||||
//ConvertDataArray<T>(ptrblock.Data, itemoffset * Marshal.SizeOf(typeof(T)), itemcount).CopyTo(items.AsSpan(curi));
|
||||
for (int i = 0; i < itemcount; i++)
|
||||
{
|
||||
int offset = (itemoffset + i) * itemsize;
|
||||
int index = curi + i;
|
||||
items[index] = ConvertData<T>(ptrblock.Data, offset);
|
||||
}
|
||||
ConvertDataArray<T>(ptrblock.Data, itemoffset * Marshal.SizeOf(typeof(T)), itemcount).CopyTo(items.AsSpan(curi));
|
||||
//for (int i = 0; i < itemcount; i++)
|
||||
//{
|
||||
// int offset = (itemoffset + i) * itemsize;
|
||||
// int index = curi + i;
|
||||
// items[index] = ConvertData<T>(ptrblock.Data, offset);
|
||||
//}
|
||||
itemoffset = 0; //start at beginning of next block..
|
||||
curi += itemcount;
|
||||
itemsleft -= itemcount;
|
||||
if (itemsleft <= 0)
|
||||
{ return items; }//all done!
|
||||
{
|
||||
return items;
|
||||
}//all done!
|
||||
ptrindex++;
|
||||
ptrblock = (ptrindex < meta.DataBlocks.Count) ? meta.DataBlocks[(int)ptrindex] : null;
|
||||
if ((ptrblock == null) || (ptrblock.Data == null))
|
||||
{ break; } //not enough items..?
|
||||
{
|
||||
break;
|
||||
} //not enough items..?
|
||||
if (ptrblock.StructureNameHash != name)
|
||||
{ break; } //type mismatch..
|
||||
{
|
||||
break;
|
||||
} //type mismatch..
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -2207,12 +2207,7 @@ namespace CodeWalker.GameFiles
|
||||
public static string XmlEscape(string unescaped)
|
||||
{
|
||||
if (unescaped == null) return null;
|
||||
XmlDocument doc = new XmlDocument();
|
||||
XmlNode node = doc.CreateElement("root");
|
||||
node.InnerText = unescaped;
|
||||
var escaped = node.InnerXml.Replace("\"", """);
|
||||
if (escaped != unescaped)
|
||||
{ }
|
||||
var escaped = System.Web.HttpUtility.HtmlEncode(unescaped).Replace("\"", """);
|
||||
return escaped;
|
||||
}
|
||||
|
||||
|
@ -117,6 +117,7 @@ using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -880,8 +881,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
foreach (var str in strs)
|
||||
{
|
||||
JenkIndex.Ensure(str);
|
||||
JenkIndex.EnsureLower(str);
|
||||
JenkIndex.EnsureBoth(str);
|
||||
}
|
||||
Strings = strs.ToArray();
|
||||
}
|
||||
|
@ -471,7 +471,7 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
|
||||
MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream("Decompress", data.Length);
|
||||
ds.CopyToFast(outstr);
|
||||
ds.CopyTo(outstr, 524288);
|
||||
return outstr.ToArray();
|
||||
}
|
||||
}
|
||||
|
@ -104,11 +104,12 @@ namespace CodeWalker.GameFiles
|
||||
position = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new resource data reader for the specified system- and graphics-stream.
|
||||
/// </summary>
|
||||
public ResourceDataReader(Stream systemStream, Stream graphicsStream, Endianess endianess = Endianess.LittleEndian)
|
||||
: base((Stream)null, endianess)
|
||||
: base(null, endianess)
|
||||
{
|
||||
this.systemStream = systemStream;
|
||||
this.graphicsStream = graphicsStream;
|
||||
@ -117,7 +118,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
|
||||
public ResourceDataReader(RpfResourceFileEntry resentry, byte[] data, Endianess endianess = Endianess.LittleEndian)
|
||||
: base((Stream)null, endianess)
|
||||
: base(null, endianess)
|
||||
{
|
||||
FileEntry = resentry;
|
||||
this.systemSize = resentry.SystemSize;
|
||||
@ -138,21 +139,21 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
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)
|
||||
{
|
||||
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.graphicsStream = Stream.Synchronized(new MemoryStream(data, (int)systemSize, (int)graphicsSize));
|
||||
this.systemStream = new MemoryStream(data, 0, (int)systemSize);
|
||||
this.graphicsStream = new MemoryStream(data, (int)systemSize, (int)graphicsSize);
|
||||
}
|
||||
|
||||
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.graphicsStream = Stream.Synchronized(new MemoryStream(data, systemSize, graphicsSize));
|
||||
this.systemStream = new MemoryStream(data, 0, systemSize);
|
||||
this.graphicsStream = new MemoryStream(data, systemSize, graphicsSize);
|
||||
}
|
||||
|
||||
public override Stream GetStream()
|
||||
@ -269,7 +270,6 @@ namespace CodeWalker.GameFiles
|
||||
return items;
|
||||
}
|
||||
|
||||
internal const int StackallocThreshold = 512;
|
||||
public unsafe byte[] ReadBytesAt(ulong position, uint count, bool cache = true, byte[] buffer = null)
|
||||
{
|
||||
long pos = (long)position;
|
||||
@ -489,6 +489,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
systemStream?.Dispose();
|
||||
graphicsStream?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -647,6 +648,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
systemStream?.Dispose();
|
||||
graphicsStream?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,26 @@ using System.Threading.Tasks;
|
||||
|
||||
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
|
||||
{
|
||||
@ -53,15 +73,6 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
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()
|
||||
{
|
||||
@ -163,7 +174,10 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ThrowInvalidResource()
|
||||
{
|
||||
throw new Exception("Invalid Resource - not GTAV!");
|
||||
}
|
||||
|
||||
private void ReadHeader(BinaryReader br)
|
||||
{
|
||||
@ -178,7 +192,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
if (Version != 0x52504637)
|
||||
{
|
||||
throw new Exception("Invalid Resource - not GTAV!");
|
||||
ThrowInvalidResource();
|
||||
}
|
||||
|
||||
var entriesLength = (int)EntryCount * 16;
|
||||
@ -202,8 +216,8 @@ namespace CodeWalker.GameFiles
|
||||
break;
|
||||
case RpfEncryption.NG:
|
||||
default:
|
||||
GTACrypto.DecryptNG(entriesdata, Name, (uint)FileSize, 0, entriesLength);
|
||||
GTACrypto.DecryptNG(namesdata, Name, (uint)FileSize, 0, namesLength);
|
||||
GTACrypto.DecryptNG(entriesdata.AsSpan(0, entriesLength), Name, (uint)FileSize);
|
||||
GTACrypto.DecryptNG(namesdata.AsSpan(0, namesLength), Name, (uint)FileSize);
|
||||
|
||||
IsNGEncrypted = true;
|
||||
break;
|
||||
@ -215,9 +229,6 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
AllEntries = new List<RpfEntry>((int)EntryCount);
|
||||
TotalFileCount = 0;
|
||||
TotalFolderCount = 0;
|
||||
TotalResourceCount = 0;
|
||||
TotalBinaryFileCount = 0;
|
||||
|
||||
for (uint i = 0; i < EntryCount; i++)
|
||||
{
|
||||
@ -231,18 +242,15 @@ namespace CodeWalker.GameFiles
|
||||
if (x == 0x7fffff00) //directory entry
|
||||
{
|
||||
e = new RpfDirectoryEntry();
|
||||
TotalFolderCount++;
|
||||
}
|
||||
else if ((x & 0x80000000) == 0) //binary file entry
|
||||
{
|
||||
e = new RpfBinaryFileEntry();
|
||||
TotalBinaryFileCount++;
|
||||
TotalFileCount++;
|
||||
}
|
||||
else //assume resource file entry
|
||||
{
|
||||
e = new RpfResourceFileEntry();
|
||||
TotalResourceCount++;
|
||||
TotalFileCount++;
|
||||
}
|
||||
|
||||
@ -328,39 +336,39 @@ namespace CodeWalker.GameFiles
|
||||
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 br = new BinaryReader(fileStream);
|
||||
try
|
||||
{
|
||||
return ScanStructure(br, updateStatus, errorLog);
|
||||
return ScanStructure(br, updateStatus, errorLog) ?? default;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LastError = ex.ToString();
|
||||
LastException = ex;
|
||||
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
|
||||
{
|
||||
ReadHeader(br);
|
||||
} catch
|
||||
{
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
GrandTotalRpfCount = 1; //count this file..
|
||||
GrandTotalFileCount = 1; //start with this one.
|
||||
GrandTotalFolderCount = 0;
|
||||
GrandTotalResourceCount = 0;
|
||||
GrandTotalBinaryFileCount = 0;
|
||||
var fileCounts = new FileCounts
|
||||
{
|
||||
Rpfs = 1,
|
||||
Files = 1
|
||||
};
|
||||
|
||||
Children = new List<RpfFile>();
|
||||
|
||||
@ -383,32 +391,29 @@ namespace CodeWalker.GameFiles
|
||||
subfile.Parent = this;
|
||||
subfile.ParentFileEntry = binentry;
|
||||
|
||||
if (subfile.ScanStructure(br, updateStatus, errorLog))
|
||||
{
|
||||
GrandTotalRpfCount += subfile.GrandTotalRpfCount;
|
||||
GrandTotalFileCount += subfile.GrandTotalFileCount;
|
||||
GrandTotalFolderCount += subfile.GrandTotalFolderCount;
|
||||
GrandTotalResourceCount += subfile.GrandTotalResourceCount;
|
||||
GrandTotalBinaryFileCount += subfile.GrandTotalBinaryFileCount;
|
||||
var result = subfile.ScanStructure(br, updateStatus, errorLog);
|
||||
|
||||
if (result is not null)
|
||||
{
|
||||
fileCounts += result.Value;
|
||||
Children.Add(subfile);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//binary file that's not an rpf...
|
||||
GrandTotalBinaryFileCount++;
|
||||
GrandTotalFileCount++;
|
||||
fileCounts.BinaryFiles++;
|
||||
fileCounts.Files++;
|
||||
}
|
||||
}
|
||||
else if (entry is RpfResourceFileEntry)
|
||||
{
|
||||
GrandTotalResourceCount++;
|
||||
GrandTotalFileCount++;
|
||||
fileCounts.Resources++;
|
||||
fileCounts.Files++;
|
||||
}
|
||||
else if (entry is RpfDirectoryEntry)
|
||||
{
|
||||
GrandTotalFolderCount++;
|
||||
fileCounts.Folders++;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -416,7 +421,7 @@ namespace CodeWalker.GameFiles
|
||||
errorLog?.Invoke(entry.Path + ": " + ex.ToString());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return fileCounts;
|
||||
}
|
||||
|
||||
|
||||
@ -500,7 +505,7 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
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);
|
||||
|
||||
MemoryStream outstr = recyclableMemoryStreamManager.GetStream();
|
||||
ds.CopyToFast(outstr);
|
||||
byte[] deflated = outstr.GetBuffer();
|
||||
byte[] outbuf = new byte[outstr.Length]; //need to copy to the right size buffer for File.WriteAllBytes().
|
||||
Array.Copy(deflated, outbuf, outbuf.Length);
|
||||
ds.CopyTo(outstr);
|
||||
byte[] outbuf = outstr.ToArray();
|
||||
|
||||
bool pathok = true;
|
||||
if (File.Exists(ofpath))
|
||||
@ -604,11 +607,12 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
LastError = ex.ToString();
|
||||
LastException = ex;
|
||||
Console.WriteLine(ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ValueTask<byte[]> ExtractFileAsync(RpfFileEntry entry)
|
||||
public async ValueTask<byte[]> ExtractFileAsync(RpfFileEntry entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -617,16 +621,16 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
if (entry is RpfBinaryFileEntry binaryFileEntry)
|
||||
{
|
||||
return ExtractFileBinaryAsync(binaryFileEntry, br);
|
||||
return await ExtractFileBinaryAsync(binaryFileEntry, br).ConfigureAwait(false);
|
||||
}
|
||||
else if (entry is RpfResourceFileEntry resourceFileEntry)
|
||||
{
|
||||
return ExtractFileResourceAsync(resourceFileEntry, br);
|
||||
return await ExtractFileResourceAsync(resourceFileEntry, br).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
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();
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
ExtractedByteCount = 0;
|
||||
try
|
||||
{
|
||||
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.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtractedByteCount += data.Length;
|
||||
}
|
||||
}
|
||||
else if (entry is RpfResourceFileEntry)
|
||||
{
|
||||
@ -1095,10 +1094,6 @@ namespace CodeWalker.GameFiles
|
||||
sb.AppendFormat("{0} : Decompressed output was empty.", entry.Path);
|
||||
sb.AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
ExtractedByteCount += data.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1128,18 +1123,22 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public List<RpfFileEntry> GetFiles(string folder, bool recurse)
|
||||
{
|
||||
if (Root == null)
|
||||
{
|
||||
return new List<RpfFileEntry>();
|
||||
}
|
||||
List<RpfFileEntry> result = new List<RpfFileEntry>();
|
||||
string[] parts = folder.ToLowerInvariant().Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
//folder.AsSpan().Split
|
||||
RpfDirectoryEntry dir = Root;
|
||||
for (int i = 0; i < parts.Length; i++)
|
||||
foreach(var part in folder.EnumerateSplit('\\'))
|
||||
{
|
||||
if (dir == null) break;
|
||||
dir = FindSubDirectory(dir, parts[i]);
|
||||
}
|
||||
if (dir != null)
|
||||
{
|
||||
GetFiles(dir, result, recurse);
|
||||
if (part.Length == 0)
|
||||
continue;
|
||||
dir = FindSubDirectory(dir, part);
|
||||
}
|
||||
|
||||
GetFiles(dir, result, recurse);
|
||||
|
||||
return result;
|
||||
}
|
||||
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++)
|
||||
{
|
||||
var cdir = dir.Directories[i];
|
||||
if (cdir.Name.ToLowerInvariant() == name)
|
||||
if (cdir.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return cdir;
|
||||
}
|
||||
@ -1175,8 +1174,25 @@ namespace CodeWalker.GameFiles
|
||||
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 byte[] DecompressBytes(byte[] bytes)
|
||||
@ -1186,7 +1202,7 @@ namespace CodeWalker.GameFiles
|
||||
using DeflateStream ds = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress);
|
||||
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.
|
||||
|
||||
if (outbuf.Length <= bytes.Length)
|
||||
@ -1212,14 +1228,8 @@ namespace CodeWalker.GameFiles
|
||||
using DeflateStream ds = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress);
|
||||
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[] 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)
|
||||
{
|
||||
@ -1245,9 +1255,7 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
ds.Write(data, 0, data.Length);
|
||||
ds.Close();
|
||||
byte[] deflated = ms.GetBuffer();
|
||||
byte[] outbuf = new byte[ms.Length]; //need to copy to the right size buffer...
|
||||
Buffer.BlockCopy(deflated, 0, outbuf, 0, outbuf.Length);
|
||||
byte[] outbuf = ms.ToArray(); //need to copy to the right size buffer...
|
||||
return outbuf;
|
||||
}
|
||||
}
|
||||
@ -1377,8 +1385,8 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
private byte[] GetHeaderNamesData()
|
||||
{
|
||||
MemoryStream namesstream = new MemoryStream();
|
||||
DataWriter nameswriter = new DataWriter(namesstream);
|
||||
using MemoryStream namesstream = new MemoryStream();
|
||||
using DataWriter nameswriter = new DataWriter(namesstream);
|
||||
var namedict = new Dictionary<string, uint>();
|
||||
foreach (var entry in AllEntries)
|
||||
{
|
||||
@ -1395,10 +1403,10 @@ namespace CodeWalker.GameFiles
|
||||
nameswriter.Write(name);
|
||||
}
|
||||
}
|
||||
var buf = new byte[namesstream.Length];
|
||||
var buf = new byte[Math.Max(namesstream.Length, 16)];
|
||||
namesstream.Position = 0;
|
||||
namesstream.Read(buf, 0, buf.Length);
|
||||
return PadBuffer(buf, 16);
|
||||
namesstream.Read(buf, 0, (int)namesstream.Length);
|
||||
return buf;
|
||||
}
|
||||
private byte[] GetHeaderEntriesData()
|
||||
{
|
||||
@ -1419,18 +1427,6 @@ namespace CodeWalker.GameFiles
|
||||
uint headerblockcount = GetBlockCount(headerusedbytes);
|
||||
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
|
||||
{
|
||||
uint rem = l % n;
|
||||
@ -2430,7 +2426,10 @@ namespace CodeWalker.GameFiles
|
||||
char ch = Name[i];
|
||||
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;
|
||||
}
|
||||
if (ch == System.IO.Path.DirectorySeparatorChar || ch == System.IO.Path.AltDirectorySeparatorChar)
|
||||
@ -3006,7 +3005,7 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
public uint Value { get; set; }
|
||||
|
||||
public RpfResourcePage[] Pages
|
||||
public readonly RpfResourcePage[] Pages
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -3032,10 +3031,10 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
}
|
||||
|
||||
public uint TypeVal { get { return (Value >> 28) & 0xF; } }
|
||||
public uint BaseShift { get { return (Value & 0xF); } }
|
||||
public uint BaseSize { get { return (0x200u << (int)BaseShift); } }
|
||||
public uint[] BaseSizes
|
||||
public readonly uint TypeVal { get { return (Value >> 28) & 0xF; } }
|
||||
public readonly uint BaseShift { get { return (Value & 0xF); } }
|
||||
public readonly uint BaseSize { get { return (0x200u << (int)BaseShift); } }
|
||||
public readonly uint[] BaseSizes
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -3054,7 +3053,7 @@ namespace CodeWalker.GameFiles
|
||||
};
|
||||
}
|
||||
}
|
||||
public uint[] PageCounts
|
||||
public readonly uint[] PageCounts
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -3072,7 +3071,7 @@ namespace CodeWalker.GameFiles
|
||||
};
|
||||
}
|
||||
}
|
||||
public uint[] PageSizes
|
||||
public readonly uint[] PageSizes
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -3092,7 +3091,7 @@ namespace CodeWalker.GameFiles
|
||||
};
|
||||
}
|
||||
}
|
||||
public uint Count
|
||||
public readonly uint Count
|
||||
{
|
||||
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];
|
||||
}
|
||||
}
|
||||
public uint Size
|
||||
public readonly uint Size
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -3152,7 +3151,7 @@ namespace CodeWalker.GameFiles
|
||||
return new RpfResourcePageFlags(v);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
public override readonly string ToString()
|
||||
{
|
||||
return "Size: " + Size.ToString() + ", Pages: " + Count.ToString();
|
||||
}
|
||||
|
@ -8,8 +8,10 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace CodeWalker.GameFiles
|
||||
{
|
||||
@ -42,6 +44,9 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
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)
|
||||
{
|
||||
using var _ = new DisposableTimer("RpfManager.Init");
|
||||
@ -52,14 +57,14 @@ namespace CodeWalker.GameFiles
|
||||
var sopt = rootOnly ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories;
|
||||
string[] allfiles = Directory.GetFiles(folder, "*.rpf", sopt);
|
||||
|
||||
BaseRpfs = new List<RpfFile>();
|
||||
ModRpfs = new List<RpfFile>();
|
||||
DlcRpfs = new List<RpfFile>();
|
||||
AllRpfs = new List<RpfFile>();
|
||||
DlcNoModRpfs = new List<RpfFile>();
|
||||
AllNoModRpfs = new List<RpfFile>();
|
||||
RpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
||||
EntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
BaseRpfs = new List<RpfFile>(1300);
|
||||
ModRpfs = new List<RpfFile>(0);
|
||||
DlcRpfs = new List<RpfFile>(3500);
|
||||
AllRpfs = new List<RpfFile>(5000);
|
||||
DlcNoModRpfs = new List<RpfFile>(3500);
|
||||
AllNoModRpfs = new List<RpfFile>(5000);
|
||||
RpfDict = new Dictionary<string, RpfFile>(DefaultRpfDictCapacity, StringComparer.OrdinalIgnoreCase);
|
||||
EntryDict = new Dictionary<string, RpfEntry>(DefaultEntryDictCapacity, StringComparer.OrdinalIgnoreCase);
|
||||
ModRpfDict = new Dictionary<string, RpfFile>(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)
|
||||
{
|
||||
Console.WriteLine(rf.LastException);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -99,12 +105,10 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
});
|
||||
|
||||
var calculateSum = (RpfFile rpf) => { return 0; };
|
||||
|
||||
calculateSum = (RpfFile rpf) =>
|
||||
static int calculateSum(RpfFile rpf)
|
||||
{
|
||||
return rpf.AllEntries?.Count ?? 0 + rpf.Children?.Sum(calculateSum) ?? 0;
|
||||
};
|
||||
}
|
||||
|
||||
var minCapacity = rpfs.Sum(calculateSum);
|
||||
if (minCapacity > AllRpfs.Capacity)
|
||||
@ -119,23 +123,23 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
if (buildIndex)
|
||||
{
|
||||
updateStatus?.Invoke("Building jenkindex...");
|
||||
Task.Run(() =>
|
||||
{
|
||||
updateStatus?.Invoke("Building jenkindex...");
|
||||
BuildBaseJenkIndex();
|
||||
IsInited = true;
|
||||
updateStatus?.Invoke("Scan complete");
|
||||
});
|
||||
updateStatus?.Invoke("Scan complete");
|
||||
}
|
||||
else
|
||||
{
|
||||
updateStatus?.Invoke("Scan complete");
|
||||
IsInited = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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)
|
||||
@ -149,20 +153,23 @@ namespace CodeWalker.GameFiles
|
||||
DlcRpfs = new List<RpfFile>();
|
||||
DlcNoModRpfs = new List<RpfFile>();
|
||||
AllNoModRpfs = new List<RpfFile>();
|
||||
RpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
||||
EntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
RpfDict = new Dictionary<string, RpfFile>(DefaultRpfDictCapacity, StringComparer.OrdinalIgnoreCase);
|
||||
EntryDict = new Dictionary<string, RpfEntry>(DefaultEntryDictCapacity, StringComparer.OrdinalIgnoreCase);
|
||||
ModRpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
||||
ModEntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var rpf in allRpfs)
|
||||
{
|
||||
RpfDict[rpf.Path] = rpf;
|
||||
if (rpf.AllEntries == null) continue;
|
||||
if (rpf.AllEntries == null)
|
||||
continue;
|
||||
foreach (var entry in rpf.AllEntries)
|
||||
{
|
||||
EntryDict[entry.Path] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"RpfDict: {RpfDict.Count}; EntryDict: {EntryDict.Count}");
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
BuildBaseJenkIndex();
|
||||
@ -173,7 +180,10 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
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));
|
||||
|
||||
if (file.AllEntries != null)
|
||||
@ -313,6 +323,7 @@ namespace CodeWalker.GameFiles
|
||||
byte[] bytes = GetFileData(path);
|
||||
return TextUtil.GetUTF8Text(bytes);
|
||||
}
|
||||
|
||||
public XmlDocument GetFileXml(string path)
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
@ -321,6 +332,7 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
doc.LoadXml(text);
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
@ -373,12 +385,12 @@ namespace CodeWalker.GameFiles
|
||||
file.Load(data, entry);
|
||||
}
|
||||
return file;
|
||||
} catch(Exception ex)
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
public bool LoadFile<T>(T file, RpfEntry e) where T : class, PackedFile
|
||||
{
|
||||
@ -428,12 +440,96 @@ namespace CodeWalker.GameFiles
|
||||
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()
|
||||
{
|
||||
using var _ = new DisposableTimer("BuildBaseJenkIndex");
|
||||
Parallel.ForEach(AllRpfs, new ParallelOptions { MaxDegreeOfParallelism = 4 }, (file) =>
|
||||
Parallel.ForEach(AllRpfs, (file) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -475,24 +571,26 @@ namespace CodeWalker.GameFiles
|
||||
JenkIndex.EnsureLower(nameChildrenLod + 'a');
|
||||
JenkIndex.EnsureLower(nameChildrenLod + 'b');
|
||||
}
|
||||
var idx = name.LastIndexOf('_');
|
||||
if (idx > 0)
|
||||
{
|
||||
var str1 = name.Substring(0, idx);
|
||||
var idx2 = str1.LastIndexOf('_');
|
||||
if (idx2 > 0)
|
||||
{
|
||||
var str2 = str1.Substring(0, idx2);
|
||||
JenkIndex.EnsureLower(str2 + "_lod");
|
||||
var maxi = 100;
|
||||
for (int i = 1; i <= maxi; i++)
|
||||
{
|
||||
var str3 = str2 + '_' + i.ToString().PadLeft(2, '0') + "_lod";
|
||||
//JenkIndex.Ensure(str3);
|
||||
JenkIndex.EnsureLower(str3);
|
||||
}
|
||||
}
|
||||
}
|
||||
//var idx = name.LastIndexOf('_');
|
||||
//if (idx > 0)
|
||||
//{
|
||||
// var str1 = name.Substring(0, idx);
|
||||
// var idx2 = str1.LastIndexOf('_');
|
||||
// if (idx2 > 0)
|
||||
// {
|
||||
// var str2 = str1.Substring(0, idx2);
|
||||
// JenkIndex.EnsureLower(str2 + "_lod");
|
||||
// var maxi = 100;
|
||||
|
||||
// for (int i = 1; i <= maxi; i++)
|
||||
// {
|
||||
// var str3 = str2 + '_' + i.ToString().PadLeft(2, '0') + "_lod";
|
||||
// //JenkIndex.Ensure(str3);
|
||||
// JenkIndex.EnsureLower(str3);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
AddAllLods(name);
|
||||
}
|
||||
else if(name.EndsWith(".sps", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
@ -560,6 +658,7 @@ namespace CodeWalker.GameFiles
|
||||
catch(Exception err)
|
||||
{
|
||||
ErrorLog?.Invoke(err.ToString());
|
||||
Console.WriteLine(err.ToString());
|
||||
//failing silently!! not so good really
|
||||
}
|
||||
});
|
||||
@ -572,6 +671,14 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
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
|
||||
{
|
||||
LittleEndian,
|
||||
BigEndian
|
||||
LittleEndian = 0,
|
||||
BigEndian = 1,
|
||||
}
|
||||
|
||||
public enum DataType
|
||||
@ -64,16 +64,10 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
private Stream baseStream;
|
||||
|
||||
private readonly byte[] _buffer = new byte[8];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the endianess of the underlying stream.
|
||||
/// </summary>
|
||||
public Endianess Endianess
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public Endianess Endianess { get; set; } = Endianess.LittleEndian;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the underlying stream.
|
||||
@ -101,15 +95,19 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new data reader for the specified stream.
|
||||
/// </summary>
|
||||
public DataReader(Stream stream, Endianess endianess = Endianess.LittleEndian)
|
||||
public DataReader(Stream stream)
|
||||
{
|
||||
if (stream is not null)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -123,6 +121,25 @@ namespace CodeWalker.GameFiles
|
||||
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>
|
||||
/// Reads data from the underlying stream. This is the only method that directly accesses
|
||||
/// the data in the underlying stream.
|
||||
@ -187,7 +204,17 @@ namespace CodeWalker.GameFiles
|
||||
/// </summary>
|
||||
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>
|
||||
@ -195,7 +222,17 @@ namespace CodeWalker.GameFiles
|
||||
/// </summary>
|
||||
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>
|
||||
@ -203,7 +240,17 @@ namespace CodeWalker.GameFiles
|
||||
/// </summary>
|
||||
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>
|
||||
@ -211,7 +258,17 @@ namespace CodeWalker.GameFiles
|
||||
/// </summary>
|
||||
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>
|
||||
@ -219,7 +276,17 @@ namespace CodeWalker.GameFiles
|
||||
/// </summary>
|
||||
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>
|
||||
@ -227,7 +294,18 @@ namespace CodeWalker.GameFiles
|
||||
/// </summary>
|
||||
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>
|
||||
@ -235,7 +313,17 @@ namespace CodeWalker.GameFiles
|
||||
/// </summary>
|
||||
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>
|
||||
@ -243,12 +331,23 @@ namespace CodeWalker.GameFiles
|
||||
/// </summary>
|
||||
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>
|
||||
/// Reads a string.
|
||||
/// </summary>
|
||||
[SkipLocalsInit]
|
||||
unsafe public string ReadStringLength(int length)
|
||||
{
|
||||
if (length == 0)
|
||||
@ -268,47 +367,30 @@ namespace CodeWalker.GameFiles
|
||||
/// <summary>
|
||||
/// Reads a string.
|
||||
/// </summary>
|
||||
[SkipLocalsInit]
|
||||
unsafe public string ReadString(int maxLength = 1024)
|
||||
{
|
||||
var bytes = stackalloc byte[Math.Min(maxLength, 1024)];
|
||||
var chars = stackalloc char[Math.Min(maxLength, 1024)];
|
||||
Span<byte> bytes = stackalloc byte[Math.Min(maxLength, 1024)];
|
||||
Span<char> chars = stackalloc char[Math.Min(maxLength, 1024)];
|
||||
var temp = ReadByte();
|
||||
var charsRead = 0;
|
||||
while (temp != 0 && (Length == -1 || Position <= Length))
|
||||
var bytesRead = 0;
|
||||
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();
|
||||
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));
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -29,6 +29,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
@ -59,21 +60,33 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public static byte[] DecryptAESData(byte[] data, byte[] key, int length, int rounds = 1)
|
||||
{
|
||||
var rijndael = Rijndael.Create();
|
||||
rijndael.KeySize = 256;
|
||||
rijndael.Key = key;
|
||||
rijndael.BlockSize = 128;
|
||||
rijndael.Mode = CipherMode.ECB;
|
||||
rijndael.Padding = PaddingMode.None;
|
||||
using var aes = Aes.Create();
|
||||
aes.KeySize = 256;
|
||||
aes.Key = key;
|
||||
aes.BlockSize = 128;
|
||||
aes.Mode = CipherMode.ECB;
|
||||
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;
|
||||
|
||||
// decrypt...
|
||||
if (length > 0)
|
||||
{
|
||||
var decryptor = rijndael.CreateDecryptor();
|
||||
using var decryptorAes = aes.CreateDecryptor();
|
||||
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;
|
||||
@ -104,7 +117,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
|
||||
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint[][] GetNGKey(string name, uint length)
|
||||
{
|
||||
uint hash = GTA5Hash.CalculateHash(name);
|
||||
@ -112,36 +125,39 @@ namespace CodeWalker.GameFiles
|
||||
return GTA5Keys.PC_NG_KEYS[keyidx];
|
||||
}
|
||||
|
||||
|
||||
public static byte[] DecryptNG(byte[] data, string name, uint fileSize, int offset = 0, int? length = null)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void DecryptNG(byte[] data, string name, uint fileSize, int offset = 0, int? length = null)
|
||||
{
|
||||
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;
|
||||
fixed (byte* bptr = data)
|
||||
{
|
||||
for (int blockIndex = offset * 16; blockIndex < length / 16; blockIndex++)
|
||||
{
|
||||
DecryptNGBlock(bptr + 16 * blockIndex, key);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
DecryptNG(data.AsSpan(offset, length.Value), key);
|
||||
}
|
||||
|
||||
public unsafe static void DecryptNGBlock(byte[] data, uint[][] key)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void DecryptNG(Span<byte> data, uint[][] key)
|
||||
{
|
||||
fixed(byte* bptr = data)
|
||||
for (int blockIndex = 0; blockIndex < data.Length / 16; blockIndex++)
|
||||
{
|
||||
DecryptNGBlock(data, key);
|
||||
DecryptNGBlock(data.Slice(16 * blockIndex, 16), key);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe static void DecryptNGBlock(byte* data, uint[][] key)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void DecryptNGBlock(Span<byte> data, uint[][] key)
|
||||
{
|
||||
DecryptNGRoundA(data, key[0], GTA5Keys.PC_NG_DECRYPT_TABLES[0]);
|
||||
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]);
|
||||
}
|
||||
|
||||
public unsafe static void DecryptNGRoundA(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)
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void DecryptNGRoundA(Span<byte> data, uint[] key, uint[][] table)
|
||||
{
|
||||
var x1 =
|
||||
table[0][data[0]] ^
|
||||
@ -194,14 +194,16 @@ namespace CodeWalker.GameFiles
|
||||
table[15][data[15]] ^
|
||||
key[3];
|
||||
|
||||
*(uint*)data = x1;
|
||||
*(uint*)(data + 4) = x2;
|
||||
*(uint*)(data + 8) = x3;
|
||||
*(uint*)(data + 12) = x4;
|
||||
MemoryMarshal.Write(data.Slice(0, 4), ref x1);
|
||||
MemoryMarshal.Write(data.Slice(4, 4), ref x2);
|
||||
MemoryMarshal.Write(data.Slice(8, 4), ref x3);
|
||||
MemoryMarshal.Write(data.Slice(12, 4), ref x4);
|
||||
}
|
||||
|
||||
// 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 =
|
||||
table[0][data[0]] ^
|
||||
@ -228,10 +230,10 @@ namespace CodeWalker.GameFiles
|
||||
table[12][data[12]] ^
|
||||
key[3];
|
||||
|
||||
*(uint*)data = x1;
|
||||
*(uint*)(data + 4) = x2;
|
||||
*(uint*)(data + 8) = x3;
|
||||
*(uint*)(data + 12) = x4;
|
||||
MemoryMarshal.Write(data.Slice(0, 4), ref x1);
|
||||
MemoryMarshal.Write(data.Slice(4, 4), ref x2);
|
||||
MemoryMarshal.Write(data.Slice(8, 4), ref x3);
|
||||
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)
|
||||
{
|
||||
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.Compression;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
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);
|
||||
//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);
|
||||
var tabs = HashSearch.SearchHashes(exeStr, GTA5KeyHashes.PC_NG_KEY_HASHES, 272);
|
||||
PC_NG_KEYS = new uint[tabs.Length][][];
|
||||
@ -92,31 +94,21 @@ namespace CodeWalker.GameFiles
|
||||
}
|
||||
//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);
|
||||
//updateStatus("ng decrypt tables found");
|
||||
|
||||
updateStatus("Searching for NG hash lookup tables...");
|
||||
updateStatus?.Invoke("Searching for NG hash lookup tables...");
|
||||
// 17 rounds
|
||||
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 = 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);
|
||||
}
|
||||
}
|
||||
LoadPCNGDecryptTable(tabs);
|
||||
|
||||
PC_LUT = HashSearch.SearchHash(exeStr, GTA5KeyHashes.PC_LUT_HASH, 0x100);
|
||||
//updateStatus("ng hash LUTs found");
|
||||
|
||||
|
||||
|
||||
updateStatus("Calculating NG encryption tables...");
|
||||
updateStatus?.Invoke("Calculating NG encryption tables...");
|
||||
|
||||
PC_NG_ENCRYPT_TABLES = new uint[17][][];
|
||||
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]);
|
||||
//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]);
|
||||
//updateStatus("ng encrypt table 2 of 17 calculated");
|
||||
|
||||
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]);
|
||||
//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]);
|
||||
//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)
|
||||
{
|
||||
@ -175,10 +201,14 @@ namespace CodeWalker.GameFiles
|
||||
updateStatus?.Invoke("Complete.");
|
||||
}
|
||||
|
||||
|
||||
private static bool keysLoaded = false;
|
||||
|
||||
public static void LoadFromPath(string path = ".\\Keys", string key = null)
|
||||
{
|
||||
if (keysLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//PC_AES_KEY = File.ReadAllBytes(path + "\\gtav_aes_key.dat");
|
||||
//PC_NG_KEYS = CryptoIO.ReadNgKeys(path + "\\gtav_ng_key.dat");
|
||||
//PC_NG_DECRYPT_TABLES = CryptoIO.ReadNgTables(path + "\\gtav_ng_decrypt_tables.dat");
|
||||
@ -188,6 +218,7 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
//GenerateMagicData(path);
|
||||
UseMagicData(path, key);
|
||||
keysLoaded = true;
|
||||
}
|
||||
|
||||
public static void SaveToPath(string path = ".\\Keys")
|
||||
@ -298,7 +329,7 @@ namespace CodeWalker.GameFiles
|
||||
{
|
||||
using (MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream())
|
||||
{
|
||||
ds.CopyToFast(outstr);
|
||||
ds.CopyTo(outstr);
|
||||
b = outstr.GetBuffer();
|
||||
}
|
||||
}
|
||||
@ -760,11 +791,12 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public static byte[][] SearchHashes(Stream stream, IList<byte[]> hashes, int length = 32)
|
||||
{
|
||||
stream = Stream.Synchronized(stream);
|
||||
var result = new byte[hashes.Count][];
|
||||
|
||||
Parallel.For(0, (stream.Length / BLOCK_LENGTH), (long k) => {
|
||||
|
||||
var hashProvider = new SHA1CryptoServiceProvider();
|
||||
// TODO: Convert to stack alloc when length appropriate (1024 or lower probs)
|
||||
var buffer = new byte[length];
|
||||
for (long i = 0; i < (BLOCK_LENGTH / ALIGN_LENGTH); i++)
|
||||
{
|
||||
@ -772,11 +804,9 @@ namespace CodeWalker.GameFiles
|
||||
if (position >= stream.Length)
|
||||
continue;
|
||||
|
||||
lock (stream)
|
||||
{
|
||||
stream.Position = position;
|
||||
stream.Read(buffer, 0, length);
|
||||
}
|
||||
|
||||
stream.Position = position;
|
||||
stream.Read(buffer, 0, length);
|
||||
|
||||
var hash = hashProvider.ComputeHash(buffer);
|
||||
for (int j = 0; j < hashes.Count; j++)
|
||||
@ -852,7 +882,7 @@ namespace CodeWalker.GameFiles
|
||||
firstPivot.SetB();
|
||||
pivots.Add(firstPivot);
|
||||
|
||||
var buf_encrypted = new byte[16];
|
||||
Span<byte> buf_encrypted = stackalloc byte[16];
|
||||
for (int pivotIdx = 1; pivotIdx < 1024; pivotIdx++)
|
||||
{
|
||||
while (true)
|
||||
@ -1221,7 +1251,7 @@ namespace CodeWalker.GameFiles
|
||||
using (var fs = new FileStream(fileName, FileMode.Create))
|
||||
{
|
||||
ms.Position = 0;
|
||||
ms.CopyToFast(fs);
|
||||
ms.CopyTo(fs);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1308,7 +1338,7 @@ namespace CodeWalker.GameFiles
|
||||
using (var fs = new FileStream(fileName, FileMode.Create))
|
||||
{
|
||||
ms.Position = 0;
|
||||
ms.CopyToFast(fs);
|
||||
ms.CopyTo(fs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1446,7 +1476,7 @@ namespace CodeWalker.GameFiles
|
||||
using (var fs = new FileStream(fileName, FileMode.Create))
|
||||
{
|
||||
ms.Position = 0;
|
||||
ms.CopyToFast(fs);
|
||||
ms.CopyTo(fs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1463,6 +1493,7 @@ namespace CodeWalker.GameFiles
|
||||
LUT = GTA5Keys.PC_LUT;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint CalculateHash(string text)
|
||||
{
|
||||
/*
|
||||
|
@ -276,7 +276,8 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
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)
|
||||
{
|
||||
@ -293,7 +294,25 @@ namespace CodeWalker.GameFiles
|
||||
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)
|
||||
@ -302,6 +321,12 @@ namespace CodeWalker.GameFiles
|
||||
Ensure(str, hash);
|
||||
}
|
||||
|
||||
public static void EnsureLower(ReadOnlySpan<char> str)
|
||||
{
|
||||
uint hash = JenkHash.GenHashLower(str);
|
||||
Ensure(str, hash);
|
||||
}
|
||||
|
||||
public static void EnsureBoth(string str)
|
||||
{
|
||||
uint hash = JenkHash.GenHash(str);
|
||||
@ -312,25 +337,15 @@ namespace CodeWalker.GameFiles
|
||||
Ensure(str, hashLower);
|
||||
}
|
||||
}
|
||||
public static void AddRange(params string[] strings)
|
||||
|
||||
public static void EnsureBoth(ReadOnlySpan<char> str)
|
||||
{
|
||||
foreach(var s in strings)
|
||||
uint hash = JenkHash.GenHash(str);
|
||||
uint hashLower = JenkHash.GenHashLower(str);
|
||||
Ensure(str, hash);
|
||||
if (hash != hashLower)
|
||||
{
|
||||
uint hash = JenkHash.GenHash(s);
|
||||
if (hash == 0) continue;
|
||||
|
||||
Index[hash] = s;
|
||||
}
|
||||
}
|
||||
|
||||
public static void AddRangeLower(params string[] strings)
|
||||
{
|
||||
foreach (var s in strings)
|
||||
{
|
||||
uint hash = JenkHash.GenHashLower(s);
|
||||
if (hash == 0) continue;
|
||||
|
||||
Index[hash] = s;
|
||||
Ensure(str, hashLower);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,10 +196,6 @@ namespace CodeWalker.GameFiles
|
||||
var rel3 = XmlRel.GetRel(relxml);
|
||||
if (rel3 != null)
|
||||
{
|
||||
if (rel3.RelDatasSorted?.Length != rel.RelDatasSorted?.Length)
|
||||
{ } //check nothing went missing...
|
||||
|
||||
|
||||
data = rel3.Save(); //full roundtrip!
|
||||
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.Buffers;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.IO;
|
||||
@ -16,152 +17,45 @@ namespace CodeWalker.Core.Utils
|
||||
{
|
||||
return br.BaseStream.ReadAsync(buffer, index, count);
|
||||
}
|
||||
}
|
||||
|
||||
public ref struct SpanStream
|
||||
{
|
||||
public Span<byte> Buffer { get; private set; }
|
||||
private int _position;
|
||||
|
||||
public static void CopyToFast(this Stream stream, Stream destination)
|
||||
public SpanStream(Span<byte> buffer)
|
||||
{
|
||||
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);
|
||||
}
|
||||
Buffer = buffer;
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
public static async Task CopyToFastAsync(this Stream stream, Stream destination, int bufferSize = 131072, CancellationToken cancellationToken = default)
|
||||
private ReadOnlySpan<byte> InternalRead(int count)
|
||||
{
|
||||
var buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
|
||||
try
|
||||
int origPos = _position;
|
||||
int newPos = origPos + count;
|
||||
|
||||
if ((uint)newPos > (uint)Buffer.Length)
|
||||
{
|
||||
int bytesRead;
|
||||
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
||||
{
|
||||
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
_position = Buffer.Length;
|
||||
ThrowHelper.ThrowEndOfFileException();
|
||||
}
|
||||
|
||||
var span = Buffer.Slice(origPos, count);
|
||||
_position = newPos;
|
||||
return span;
|
||||
}
|
||||
|
||||
private static async Task FinishWriteAsync(Task writeTask, byte[] localBuffer)
|
||||
{
|
||||
try
|
||||
{
|
||||
await writeTask.ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(localBuffer);
|
||||
}
|
||||
}
|
||||
public short ReadInt16() => BinaryPrimitives.ReadInt16LittleEndian(InternalRead(sizeof(short)));
|
||||
|
||||
public static ValueTask WriteAsync(this Stream stream, Memory<byte> buffer, CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> array))
|
||||
{
|
||||
return new ValueTask(stream.WriteAsync(array.Array!, array.Offset, array.Count, cancellationToken));
|
||||
}
|
||||
public ushort ReadUInt16() => BinaryPrimitives.ReadUInt16LittleEndian(InternalRead(sizeof(ushort)));
|
||||
|
||||
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
||||
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)
|
||||
{
|
||||
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
||||
try
|
||||
{
|
||||
buffer.CopyTo(sharedBuffer);
|
||||
stream.Write(sharedBuffer, 0, buffer.Length);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
public int ReadInt32() => BinaryPrimitives.ReadInt32LittleEndian(InternalRead(sizeof(int)));
|
||||
public uint ReadUInt32() => BinaryPrimitives.ReadUInt32LittleEndian(InternalRead(sizeof(uint)));
|
||||
public long ReadInt64() => BinaryPrimitives.ReadInt64LittleEndian(InternalRead(sizeof(long)));
|
||||
public ulong ReadUInt64() => BinaryPrimitives.ReadUInt64LittleEndian(InternalRead(sizeof(ulong)));
|
||||
public unsafe Half ReadHalf() => BinaryPrimitives.ReadHalfLittleEndian(InternalRead(sizeof(Half)));
|
||||
public unsafe float ReadSingle() => BinaryPrimitives.ReadSingleLittleEndian(InternalRead(sizeof(float)));
|
||||
public unsafe double ReadDouble() => BinaryPrimitives.ReadDoubleLittleEndian(InternalRead(sizeof(double)));
|
||||
}
|
||||
}
|
||||
|
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 SharpDX;
|
||||
using Color = SharpDX.Color;
|
||||
using Half = SharpDX.Half;
|
||||
|
||||
namespace CodeWalker
|
||||
{
|
||||
@ -86,24 +87,39 @@ namespace CodeWalker
|
||||
|
||||
|
||||
|
||||
public static string GetUTF8Text(byte[] bytes)
|
||||
public static string GetUTF8Text(Span<byte> bytes)
|
||||
{
|
||||
if (bytes == null)
|
||||
{ return string.Empty; } //file not found..
|
||||
var start = 0;
|
||||
var length = bytes.Length;
|
||||
if (bytes == null || bytes.Length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
} //file not found..
|
||||
if ((bytes.Length > 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF))
|
||||
{
|
||||
start = 3;
|
||||
length = bytes.Length - 3;
|
||||
bytes = bytes.Slice(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
foreach(var searchString in strings)
|
||||
|
@ -33,8 +33,7 @@ namespace CodeWalker.World
|
||||
|
||||
List<AudioPlacement> placements = new List<AudioPlacement>();
|
||||
|
||||
GameFileCache.AudioDatRelFilesLock.EnterReadLock();
|
||||
try
|
||||
if (GameFileCache.AudioDatRelFiles != null)
|
||||
{
|
||||
foreach (var relfile in GameFileCache.AudioDatRelFiles)
|
||||
{
|
||||
@ -47,10 +46,6 @@ namespace CodeWalker.World
|
||||
PlacementsDict[relfile] = placements.ToArray();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
GameFileCache.AudioDatRelFilesLock.ExitReadLock();
|
||||
}
|
||||
|
||||
AllItems.AddRange(Zones);
|
||||
AllItems.AddRange(Emitters);
|
||||
|
@ -44,13 +44,13 @@ namespace CodeWalker.World
|
||||
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());
|
||||
Init(hash, gfc);
|
||||
await InitAsync(hash, gfc);
|
||||
Name = name;
|
||||
}
|
||||
public void Init(MetaHash pedhash, GameFileCache gfc)
|
||||
public async ValueTask InitAsync(MetaHash pedhash, GameFileCache gfc)
|
||||
{
|
||||
|
||||
Name = string.Empty;
|
||||
@ -106,11 +106,11 @@ namespace CodeWalker.World
|
||||
RpfFileEntry clothFile = null;
|
||||
if (ClothFilesDict?.TryGetValue(pedhash, out clothFile) ?? false)
|
||||
{
|
||||
Yld = gfc.GetFileUncached<YldFile>(clothFile);
|
||||
Yld = await gfc.GetFileUncachedAsync<YldFile>(clothFile);
|
||||
while ((Yld != null) && (!Yld.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(Yld);
|
||||
await Task.Delay(1);//kinda hacky
|
||||
await gfc.TryLoadEnqueue(Yld);
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,27 +118,27 @@ namespace CodeWalker.World
|
||||
|
||||
while ((Ydd != null) && (!Ydd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
await Task.Delay(1);//kinda hacky
|
||||
Ydd = gfc.GetYdd(pedhash);
|
||||
}
|
||||
while ((Ytd != null) && (!Ytd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
await Task.Delay(1);//kinda hacky
|
||||
Ytd = gfc.GetYtd(pedhash);
|
||||
}
|
||||
while ((Ycd != null) && (!Ycd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
await Task.Delay(1);//kinda hacky
|
||||
Ycd = gfc.GetYcd(ycdhash);
|
||||
}
|
||||
while ((Yed != null) && (!Yed.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
await Task.Delay(1);//kinda hacky
|
||||
Yed = gfc.GetYed(yedhash);
|
||||
}
|
||||
while ((Yft != null) && (!Yft.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
await Task.Delay(1);//kinda hacky
|
||||
Yft = gfc.GetYft(pedhash);
|
||||
}
|
||||
|
||||
@ -150,7 +150,7 @@ namespace CodeWalker.World
|
||||
Ycd?.ClipMap?.TryGetValue(cliphash, out cme);
|
||||
AnimClip = cme;
|
||||
|
||||
var exprhash = JenkHash.GenHash(initdata.ExpressionName.ToLowerInvariant());
|
||||
var exprhash = JenkHash.GenHashLower(initdata.ExpressionName);
|
||||
Expression expr = null;
|
||||
Yed?.ExprMap?.TryGetValue(exprhash, out 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))
|
||||
{
|
||||
@ -174,7 +174,7 @@ namespace CodeWalker.World
|
||||
return;
|
||||
}
|
||||
|
||||
MetaHash namehash = JenkHash.GenHash(name.ToLowerInvariant());
|
||||
MetaHash namehash = JenkHash.GenHashLower(name);
|
||||
Drawable d = null;
|
||||
if (Ydd?.Dict != null)
|
||||
{
|
||||
@ -185,11 +185,11 @@ namespace CodeWalker.World
|
||||
RpfFileEntry file = null;
|
||||
if (DrawableFilesDict.TryGetValue(namehash, out file))
|
||||
{
|
||||
var ydd = gfc.GetFileUncached<YddFile>(file);
|
||||
var ydd = await gfc.GetFileUncachedAsync<YddFile>(file);
|
||||
while ((ydd != null) && (!ydd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(ydd);
|
||||
await Task.Delay(1);//kinda hacky
|
||||
await gfc.TryLoadEnqueue(ydd);
|
||||
}
|
||||
if (ydd?.Drawables?.Length > 0)
|
||||
{
|
||||
@ -209,11 +209,11 @@ namespace CodeWalker.World
|
||||
RpfFileEntry file = null;
|
||||
if (TextureFilesDict.TryGetValue(texhash, out file))
|
||||
{
|
||||
var ytd = gfc.GetFileUncached<YtdFile>(file);
|
||||
var ytd = await gfc.GetFileUncachedAsync<YtdFile>(file);
|
||||
while ((ytd != null) && (!ytd.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(ytd);
|
||||
await Task.Delay(1);//kinda hacky
|
||||
await gfc.TryLoadEnqueue(ytd);
|
||||
}
|
||||
if (ytd?.TextureDict?.Textures?.data_items.Length > 0)
|
||||
{
|
||||
@ -232,11 +232,11 @@ namespace CodeWalker.World
|
||||
RpfFileEntry file = null;
|
||||
if (ClothFilesDict.TryGetValue(namehash, out file))
|
||||
{
|
||||
var yld = gfc.GetFileUncached<YldFile>(file);
|
||||
var yld = await gfc.GetFileUncachedAsync<YldFile>(file);
|
||||
while ((yld != null) && (!yld.Loaded))
|
||||
{
|
||||
Thread.Sleep(1);//kinda hacky
|
||||
gfc.TryLoadEnqueue(yld);
|
||||
await Task.Delay(1);//kinda hacky
|
||||
await gfc.TryLoadEnqueue(yld);
|
||||
}
|
||||
if (yld?.ClothDictionary?.Clothes?.data_items?.Length > 0)
|
||||
{
|
||||
@ -266,7 +266,7 @@ namespace CodeWalker.World
|
||||
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;
|
||||
if (vi != null)
|
||||
@ -279,17 +279,17 @@ namespace CodeWalker.World
|
||||
{
|
||||
var name = item?.GetDrawableName(alt);
|
||||
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++)
|
||||
{
|
||||
SetComponentDrawable(i, 0, 0, 0, gfc);
|
||||
await SetComponentDrawableAsync(i, 0, 0, 0, gfc);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>CWPeds.ico</ApplicationIcon>
|
||||
<Copyright>dexyfex</Copyright>
|
||||
@ -10,18 +9,13 @@
|
||||
<Authors>dexyfex</Authors>
|
||||
<AssemblyName>CodeWalker Ped Viewer</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CodeWalker\CodeWalker.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,8 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ApplicationIcon>CWRPFExplorer.ico</ApplicationIcon>
|
||||
@ -10,23 +9,18 @@
|
||||
<Company>dexyfex software</Company>
|
||||
<Authors>dexyfex</Authors>
|
||||
<AssemblyName>CodeWalker RPF Explorer</AssemblyName>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CodeWalker\CodeWalker.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,17 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<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.runner.visualstudio" Version="2.4.3">
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
@ -22,9 +17,7 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj" />
|
||||
</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.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace CodeWalker.Test
|
||||
{
|
||||
@ -122,6 +124,11 @@ namespace CodeWalker.Test
|
||||
|
||||
public class TestBinaryConversions
|
||||
{
|
||||
private readonly ITestOutputHelper _output;
|
||||
public TestBinaryConversions(ITestOutputHelper testOutputHelper)
|
||||
{
|
||||
_output = testOutputHelper;
|
||||
}
|
||||
[Fact]
|
||||
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,28 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ApplicationIcon>CWVehicles.ico</ApplicationIcon>
|
||||
<Copyright>dexyfex</Copyright>
|
||||
<Company>dexyfex software</Company>
|
||||
<Authors>dexyfex</Authors>
|
||||
<AssemblyName>CodeWalker Vehicle Viewer</AssemblyName>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CodeWalker\CodeWalker.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -1,24 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<UseWPF>true</UseWPF>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<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.Mathematics" Version="4.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -249,22 +249,34 @@ namespace CodeWalker
|
||||
ofd.InitialDirectory = fbd.SelectedPath;
|
||||
|
||||
int result = 0;
|
||||
var ns = "System.Windows.Forms";
|
||||
var asmb = Assembly.GetAssembly(typeof(OpenFileDialog));
|
||||
var dialogint = GetType(asmb, ns, "FileDialogNative.IFileDialog");
|
||||
var ns = "MS.Internal.AppModel";
|
||||
var asmb = Assembly.Load("System.Windows.Forms.Primitives");
|
||||
//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");
|
||||
Call(typeof(OpenFileDialog), ofd, "OnBeforeVistaDialog", dialog);
|
||||
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);
|
||||
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 };
|
||||
Call(dialogint, dialog, "Advise", parameters);
|
||||
var adviseres = Convert.ToUInt32(parameters[1]);
|
||||
try { result = Convert.ToInt32(Call(dialogint, dialog, "Show", hWndOwner)); }
|
||||
finally { Call(dialogint, dialog, "Unadvise", adviseres); }
|
||||
try {
|
||||
result = Convert.ToInt32(Call(dialogint, dialog, "Show", hWndOwner));
|
||||
}
|
||||
finally {
|
||||
//pfde.Dispose();
|
||||
Call(dialogint, dialog, "Unadvise", adviseres);
|
||||
}
|
||||
GC.KeepAlive(pfde);
|
||||
|
||||
|
||||
|
||||
fbd.SelectedPath = ofd.FileName;
|
||||
|
||||
return (result == 0) ? DialogResult.OK : DialogResult.Cancel;
|
||||
@ -296,12 +308,33 @@ namespace CodeWalker
|
||||
if (mi == null) return null;
|
||||
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)
|
||||
{
|
||||
var type = GetType(asmb, ns, typeName);
|
||||
var fieldInfo = type.GetField(name);
|
||||
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)
|
||||
{
|
||||
var type = GetType(asmb, ns, name);
|
||||
|
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.7.34031.279
|
||||
@ -25,7 +25,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeWalker.Vehicles", "Code
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeWalker.Test", "CodeWalker.Test\CodeWalker.Test.csproj", "{067FF87E-CA79-4B29-BCF6-11622999EDC6}"
|
||||
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
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -151,27 +151,6 @@
|
||||
<setting name="DLC" serializeAs="String">
|
||||
<value />
|
||||
</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">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
@ -250,6 +229,26 @@
|
||||
<setting name="AntiAliasing" serializeAs="String">
|
||||
<value>2</value>
|
||||
</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>
|
||||
</userSettings>
|
||||
<runtime>
|
||||
|
@ -1,31 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ApplicationIcon>CW.ico</ApplicationIcon>
|
||||
<Copyright>dexyfex</Copyright>
|
||||
<Company>dexyfex software</Company>
|
||||
<Authors>dexyfex</Authors>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<Nullable>annotations</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
|
||||
<PackageReference Include="DirectXTexNet" Version="1.0.1" />
|
||||
<PackageReference Include="DirectXTexNet" Version="1.0.3" />
|
||||
<PackageReference Include="DockPanelSuite.ThemeVS2015" Version="3.1.0" />
|
||||
<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="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.D3DCompiler" 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.XAudio2" 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>
|
||||
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj" />
|
||||
<ProjectReference Include="..\CodeWalker.WinForms\CodeWalker.WinForms.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Windows.Forms.DataVisualization" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Settings.Designer.cs">
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
@ -52,12 +49,10 @@
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Properties\Settings.settings">
|
||||
<Generator>PublicSettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -8,7 +8,6 @@ using CodeWalker.Core.Utils;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
@ -19,13 +18,10 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using WeifenLuo.WinFormsUI.Docking;
|
||||
using System.Runtime.CompilerServices;
|
||||
using static CodeWalker.GameFiles.GameFileCache;
|
||||
|
||||
using CodeWalker.WinForms;
|
||||
using Newtonsoft.Json;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace CodeWalker
|
||||
{
|
||||
@ -34,15 +30,15 @@ namespace CodeWalker
|
||||
private volatile bool Ready = 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();
|
||||
|
||||
public MainTreeFolder RootFolder;
|
||||
public MainTreeFolder? RootFolder;
|
||||
public List<MainTreeFolder> ExtraRootFolders = new List<MainTreeFolder>();
|
||||
public MainTreeFolder CurrentFolder;
|
||||
public List<MainListItem> CurrentFiles;
|
||||
public MainTreeFolder? CurrentFolder;
|
||||
public List<MainListItem>? CurrentFiles;
|
||||
private bool FirstRefreshed = false;
|
||||
private List<MainListItem> CopiedFiles = new List<MainListItem>();
|
||||
|
||||
@ -57,17 +53,17 @@ namespace CodeWalker
|
||||
public volatile bool Searching = false;
|
||||
private MainTreeFolder SearchResults;
|
||||
|
||||
private List<RpfFile> AllRpfs { get; set; }
|
||||
private GameFileCache FileCache { get; set; }
|
||||
private object FileCacheSyncRoot = new object();
|
||||
private List<RpfFile>? AllRpfs { get; set; }
|
||||
private static GameFileCache FileCache => GameFileCacheFactory.Instance;
|
||||
private readonly object FileCacheSyncRoot = new object();
|
||||
|
||||
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 static event Action ForceTreeRefresh;
|
||||
public static event Action? ForceTreeRefresh;
|
||||
|
||||
static ExploreForm()
|
||||
{
|
||||
@ -76,8 +72,11 @@ namespace CodeWalker
|
||||
|
||||
public ExploreForm()
|
||||
{
|
||||
ETWEvents.Log.CreatingForm(nameof(ExploreForm));
|
||||
Instance = this;
|
||||
SuspendLayout();
|
||||
InitializeComponent();
|
||||
ResumeLayout();
|
||||
|
||||
SetTheme(Settings.Default.ExplorerWindowTheme, false);
|
||||
|
||||
@ -170,11 +169,13 @@ namespace CodeWalker
|
||||
var folderPath = folder?.Trim();
|
||||
if (!string.IsNullOrEmpty(folderPath))
|
||||
{
|
||||
var root = new MainTreeFolder();
|
||||
root.FullPath = folderPath;
|
||||
root.Path = folderPath;
|
||||
root.Name = Path.GetFileName(Path.GetDirectoryName(folderPath));
|
||||
root.IsExtraFolder = true;
|
||||
var root = new MainTreeFolder
|
||||
{
|
||||
FullPath = folderPath,
|
||||
Path = folderPath,
|
||||
Name = Path.GetFileName(Path.GetDirectoryName(folderPath)) ?? folderPath,
|
||||
IsExtraFolder = true
|
||||
};
|
||||
ExtraRootFolders.Add(root);
|
||||
}
|
||||
}
|
||||
@ -185,29 +186,28 @@ namespace CodeWalker
|
||||
var extrafolders = new StringBuilder();
|
||||
foreach (var folder in ExtraRootFolders)
|
||||
{
|
||||
if (extrafolders.Length > 0) extrafolders.Append("\n");
|
||||
extrafolders.Append(folder.FullPath);
|
||||
extrafolders.AppendLine(folder.FullPath);
|
||||
}
|
||||
Settings.Default.RPFExplorerExtraFolders = extrafolders.ToString();
|
||||
|
||||
Settings.Default.Save();
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(FileCache))]
|
||||
private void Init()
|
||||
{
|
||||
ETWEvents.Log.LoadingForm(nameof(ExploreForm));
|
||||
//called from ExploreForm_Load
|
||||
|
||||
// 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
|
||||
// here for now to make sure
|
||||
if(!GTAFolder.UpdateGTAFolder(true))
|
||||
if (!GTAFolder.UpdateGTAFolder(true))
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
throw new Exception("No GTA Folder found!");
|
||||
}
|
||||
|
||||
FileCache = GameFileCacheFactory.GetInstance();
|
||||
|
||||
new Task(async () =>
|
||||
{
|
||||
try
|
||||
@ -271,6 +271,7 @@ namespace CodeWalker
|
||||
{
|
||||
UpdateStatus?.Invoke("Loading file cache...");
|
||||
var allRpfs = AllRpfs;
|
||||
|
||||
FileCache.Init(updateStatus: null, ErrorLog, allRpfs); //inits main dicts and archetypes only...
|
||||
|
||||
UpdateStatus?.Invoke("Loading materials...");
|
||||
@ -299,9 +300,10 @@ namespace CodeWalker
|
||||
return FileCache; //return it even though it's probably not inited yet..
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(FileTypes))]
|
||||
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("", "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_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)
|
||||
{
|
||||
EnsureFileTypesInitialized();
|
||||
FileTypes ??= new Dictionary<string, FileTypeInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
var ft = new FileTypeInfo(ext, name, imgidx, defaultAction, xmlConvertible);
|
||||
FileTypes[ext] = ft;
|
||||
}
|
||||
|
||||
private static void InitSubFileType(string ext, string subext, string name, int imgidx, FileTypeAction defaultAction = FileTypeAction.ViewHex, bool xmlConvertible = false)
|
||||
{
|
||||
FileTypeInfo pti = null;
|
||||
if (FileTypes.TryGetValue(ext, out pti))
|
||||
EnsureFileTypesInitialized();
|
||||
if (FileTypes.TryGetValue(ext, out var pti))
|
||||
{
|
||||
var ft = new FileTypeInfo(subext, name, imgidx, defaultAction, xmlConvertible);
|
||||
pti.AddSubType(ft);
|
||||
@ -377,6 +392,7 @@ namespace CodeWalker
|
||||
}
|
||||
public static FileTypeInfo GetFileType(string fn)
|
||||
{
|
||||
EnsureFileTypesInitialized();
|
||||
if (fn.IndexOfAny(InvalidFileNameChars) != -1)
|
||||
{
|
||||
return FileTypes[""];
|
||||
@ -402,7 +418,7 @@ namespace CodeWalker
|
||||
}
|
||||
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!
|
||||
return ft;
|
||||
}
|
||||
@ -461,10 +477,11 @@ namespace CodeWalker
|
||||
}
|
||||
|
||||
|
||||
public void Navigate(MainTreeFolder f)
|
||||
public void Navigate(MainTreeFolder? f)
|
||||
{
|
||||
if (!Ready) return;
|
||||
if (f == CurrentFolder) return; //already there!
|
||||
ArgumentNullException.ThrowIfNull(f);
|
||||
if (f.IsSearchResults)
|
||||
{
|
||||
AddMainTreeViewRoot(f); //add the current search result node
|
||||
@ -477,8 +494,7 @@ namespace CodeWalker
|
||||
|
||||
foreach (TreeNode tn in MainTreeView.Nodes)
|
||||
{
|
||||
var tnf = tn.Tag as MainTreeFolder;
|
||||
if ((tn != sr) && (tnf != null) && (tnf.IsSearchResults))
|
||||
if ((tn != sr) && (tn.Tag is MainTreeFolder tnf) && (tnf.IsSearchResults))
|
||||
{
|
||||
MainTreeView.Nodes.Remove(tn); //remove existing search result node
|
||||
break;
|
||||
@ -494,7 +510,7 @@ namespace CodeWalker
|
||||
hierarchy.Add(pf);
|
||||
pf = pf.Parent;
|
||||
}
|
||||
TreeNode n = null;
|
||||
TreeNode? n = null;
|
||||
for (int i = hierarchy.Count - 1; i >= 0; i--)
|
||||
{
|
||||
n = FindTreeNode(hierarchy[i], n);
|
||||
@ -516,9 +532,10 @@ namespace CodeWalker
|
||||
{
|
||||
if (!Ready) return;
|
||||
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);
|
||||
TreeNode n = MainTreeView.Nodes[0];// FindTreeNode("gta v", null);
|
||||
TreeNode? n = MainTreeView.Nodes[0];// FindTreeNode("gta v", null);
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
{
|
||||
for (int i = 0; i < hierarchy.Length; i++)
|
||||
@ -565,13 +582,13 @@ namespace CodeWalker
|
||||
EditModeButton.Enabled = true;
|
||||
}
|
||||
|
||||
public void GoUp(MainTreeFolder toFolder = null)
|
||||
public void GoUp(MainTreeFolder? toFolder = null)
|
||||
{
|
||||
var fld = (toFolder == null) ? CurrentFolder?.Parent : toFolder;
|
||||
if (fld == null) return;
|
||||
Navigate(fld);
|
||||
}
|
||||
public void GoBack(MainTreeFolder toFolder = null)
|
||||
public void GoBack(MainTreeFolder? toFolder = null)
|
||||
{
|
||||
if (BackSteps.Count == 0) return;
|
||||
var s = BackSteps.Pop();
|
||||
@ -586,7 +603,7 @@ namespace CodeWalker
|
||||
HistoryNavigating = false;
|
||||
UpdateHistoryUI();
|
||||
}
|
||||
public void GoForward(MainTreeFolder toFolder = null)
|
||||
public void GoForward(MainTreeFolder? toFolder = null)
|
||||
{
|
||||
if (ForwardSteps.Count == 0) return;
|
||||
var s = ForwardSteps.Pop();
|
||||
@ -611,6 +628,7 @@ namespace CodeWalker
|
||||
{
|
||||
var button = UpButton.DropDownItems.Add(pf.GetToolText());
|
||||
button.Tag = pf;
|
||||
|
||||
button.Click += UpListButton_Click;
|
||||
pf = pf.Parent;
|
||||
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;
|
||||
foreach (TreeNode node in tnc)
|
||||
@ -721,7 +739,7 @@ namespace CodeWalker
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private TreeNode FindTreeNode(string text, TreeNode parent)
|
||||
private TreeNode? FindTreeNode(string text, TreeNode? parent)
|
||||
{
|
||||
var tnc = (parent != null) ? parent.Nodes : MainTreeView.Nodes;
|
||||
foreach (TreeNode node in tnc)
|
||||
@ -735,7 +753,8 @@ namespace CodeWalker
|
||||
}
|
||||
|
||||
|
||||
|
||||
[MemberNotNull(nameof(RootFolder))]
|
||||
[MemberNotNull(nameof(AllRpfs))]
|
||||
private async Task RefreshMainTreeView()
|
||||
{
|
||||
using var _ = new DisposableTimer("RefreshMainTreeView");
|
||||
@ -747,15 +766,18 @@ namespace CodeWalker
|
||||
UpdateStatus?.Invoke("Scanning...");
|
||||
|
||||
|
||||
var root = new MainTreeFolder();
|
||||
root.FullPath = GTAFolder.GetCurrentGTAFolderWithTrailingSlash();
|
||||
root.Path = "";
|
||||
root.Name = "GTA V";
|
||||
var root = new MainTreeFolder
|
||||
{
|
||||
FullPath = GTAFolder.GetCurrentGTAFolderWithTrailingSlash(),
|
||||
Path = "",
|
||||
Name = "GTA V"
|
||||
};
|
||||
RootFolder = root;
|
||||
|
||||
var tasks = new List<Task<TreeNode>>();
|
||||
|
||||
tasks.Add(Task.Run(() => RefreshMainTreeViewRoot(root, true)));
|
||||
var tasks = new List<Task<TreeNode>>
|
||||
{
|
||||
Task.Run(() => RefreshMainTreeViewRoot(root, true))
|
||||
};
|
||||
|
||||
|
||||
var remFolders = new List<MainTreeFolder>();
|
||||
@ -791,6 +813,7 @@ namespace CodeWalker
|
||||
|
||||
BeginInvoke(() =>
|
||||
{
|
||||
SuspendLayout();
|
||||
MainTreeView.BeginUpdate();
|
||||
ClearMainTreeView();
|
||||
|
||||
@ -799,6 +822,7 @@ namespace CodeWalker
|
||||
Ready = true;
|
||||
|
||||
MainTreeView.EndUpdate();
|
||||
ResumeLayout();
|
||||
MainTreeViewRefreshComplete();
|
||||
});
|
||||
|
||||
@ -889,6 +913,7 @@ namespace CodeWalker
|
||||
|
||||
if (rpf.LastException != null) //incase of corrupted rpf (or renamed NG encrypted RPF)
|
||||
{
|
||||
Console.WriteLine(rpf.LastException);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1141,29 +1166,35 @@ namespace CodeWalker
|
||||
}
|
||||
private MainTreeFolder CreateRpfTreeFolder(RpfFile rpf, string relpath, string fullpath)
|
||||
{
|
||||
var node = new MainTreeFolder();
|
||||
node.RpfFile = rpf;
|
||||
node.RpfFolder = rpf.Root;
|
||||
node.Name = rpf.Name;
|
||||
node.Path = relpath;
|
||||
node.FullPath = fullpath;
|
||||
var node = new MainTreeFolder
|
||||
{
|
||||
RpfFile = rpf,
|
||||
RpfFolder = rpf.Root,
|
||||
Name = rpf.Name,
|
||||
Path = relpath,
|
||||
FullPath = fullpath,
|
||||
};
|
||||
return node;
|
||||
}
|
||||
private MainTreeFolder CreateRpfDirTreeFolder(RpfDirectoryEntry dir, string relpath, string fullpath)
|
||||
{
|
||||
var node = new MainTreeFolder();
|
||||
node.RpfFolder = dir;
|
||||
node.Name = dir.Name;
|
||||
node.Path = relpath;
|
||||
node.FullPath = fullpath;
|
||||
var node = new MainTreeFolder
|
||||
{
|
||||
RpfFolder = dir,
|
||||
Name = dir.Name,
|
||||
Path = relpath,
|
||||
FullPath = fullpath,
|
||||
};
|
||||
return node;
|
||||
}
|
||||
private MainTreeFolder CreateRootDirTreeFolder(string name, string path, string fullpath)
|
||||
{
|
||||
var node = new MainTreeFolder();
|
||||
node.Name = name;
|
||||
node.Path = path;
|
||||
node.FullPath = fullpath;
|
||||
var node = new MainTreeFolder
|
||||
{
|
||||
Name = name,
|
||||
Path = path,
|
||||
FullPath = fullpath,
|
||||
};
|
||||
return node;
|
||||
}
|
||||
private void RenameTreeFolder(MainTreeFolder f, string newname)
|
||||
@ -1299,6 +1330,8 @@ namespace CodeWalker
|
||||
{
|
||||
ForceTreeRefresh?.Invoke();
|
||||
}
|
||||
|
||||
|
||||
private void RefreshMainListView()
|
||||
{
|
||||
MainListView.VirtualListSize = 0;
|
||||
@ -1377,11 +1410,13 @@ namespace CodeWalker
|
||||
SearchGlobalButton.Checked = true;
|
||||
SearchFilterButton.Checked = false;
|
||||
|
||||
SearchResults = new MainTreeFolder();
|
||||
SearchResults.Name = "Search Results: " + text;
|
||||
SearchResults.Path = SearchResults.Name;
|
||||
SearchResults.IsSearchResults = true;
|
||||
SearchResults.SearchTerm = text;
|
||||
SearchResults = new MainTreeFolder
|
||||
{
|
||||
Name = "Search Results: " + text,
|
||||
Path = "Search Results: " + text,
|
||||
IsSearchResults = true,
|
||||
SearchTerm = text,
|
||||
};
|
||||
|
||||
Navigate(SearchResults);
|
||||
|
||||
@ -1389,7 +1424,7 @@ namespace CodeWalker
|
||||
MainListView.SetSortIcon(SortColumnIndex, SortDirection);
|
||||
MainListView.VirtualListSize = 0;
|
||||
|
||||
CurrentFiles.Clear();
|
||||
CurrentFiles?.Clear();
|
||||
|
||||
UpdateStatus?.Invoke("Searching...");
|
||||
|
||||
@ -1401,7 +1436,7 @@ namespace CodeWalker
|
||||
|
||||
Cursor = Cursors.WaitCursor;
|
||||
|
||||
var resultcount = RootFolder.Search(term, this);
|
||||
var resultcount = RootFolder?.Search(term, this) ?? 0;
|
||||
|
||||
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.ListItems != CurrentFiles) return;
|
||||
@ -2415,8 +2450,8 @@ 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();
|
||||
shaders.Sort((a, b) => { return b.GeomCount.CompareTo(a.GeomCount); });
|
||||
@ -3691,11 +3726,13 @@ namespace CodeWalker
|
||||
if (folder.FullPath == folderPath) return;
|
||||
}
|
||||
|
||||
var root = new MainTreeFolder();
|
||||
root.FullPath = folderPath;
|
||||
root.Path = folderPath;
|
||||
root.Name = Path.GetFileName(Path.GetDirectoryName(folderPath));
|
||||
root.IsExtraFolder = true;
|
||||
var root = new MainTreeFolder
|
||||
{
|
||||
FullPath = folderPath,
|
||||
Path = folderPath,
|
||||
Name = Path.GetFileName(Path.GetDirectoryName(folderPath)),
|
||||
IsExtraFolder = true,
|
||||
};
|
||||
ExtraRootFolders.Add(root);
|
||||
|
||||
Task.Run(() =>
|
||||
@ -4586,13 +4623,13 @@ namespace CodeWalker
|
||||
|
||||
private void ToolsBinSearchMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
BinarySearchForm f = new BinarySearchForm(GetFileCache());
|
||||
BinarySearchForm f = new BinarySearchForm();
|
||||
f.Show(this);
|
||||
}
|
||||
|
||||
private void ToolsAudioExplorerMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
AudioExplorerForm f = new AudioExplorerForm(GetFileCache());
|
||||
AudioExplorerForm f = new AudioExplorerForm();
|
||||
f.Show(this);
|
||||
}
|
||||
|
||||
@ -4604,7 +4641,7 @@ namespace CodeWalker
|
||||
|
||||
private void ToolsJenkIndMenu_Click(object sender, EventArgs e)
|
||||
{
|
||||
JenkIndForm f = new JenkIndForm(GetFileCache());
|
||||
JenkIndForm f = new JenkIndForm();
|
||||
f.Show(this);
|
||||
}
|
||||
|
||||
@ -4632,9 +4669,9 @@ namespace CodeWalker
|
||||
|
||||
public class MainTreeFolder
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public required string Name { get; set; }
|
||||
|
||||
private string _nameLower;
|
||||
private string? _nameLower;
|
||||
public string NameLower
|
||||
{
|
||||
get
|
||||
@ -4646,20 +4683,20 @@ namespace CodeWalker
|
||||
_nameLower = value;
|
||||
}
|
||||
}
|
||||
public string Path { get; set; }
|
||||
public string FullPath { get; set; }
|
||||
public RpfFile RpfFile { get; set; }
|
||||
public RpfDirectoryEntry RpfFolder { get; set; }
|
||||
public HashSet<string> Files { get; set; }
|
||||
public required string Path { get; set; }
|
||||
public string? FullPath { get; set; }
|
||||
public RpfFile? RpfFile { get; set; }
|
||||
public RpfDirectoryEntry? RpfFolder { get; set; }
|
||||
public HashSet<string>? Files { get; set; }
|
||||
private object filesLock = new object();
|
||||
public MainTreeFolder Parent { get; set; }
|
||||
public List<MainTreeFolder> Children { get; set; }
|
||||
private object childrenLock = new object();
|
||||
public List<MainListItem> ListItems { get; set; }
|
||||
public TreeNode TreeNode { get; set; }
|
||||
public bool IsSearchResults { get; set; }
|
||||
public string SearchTerm { get; set; }
|
||||
public bool IsExtraFolder { get; set; }
|
||||
public MainTreeFolder? Parent { get; set; }
|
||||
public List<MainTreeFolder>? Children { get; set; }
|
||||
private readonly object childrenLock = new object();
|
||||
public List<MainListItem>? ListItems { get; set; }
|
||||
public TreeNode? TreeNode { get; set; }
|
||||
public bool IsSearchResults { get; set; } = false;
|
||||
public string? SearchTerm { get; set; }
|
||||
public bool IsExtraFolder { get; set; } = false;
|
||||
|
||||
public void AddFile(string file)
|
||||
{
|
||||
|
@ -401,7 +401,7 @@ namespace CodeWalker.Forms
|
||||
{
|
||||
Stream wavStream = audio.GetWavStream();
|
||||
FileStream stream = File.Create(saveFileDialog.FileName);
|
||||
wavStream.CopyToFast(stream);
|
||||
wavStream.CopyTo(stream);
|
||||
stream.Close();
|
||||
wavStream.Close();
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ namespace CodeWalker.Forms
|
||||
List<VertexTypePC> gridVerts = new List<VertexTypePC>();
|
||||
object gridSyncRoot = new object();
|
||||
|
||||
GameFileCache gameFileCache = null;
|
||||
GameFileCache gameFileCache => GameFileCacheFactory.Instance;
|
||||
Archetype currentArchetype = null;
|
||||
bool updateArchetypeStatus = true;
|
||||
|
||||
@ -134,8 +134,6 @@ namespace CodeWalker.Forms
|
||||
if (this.DesignMode) return;
|
||||
InitializeComponent();
|
||||
|
||||
gameFileCache = GameFileCacheFactory.GetInstance();
|
||||
|
||||
if (ExploreForm.Instance == null)
|
||||
{
|
||||
gameFileCache.EnableDlc = false;
|
||||
@ -2310,7 +2308,7 @@ namespace CodeWalker.Forms
|
||||
Input.KeyDown(e, enablemove);
|
||||
|
||||
var k = e.KeyCode;
|
||||
var kb = Input.keyBindings;
|
||||
var kb = Input.KeyBindings;
|
||||
bool ctrl = Input.CtrlPressed;
|
||||
bool shift = Input.ShiftPressed;
|
||||
|
||||
|
@ -218,7 +218,7 @@ namespace CodeWalker.Forms
|
||||
return false;//what are we even doing here?
|
||||
case MetaFormat.AudioRel:
|
||||
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");
|
||||
return false;
|
||||
|
@ -10,7 +10,6 @@ using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Remoting.Channels;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
@ -11,17 +11,24 @@ namespace CodeWalker.GameFiles
|
||||
|
||||
public static class GameFileCacheFactory
|
||||
{
|
||||
public static GameFileCache _instance = null;
|
||||
public static GameFileCache? _instance;
|
||||
|
||||
public static GameFileCache Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance is null)
|
||||
{
|
||||
var s = Settings.Default;
|
||||
_instance = new GameFileCache(s.CacheSize, s.CacheTime, GTAFolder.CurrentGTAFolder, s.DLC, s.EnableMods, s.ExcludeFolders, Settings.Default.Key);
|
||||
GTAFolder.OnGTAFolderChanged += _instance.SetGtaFolder;
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
public static GameFileCache GetInstance()
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
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);
|
||||
GTAFolder.OnGTAFolderChanged += _instance.SetGtaFolder;
|
||||
}
|
||||
return _instance;
|
||||
return Instance;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -752,7 +752,7 @@ namespace CodeWalker
|
||||
|
||||
|
||||
|
||||
public void LoadPed()
|
||||
public async ValueTask LoadPedAsync()
|
||||
{
|
||||
var pedname = PedNameComboBox.Text;
|
||||
var pedhash = JenkHash.GenHash(pedname.ToLowerInvariant());
|
||||
@ -765,7 +765,7 @@ namespace CodeWalker
|
||||
|
||||
DetailsPropertyGrid.SelectedObject = null;
|
||||
|
||||
SelectedPed.Init(pedname, GameFileCache);
|
||||
await SelectedPed.InitAsync(pedname, GameFileCache);
|
||||
|
||||
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 name = comboItem?.DrawableName;
|
||||
var tex = comboItem?.TextureName;
|
||||
|
||||
SelectedPed.SetComponentDrawable(index, name, tex, GameFileCache);
|
||||
await SelectedPed.SetComponentDrawableAsync(index, name, tex, GameFileCache);
|
||||
|
||||
UpdateModelsUI();
|
||||
}
|
||||
@ -916,9 +916,14 @@ namespace CodeWalker
|
||||
private void SelectClip(string name)
|
||||
{
|
||||
MetaHash cliphash = JenkHash.GenHash(name);
|
||||
ClipMapEntry cme = null;
|
||||
SelectedPed.Ycd?.ClipMap?.TryGetValue(cliphash, out cme);
|
||||
SelectedPed.AnimClip = cme;
|
||||
if (SelectedPed.Ycd?.ClipMap?.TryGetValue(cliphash, out var cme) ?? false)
|
||||
{
|
||||
SelectedPed.AnimClip = cme;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedPed.AnimClip = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1209,7 +1214,7 @@ namespace CodeWalker
|
||||
Input.KeyDown(e, enablemove);
|
||||
|
||||
var k = e.KeyCode;
|
||||
var kb = Input.keyBindings;
|
||||
var kb = Input.KeyBindings;
|
||||
bool ctrl = Input.CtrlPressed;
|
||||
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;
|
||||
|
||||
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)
|
||||
|
@ -16,18 +16,16 @@ using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Shell;
|
||||
|
||||
namespace CodeWalker
|
||||
namespace CodeWalker;
|
||||
static class Program
|
||||
{
|
||||
static class Program
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool AllocConsole();
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
/// </summary>
|
||||
[STAThread]
|
||||
static void Main(string[] args)
|
||||
Task.Run(() =>
|
||||
{
|
||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||
ConsoleWindow.Hide();
|
||||
@ -36,193 +34,193 @@ namespace CodeWalker
|
||||
{
|
||||
Console.WriteLine($"Unhandeled exception occured: {e.Exception}");
|
||||
};
|
||||
|
||||
|
||||
bool menumode = false;
|
||||
bool explorermode = false;
|
||||
bool projectmode = false;
|
||||
bool vehiclesmode = false;
|
||||
bool pedsmode = false;
|
||||
string path = null;
|
||||
if ((args != null) && (args.Length > 0))
|
||||
});
|
||||
bool menumode = false;
|
||||
bool explorermode = false;
|
||||
bool projectmode = false;
|
||||
bool vehiclesmode = false;
|
||||
bool pedsmode = false;
|
||||
string path = null;
|
||||
if ((args != null) && (args.Length > 0))
|
||||
{
|
||||
foreach (string arg in args)
|
||||
{
|
||||
foreach (string arg in args)
|
||||
string argl = arg.ToLowerInvariant();
|
||||
if (argl == "menu")
|
||||
{
|
||||
string argl = arg.ToLowerInvariant();
|
||||
if (argl == "menu")
|
||||
menumode = true;
|
||||
}
|
||||
if (argl == "explorer")
|
||||
{
|
||||
explorermode = true;
|
||||
}
|
||||
if (argl == "project")
|
||||
{
|
||||
projectmode = true;
|
||||
}
|
||||
if (argl == "vehicles")
|
||||
{
|
||||
vehiclesmode = true;
|
||||
}
|
||||
if (argl == "peds")
|
||||
{
|
||||
pedsmode = true;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (File.Exists(arg))
|
||||
{
|
||||
menumode = true;
|
||||
}
|
||||
if (argl == "explorer")
|
||||
{
|
||||
explorermode = true;
|
||||
}
|
||||
if (argl == "project")
|
||||
{
|
||||
projectmode = true;
|
||||
}
|
||||
if (argl == "vehicles")
|
||||
{
|
||||
vehiclesmode = true;
|
||||
}
|
||||
if (argl == "peds")
|
||||
{
|
||||
pedsmode = true;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (File.Exists(arg))
|
||||
{
|
||||
path = arg;
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex);
|
||||
Console.WriteLine(ex);
|
||||
path = arg;
|
||||
}
|
||||
} catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex);
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EnsureJumpList();
|
||||
Task.Run(EnsureJumpList);
|
||||
|
||||
//Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
//Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
|
||||
// Always check the GTA folder first thing
|
||||
if (!GTAFolder.UpdateGTAFolder(Properties.Settings.Default.RememberGTAFolder))
|
||||
{
|
||||
MessageBox.Show("Could not load CodeWalker because no valid GTA 5 folder was selected. CodeWalker will now exit.", "GTA 5 Folder Not Found", MessageBoxButtons.OK, MessageBoxIcon.Stop);
|
||||
return;
|
||||
}
|
||||
// Always check the GTA folder first thing
|
||||
if (!GTAFolder.UpdateGTAFolder(Properties.Settings.Default.RememberGTAFolder))
|
||||
{
|
||||
MessageBox.Show("Could not load CodeWalker because no valid GTA 5 folder was selected. CodeWalker will now exit.", "GTA 5 Folder Not Found", MessageBoxButtons.OK, MessageBoxIcon.Stop);
|
||||
return;
|
||||
}
|
||||
#if !DEBUG
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
#endif
|
||||
if (menumode)
|
||||
if (menumode)
|
||||
{
|
||||
Application.Run(new MenuForm());
|
||||
}
|
||||
else if (explorermode)
|
||||
{
|
||||
if (!NamedPipe.TrySendMessageToOtherProcess("explorer"))
|
||||
{
|
||||
Application.Run(new MenuForm());
|
||||
}
|
||||
else if (explorermode)
|
||||
{
|
||||
if (!NamedPipe.TrySendMessageToOtherProcess("explorer"))
|
||||
{
|
||||
var form = new ExploreForm();
|
||||
var namedPipe = new NamedPipe(form);
|
||||
namedPipe.Init();
|
||||
Application.Run(form);
|
||||
}
|
||||
}
|
||||
else if (projectmode)
|
||||
{
|
||||
Application.Run(new Project.ProjectForm());
|
||||
}
|
||||
else if (vehiclesmode)
|
||||
{
|
||||
Application.Run(new VehicleForm());
|
||||
}
|
||||
else if (pedsmode)
|
||||
{
|
||||
Application.Run(new PedsForm());
|
||||
}
|
||||
else if (path != null)
|
||||
{
|
||||
if (!NamedPipe.TrySendMessageToOtherProcess($"open-file {path}"))
|
||||
{
|
||||
Form form = null;
|
||||
try
|
||||
{
|
||||
form = OpenAnyFile.OpenFilePath(path);
|
||||
}
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
MessageBox.Show("Dit type bestand is op het moment nog niet ondersteund!", ex.ToString());
|
||||
}
|
||||
if (form != null)
|
||||
{
|
||||
Application.Run(form);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var form = new WorldForm();
|
||||
var form = new ExploreForm();
|
||||
var namedPipe = new NamedPipe(form);
|
||||
namedPipe.Init();
|
||||
Application.Run(form);
|
||||
}
|
||||
}
|
||||
else if (projectmode)
|
||||
{
|
||||
Application.Run(new Project.ProjectForm());
|
||||
}
|
||||
else if (vehiclesmode)
|
||||
{
|
||||
Application.Run(new VehicleForm());
|
||||
}
|
||||
else if (pedsmode)
|
||||
{
|
||||
Application.Run(new PedsForm());
|
||||
}
|
||||
else if (path != null)
|
||||
{
|
||||
if (!NamedPipe.TrySendMessageToOtherProcess($"open-file {path}"))
|
||||
{
|
||||
Form form = null;
|
||||
try
|
||||
{
|
||||
form = OpenAnyFile.OpenFilePath(path);
|
||||
}
|
||||
catch (NotImplementedException ex)
|
||||
{
|
||||
MessageBox.Show("Dit type bestand is op het moment nog niet ondersteund!", ex.ToString());
|
||||
}
|
||||
if (form != null)
|
||||
{
|
||||
Application.Run(form);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var form = new WorldForm();
|
||||
var namedPipe = new NamedPipe(form);
|
||||
namedPipe.Init();
|
||||
Application.Run(form);
|
||||
}
|
||||
#if !DEBUG
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show("An unexpected error was encountered!\n" + ex.ToString());
|
||||
//this can happen if folder wasn't chosen, or in some other catastrophic error. meh.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void EnsureJumpList()
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (Settings.Default.JumpListInitialised) return;
|
||||
MessageBox.Show("An unexpected error was encountered!\n" + ex.ToString());
|
||||
//this can happen if folder wasn't chosen, or in some other catastrophic error. meh.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var cwpath = Assembly.GetEntryAssembly().Location;
|
||||
var cwdir = Path.GetDirectoryName(cwpath);
|
||||
|
||||
var jtWorld = new JumpTask();
|
||||
jtWorld.ApplicationPath = cwpath;
|
||||
jtWorld.IconResourcePath = cwpath;
|
||||
jtWorld.WorkingDirectory = cwdir;
|
||||
jtWorld.Arguments = "";
|
||||
jtWorld.Title = "World View";
|
||||
jtWorld.Description = "Display the GTAV World";
|
||||
jtWorld.CustomCategory = "Launch Options";
|
||||
static void EnsureJumpList()
|
||||
{
|
||||
if (Settings.Default.JumpListInitialised) return;
|
||||
|
||||
var jtExplorer = new JumpTask();
|
||||
jtExplorer.ApplicationPath = cwpath;
|
||||
jtExplorer.IconResourcePath = Path.Combine(cwdir, "CodeWalker RPF Explorer.exe");
|
||||
jtExplorer.WorkingDirectory = cwdir;
|
||||
jtExplorer.Arguments = "explorer";
|
||||
jtExplorer.Title = "RPF Explorer";
|
||||
jtExplorer.Description = "Open RPF Explorer";
|
||||
jtExplorer.CustomCategory = "Launch Options";
|
||||
try
|
||||
{
|
||||
var cwpath = Assembly.GetEntryAssembly().Location;
|
||||
var cwdir = Path.GetDirectoryName(cwpath);
|
||||
|
||||
var jtVehicles = new JumpTask();
|
||||
jtVehicles.ApplicationPath = cwpath;
|
||||
jtVehicles.IconResourcePath = Path.Combine(cwdir, "CodeWalker Vehicle Viewer.exe");
|
||||
jtVehicles.WorkingDirectory = cwdir;
|
||||
jtVehicles.Arguments = "vehicles";
|
||||
jtVehicles.Title = "Vehicle Viewer";
|
||||
jtVehicles.Description = "Open Vehicle Viewer";
|
||||
jtVehicles.CustomCategory = "Launch Options";
|
||||
var jtWorld = new JumpTask();
|
||||
jtWorld.ApplicationPath = cwpath;
|
||||
jtWorld.IconResourcePath = cwpath;
|
||||
jtWorld.WorkingDirectory = cwdir;
|
||||
jtWorld.Arguments = "";
|
||||
jtWorld.Title = "World View";
|
||||
jtWorld.Description = "Display the GTAV World";
|
||||
jtWorld.CustomCategory = "Launch Options";
|
||||
|
||||
var jtPeds = new JumpTask();
|
||||
jtPeds.ApplicationPath = cwpath;
|
||||
jtPeds.IconResourcePath = Path.Combine(cwdir, "CodeWalker Ped Viewer.exe");
|
||||
jtPeds.WorkingDirectory = cwdir;
|
||||
jtPeds.Arguments = "peds";
|
||||
jtPeds.Title = "Ped Viewer";
|
||||
jtPeds.Description = "Open Ped Viewer";
|
||||
jtPeds.CustomCategory = "Launch Options";
|
||||
var jtExplorer = new JumpTask();
|
||||
jtExplorer.ApplicationPath = cwpath;
|
||||
jtExplorer.IconResourcePath = Path.Combine(cwdir, "CodeWalker RPF Explorer.exe");
|
||||
jtExplorer.WorkingDirectory = cwdir;
|
||||
jtExplorer.Arguments = "explorer";
|
||||
jtExplorer.Title = "RPF Explorer";
|
||||
jtExplorer.Description = "Open RPF Explorer";
|
||||
jtExplorer.CustomCategory = "Launch Options";
|
||||
|
||||
var jumpList = new JumpList();
|
||||
var jtVehicles = new JumpTask();
|
||||
jtVehicles.ApplicationPath = cwpath;
|
||||
jtVehicles.IconResourcePath = Path.Combine(cwdir, "CodeWalker Vehicle Viewer.exe");
|
||||
jtVehicles.WorkingDirectory = cwdir;
|
||||
jtVehicles.Arguments = "vehicles";
|
||||
jtVehicles.Title = "Vehicle Viewer";
|
||||
jtVehicles.Description = "Open Vehicle Viewer";
|
||||
jtVehicles.CustomCategory = "Launch Options";
|
||||
|
||||
jumpList.JumpItems.Add(jtWorld);
|
||||
jumpList.JumpItems.Add(jtExplorer);
|
||||
jumpList.JumpItems.Add(jtVehicles);
|
||||
jumpList.JumpItems.Add(jtPeds);
|
||||
var jtPeds = new JumpTask();
|
||||
jtPeds.ApplicationPath = cwpath;
|
||||
jtPeds.IconResourcePath = Path.Combine(cwdir, "CodeWalker Ped Viewer.exe");
|
||||
jtPeds.WorkingDirectory = cwdir;
|
||||
jtPeds.Arguments = "peds";
|
||||
jtPeds.Title = "Ped Viewer";
|
||||
jtPeds.Description = "Open Ped Viewer";
|
||||
jtPeds.CustomCategory = "Launch Options";
|
||||
|
||||
jumpList.Apply();
|
||||
var jumpList = new JumpList();
|
||||
|
||||
Settings.Default.JumpListInitialised = true;
|
||||
Settings.Default.Save();
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
jumpList.JumpItems.Add(jtWorld);
|
||||
jumpList.JumpItems.Add(jtExplorer);
|
||||
jumpList.JumpItems.Add(jtVehicles);
|
||||
jumpList.JumpItems.Add(jtPeds);
|
||||
|
||||
jumpList.Apply();
|
||||
|
||||
Settings.Default.JumpListInitialised = true;
|
||||
Settings.Default.Save();
|
||||
}
|
||||
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>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
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.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("True")]
|
||||
@ -929,5 +898,33 @@ namespace CodeWalker.Properties {
|
||||
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">
|
||||
<Value Profile="(Default)" />
|
||||
</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">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
@ -240,5 +221,24 @@
|
||||
<Setting Name="AntiAliasing" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">2</Value>
|
||||
</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>
|
||||
</SettingsFile>
|
@ -57,7 +57,7 @@ namespace CodeWalker.Rendering
|
||||
{
|
||||
//SharpDX.Configuration.EnableObjectTracking = true;
|
||||
|
||||
SwapChainDescription scd = new SwapChainDescription()
|
||||
var scd = new SwapChainDescription()
|
||||
{
|
||||
BufferCount = 2,
|
||||
Flags = SwapChainFlags.None,
|
||||
|
@ -14,15 +14,14 @@ namespace CodeWalker.Tools
|
||||
{
|
||||
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 Dictionary<string, RelData> NameComboLookup = new Dictionary<string, RelData>();
|
||||
|
||||
|
||||
public AudioExplorerForm(GameFileCache gfc)
|
||||
public AudioExplorerForm()
|
||||
{
|
||||
GameFileCache = gfc;
|
||||
InitializeComponent();
|
||||
LoadDropDowns();
|
||||
}
|
||||
|
@ -18,14 +18,12 @@ namespace CodeWalker.Tools
|
||||
private volatile bool InProgress = false;
|
||||
private volatile bool AbortOperation = false;
|
||||
|
||||
private GameFileCache FileCache = null;
|
||||
private RpfManager RpfMan = null;
|
||||
private static GameFileCache FileCache => GameFileCacheFactory.Instance;
|
||||
private static RpfManager RpfMan => FileCache.RpfMan;
|
||||
|
||||
|
||||
public BinarySearchForm(GameFileCache cache = null)
|
||||
public BinarySearchForm()
|
||||
{
|
||||
FileCache = cache;
|
||||
RpfMan = cache?.RpfMan;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
@ -37,12 +35,11 @@ namespace CodeWalker.Tools
|
||||
DataTextBox.SetTabStopWidth(3);
|
||||
|
||||
|
||||
if (RpfMan == null || !RpfMan.IsInited)
|
||||
if (!RpfMan.IsInited)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
|
||||
RpfMan ??= RpfManager.GetInstance();
|
||||
RpfMan.Init(GTAFolder.CurrentGTAFolder, UpdateStatus, UpdateStatus, false, false);
|
||||
RPFScanComplete();
|
||||
});
|
||||
|
@ -43,18 +43,22 @@ namespace CodeWalker.Tools
|
||||
private void BrowseForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
var info = DetailsPropertyGrid.GetType().GetProperty("Controls");
|
||||
var collection = info.GetValue(DetailsPropertyGrid, null) as Control.ControlCollection;
|
||||
foreach (var control in collection)
|
||||
var collection = info?.GetValue(DetailsPropertyGrid, null) as Control.ControlCollection;
|
||||
if (collection is not null)
|
||||
{
|
||||
var ctyp = control.GetType();
|
||||
if (ctyp.Name == "PropertyGridView")
|
||||
foreach (var control in collection)
|
||||
{
|
||||
var prop = ctyp.GetField("labelRatio");
|
||||
var val = prop.GetValue(control);
|
||||
prop.SetValue(control, 4.0); //somehow this sets the width of the property grid's label column...
|
||||
var ctyp = control.GetType();
|
||||
if (ctyp.Name == "PropertyGridView")
|
||||
{
|
||||
var prop = ctyp.GetField("labelRatio");
|
||||
var val = prop.GetValue(control);
|
||||
prop.SetValue(control, 4.0); //somehow this sets the width of the property grid's label column...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FolderTextBox.Text = GTAFolder.CurrentGTAFolder;
|
||||
DataHexLineCombo.Text = "16";
|
||||
|
||||
@ -120,11 +124,7 @@ namespace CodeWalker.Tools
|
||||
|
||||
string[] allfiles = Directory.GetFiles(searchpath, "*.rpf", SearchOption.AllDirectories);
|
||||
|
||||
uint totrpfs = 0;
|
||||
uint totfiles = 0;
|
||||
uint totfolders = 0;
|
||||
uint totresfiles = 0;
|
||||
uint totbinfiles = 0;
|
||||
var counts = new FileCounts();
|
||||
|
||||
foreach (string rpfpath in allfiles)
|
||||
{
|
||||
@ -139,22 +139,16 @@ namespace CodeWalker.Tools
|
||||
|
||||
UpdateStatus("Scanning " + rf.Name + "...");
|
||||
|
||||
rf.ScanStructure(UpdateStatus, UpdateStatus);
|
||||
|
||||
totrpfs += rf.GrandTotalRpfCount;
|
||||
totfiles += rf.GrandTotalFileCount;
|
||||
totfolders += rf.GrandTotalFolderCount;
|
||||
totresfiles += rf.GrandTotalResourceCount;
|
||||
totbinfiles += rf.GrandTotalBinaryFileCount;
|
||||
counts += rf.ScanStructure(UpdateStatus, UpdateStatus);
|
||||
|
||||
AddScannedFile(rf, null, true);
|
||||
|
||||
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;
|
||||
TotalFileCount = (int)totfiles;
|
||||
TotalFileCount = (int)counts.Files;
|
||||
});
|
||||
|
||||
}
|
||||
@ -739,12 +733,11 @@ namespace CodeWalker.Tools
|
||||
errcount++;
|
||||
}
|
||||
|
||||
totbytes += file.ExtractedByteCount;
|
||||
curfile++;
|
||||
}
|
||||
|
||||
|
||||
UpdateStatus("Test complete. " + errcount.ToString() + " problems encountered, " + totbytes.ToString() + " total bytes extracted.");
|
||||
UpdateStatus("Test complete. " + errcount.ToString() + " problems encountered");
|
||||
InProgress = false;
|
||||
});
|
||||
}
|
||||
|
@ -17,9 +17,9 @@ namespace CodeWalker.Tools
|
||||
{
|
||||
Dictionary<uint, string> extraStrings = new Dictionary<uint, string>();
|
||||
|
||||
private static GameFileCache GameFileCache => GameFileCacheFactory.Instance;
|
||||
|
||||
|
||||
public JenkIndForm(GameFileCache gameFileCache = null)
|
||||
public JenkIndForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
@ -32,16 +32,15 @@ namespace CodeWalker.Tools
|
||||
MainPanel.Enabled = false;
|
||||
Cursor = Cursors.WaitCursor;
|
||||
|
||||
if ((gameFileCache == null) || (gameFileCache.IsInited == false))
|
||||
if (!GameFileCache.IsInited)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
|
||||
GameFileCache gfc = GameFileCacheFactory.GetInstance();
|
||||
gfc.DoFullStringIndex = true;
|
||||
gfc.Init(UpdateStatus, UpdateStatus);
|
||||
GameFileCache.DoFullStringIndex = true;
|
||||
GameFileCache.Init(UpdateStatus, UpdateStatus);
|
||||
IndexBuildComplete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -58,8 +57,8 @@ namespace CodeWalker.Tools
|
||||
try
|
||||
{
|
||||
UpdateStatus("Loading strings...");
|
||||
gameFileCache.DoFullStringIndex = true;
|
||||
await gameFileCache.InitStringDictsAsync();
|
||||
GameFileCache.DoFullStringIndex = true;
|
||||
await GameFileCache.InitStringDictsAsync();
|
||||
IndexBuildComplete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -9,6 +9,7 @@ using CodeWalker.Properties;
|
||||
using Microsoft.Win32;
|
||||
using CodeWalker.GameFiles;
|
||||
using CodeWalker.Utils;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace CodeWalker
|
||||
{
|
||||
@ -16,7 +17,7 @@ namespace CodeWalker
|
||||
{
|
||||
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
|
||||
{
|
||||
if (currentGTAFolder == value) return;
|
||||
@ -24,9 +25,9 @@ namespace CodeWalker
|
||||
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))
|
||||
{
|
||||
@ -49,7 +50,7 @@ namespace CodeWalker
|
||||
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);
|
||||
|
||||
@ -60,11 +61,11 @@ namespace CodeWalker
|
||||
return true;
|
||||
}
|
||||
|
||||
string origFolder = CurrentGTAFolder;
|
||||
string folder = CurrentGTAFolder;
|
||||
var origFolder = CurrentGTAFolder;
|
||||
var folder = CurrentGTAFolder;
|
||||
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)
|
||||
{
|
||||
f.SelectedFolder = autoFolder;
|
||||
@ -76,22 +77,23 @@ namespace CodeWalker
|
||||
folder = f.SelectedFolder;
|
||||
}
|
||||
|
||||
string failReason;
|
||||
if(ValidateGTAFolder(folder, out failReason))
|
||||
if (ValidateGTAFolder(folder, out string? failReason))
|
||||
{
|
||||
SetGTAFolder(folder);
|
||||
if(folder != origFolder)
|
||||
if (folder != origFolder)
|
||||
{
|
||||
MessageBox.Show($"Successfully changed GTA Folder to \"{folder}\"", "Set GTA Folder", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||
}
|
||||
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);
|
||||
if(tryAgain == DialogResult.Retry)
|
||||
if (tryAgain == DialogResult.Retry)
|
||||
{
|
||||
return UpdateGTAFolder(false);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -123,9 +125,9 @@ namespace CodeWalker
|
||||
}
|
||||
|
||||
RegistryKey baseKey32 = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
|
||||
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 oivPathValue = Registry.CurrentUser.OpenSubKey(@"Software\NewTechnologyStudio\OpenIV.exe\BrowseForFolder")?.GetValue("game_path_Five_pc") 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? oivPathValue = Registry.CurrentUser.OpenSubKey(@"Software\NewTechnologyStudio\OpenIV.exe\BrowseForFolder")?.GetValue("game_path_Five_pc") as string;
|
||||
|
||||
if(steamPathValue?.EndsWith("\\GTAV") == true)
|
||||
{
|
||||
@ -150,7 +152,7 @@ namespace CodeWalker
|
||||
return matches.Count > 0;
|
||||
}
|
||||
|
||||
public static string AutoDetectFolder(out string source)
|
||||
public static string? AutoDetectFolder(out string? source)
|
||||
{
|
||||
source = null;
|
||||
|
||||
@ -164,7 +166,7 @@ namespace CodeWalker
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string AutoDetectFolder() => AutoDetectFolder(out string _);
|
||||
public static string? AutoDetectFolder() => AutoDetectFolder(out string? _);
|
||||
|
||||
public static void UpdateSettings()
|
||||
{
|
||||
|
@ -42,7 +42,18 @@ namespace CodeWalker
|
||||
public volatile bool kbjump = 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 ShiftPressed = false;
|
||||
@ -127,13 +138,13 @@ namespace CodeWalker
|
||||
//WASD move...
|
||||
if (enablemove)
|
||||
{
|
||||
if (k == keyBindings.MoveForward) kbmovefwd = true;
|
||||
if (k == keyBindings.MoveBackward) kbmovebck = true;
|
||||
if (k == keyBindings.MoveLeft) kbmovelft = true;
|
||||
if (k == keyBindings.MoveRight) kbmovergt = true;
|
||||
if (k == keyBindings.MoveUp) kbmoveup = true;
|
||||
if (k == keyBindings.MoveDown) kbmovedn = true;
|
||||
if (k == keyBindings.Jump) kbjump = true;
|
||||
if (k == KeyBindings.MoveForward) kbmovefwd = true;
|
||||
if (k == KeyBindings.MoveBackward) kbmovebck = true;
|
||||
if (k == KeyBindings.MoveLeft) kbmovelft = true;
|
||||
if (k == KeyBindings.MoveRight) kbmovergt = true;
|
||||
if (k == KeyBindings.MoveUp) kbmoveup = true;
|
||||
if (k == KeyBindings.MoveDown) kbmovedn = true;
|
||||
if (k == KeyBindings.Jump) kbjump = true;
|
||||
}
|
||||
|
||||
kbmoving = kbmovefwd || kbmovebck || kbmovelft || kbmovergt || kbmoveup || kbmovedn || kbjump;
|
||||
@ -146,13 +157,13 @@ namespace CodeWalker
|
||||
ShiftPressed = (e.Modifiers & Keys.Shift) > 0;
|
||||
|
||||
var k = e.KeyCode;
|
||||
if (k == keyBindings.MoveForward) kbmovefwd = false;
|
||||
if (k == keyBindings.MoveBackward) kbmovebck = false;
|
||||
if (k == keyBindings.MoveLeft) kbmovelft = false;
|
||||
if (k == keyBindings.MoveRight) kbmovergt = false;
|
||||
if (k == keyBindings.MoveUp) kbmoveup = false;
|
||||
if (k == keyBindings.MoveDown) kbmovedn = false;
|
||||
if (k == keyBindings.Jump) kbjump = false;
|
||||
if (k == KeyBindings.MoveForward) kbmovefwd = false;
|
||||
if (k == KeyBindings.MoveBackward) kbmovebck = false;
|
||||
if (k == KeyBindings.MoveLeft) kbmovelft = false;
|
||||
if (k == KeyBindings.MoveRight) kbmovergt = false;
|
||||
if (k == KeyBindings.MoveUp) kbmoveup = false;
|
||||
if (k == KeyBindings.MoveDown) kbmovedn = false;
|
||||
if (k == KeyBindings.Jump) kbjump = false;
|
||||
|
||||
kbmoving = kbmovefwd || kbmovebck || kbmovelft || kbmovergt || kbmoveup || kbmovedn || kbjump;
|
||||
|
||||
@ -263,6 +274,7 @@ namespace CodeWalker
|
||||
|
||||
public KeyBindings(StringCollection sc)
|
||||
{
|
||||
Console.WriteLine("Creating KeyBindings");
|
||||
foreach (string s in sc)
|
||||
{
|
||||
string[] parts = s.Split(':');
|
||||
|
@ -1041,7 +1041,7 @@ namespace CodeWalker
|
||||
Input.KeyDown(e, enablemove);
|
||||
|
||||
var k = e.KeyCode;
|
||||
var kb = Input.keyBindings;
|
||||
var kb = Input.KeyBindings;
|
||||
bool ctrl = Input.CtrlPressed;
|
||||
bool shift = Input.ShiftPressed;
|
||||
|
||||
|
@ -18,7 +18,7 @@ namespace CodeWalker.World
|
||||
public partial class CutsceneForm : Form
|
||||
{
|
||||
private WorldForm WorldForm;
|
||||
private GameFileCache GameFileCache;
|
||||
private GameFileCache GameFileCache => GameFileCacheFactory.Instance;
|
||||
private AudioDatabase AudioDatabase;
|
||||
|
||||
private Cutscene Cutscene = null;
|
||||
@ -43,7 +43,6 @@ namespace CodeWalker.World
|
||||
public CutsceneForm(WorldForm worldForm)
|
||||
{
|
||||
WorldForm = worldForm;
|
||||
GameFileCache = WorldForm.GameFileCache;
|
||||
AudioDatabase = new AudioDatabase();
|
||||
InitializeComponent();
|
||||
}
|
||||
@ -105,7 +104,7 @@ namespace CodeWalker.World
|
||||
private void SelectCutscene(CutsceneDropdownItem dditem)
|
||||
{
|
||||
Cursor = Cursors.WaitCursor;
|
||||
Task.Run(() =>
|
||||
Task.Run(async () =>
|
||||
{
|
||||
CutFile cutFile = null;
|
||||
Cutscene cutscene = null;
|
||||
@ -125,7 +124,7 @@ namespace CodeWalker.World
|
||||
GameFileCache.RpfMan.LoadFile(cutFile, entry);
|
||||
|
||||
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
|
||||
{
|
||||
public CutFile CutFile { get; set; } = null;
|
||||
private GameFileCache GameFileCache = null;
|
||||
private GameFileCache GameFileCache => GameFileCacheFactory.Instance;
|
||||
private WorldForm WorldForm = 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;
|
||||
GameFileCache = gfc;
|
||||
WorldForm = wf;
|
||||
AudioDB = adb;
|
||||
|
||||
@ -539,7 +537,7 @@ namespace CodeWalker.World
|
||||
|
||||
|
||||
LoadYcds();
|
||||
CreateSceneObjects();
|
||||
await CreateSceneObjectsAsync();
|
||||
RaiseEvents(0.0f);
|
||||
}
|
||||
|
||||
@ -1164,9 +1162,9 @@ namespace CodeWalker.World
|
||||
int drbl = args.iDrawable;
|
||||
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>();
|
||||
|
||||
@ -1274,7 +1272,7 @@ namespace CodeWalker.World
|
||||
foreach (var obj in Objects.Values)
|
||||
{
|
||||
var sobj = new CutsceneObject();
|
||||
sobj.Init(obj, GameFileCache, AudioDB);
|
||||
await sobj.InitAsync(obj, GameFileCache, AudioDB);
|
||||
SceneObjects[sobj.ObjectID] = sobj;
|
||||
|
||||
if (sobj.AnimHash != 0)
|
||||
@ -1320,7 +1318,7 @@ namespace CodeWalker.World
|
||||
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;
|
||||
ObjectID = obj?.iObjectId ?? -1;
|
||||
@ -1345,7 +1343,7 @@ namespace CodeWalker.World
|
||||
}
|
||||
else if (obj is CutPedModelObject ped)
|
||||
{
|
||||
InitPed(ped, gfc);
|
||||
await InitPedAsync(ped, gfc);
|
||||
}
|
||||
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.Init(ped.StreamingName, gfc);
|
||||
Ped.LoadDefaultComponents(gfc);
|
||||
await Ped.InitAsync(ped.StreamingName, gfc);
|
||||
await Ped.LoadDefaultComponentsAsync(gfc);
|
||||
|
||||
//if (ped.StreamingName == JenkHash.GenHash("player_zero"))
|
||||
//{
|
||||
|
@ -27,7 +27,13 @@ namespace CodeWalker
|
||||
{
|
||||
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; } }
|
||||
|
||||
volatile bool formopen = false;
|
||||
@ -36,23 +42,31 @@ namespace CodeWalker
|
||||
volatile bool initialised = false;
|
||||
|
||||
Stopwatch frametimer = new Stopwatch();
|
||||
Space space = new Space();
|
||||
Space space;
|
||||
Camera camera;
|
||||
Timecycle timecycle;
|
||||
Weather weather;
|
||||
Clouds clouds;
|
||||
Water water = new Water();
|
||||
Trains trains = new Trains();
|
||||
Scenarios scenarios = new Scenarios();
|
||||
PopZones popzones = new PopZones();
|
||||
Heightmaps heightmaps = new Heightmaps();
|
||||
Watermaps watermaps = new Watermaps();
|
||||
AudioZones audiozones = new AudioZones();
|
||||
|
||||
private Water water;
|
||||
Water Water { get => water ??= new Water(); }
|
||||
private Trains trains;
|
||||
Trains Trains { get => trains ??= new Trains(); }
|
||||
private Scenarios scenarios;
|
||||
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 CancellationToken CancellationToken;
|
||||
|
||||
public Space Space { get { return space; } }
|
||||
public Space Space { get => space ??= new Space(); }
|
||||
|
||||
bool MouseLButtonDown = false;
|
||||
bool MouseRButtonDown = false;
|
||||
@ -70,8 +84,9 @@ namespace CodeWalker
|
||||
Vector3 prevworldpos = new Vector3(0, 0, 100); //also the start pos
|
||||
|
||||
|
||||
public GameFileCache GameFileCache { get => gameFileCache; }
|
||||
GameFileCache gameFileCache = GameFileCacheFactory.GetInstance();
|
||||
private GameFileCache gameFileCache;
|
||||
public GameFileCache GameFileCache { get => gameFileCache ??= GameFileCacheFactory.GetInstance(); }
|
||||
|
||||
|
||||
|
||||
WorldControlMode ControlMode = WorldControlMode.Free;
|
||||
@ -91,8 +106,11 @@ namespace CodeWalker
|
||||
bool ControlBrushEnabled;
|
||||
//float ControlBrushRadius;
|
||||
|
||||
Entity camEntity = new Entity();
|
||||
PedEntity pedEntity = new PedEntity();
|
||||
private Entity camEntity;
|
||||
private PedEntity pedEntity;
|
||||
|
||||
Entity CamEntity { get => camEntity ??= new Entity(); }
|
||||
PedEntity PedEntity { get => pedEntity ??= new PedEntity(); }
|
||||
|
||||
|
||||
bool iseditmode = false;
|
||||
@ -216,10 +234,17 @@ namespace CodeWalker
|
||||
|
||||
public WorldForm()
|
||||
{
|
||||
|
||||
Task.Run(() => {
|
||||
if (!GameFileCache.IsInited)
|
||||
{
|
||||
GameFileCache.Init();
|
||||
}
|
||||
});
|
||||
CancellationToken = CancellationTokenSource.Token;
|
||||
InitializeComponent();
|
||||
|
||||
Renderer = new Renderer(this, gameFileCache);
|
||||
Renderer = new Renderer(this, GameFileCache);
|
||||
camera = Renderer.camera;
|
||||
timecycle = Renderer.timecycle;
|
||||
weather = Renderer.weather;
|
||||
@ -228,20 +253,15 @@ namespace CodeWalker
|
||||
CurMouseHit.WorldForm = this;
|
||||
LastMouseHit.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
|
||||
|
||||
initedOk = Renderer.Init();
|
||||
|
||||
if (!initedOk)
|
||||
{
|
||||
Close();
|
||||
@ -365,11 +385,11 @@ namespace CodeWalker
|
||||
}
|
||||
}
|
||||
|
||||
camera.FollowEntity = camEntity;
|
||||
camEntity.Position = (startupviewmode!=2) ? prevworldpos : Vector3.Zero;
|
||||
camEntity.Orientation = Quaternion.LookAtLH(Vector3.Zero, Vector3.Up, Vector3.ForwardLH);
|
||||
camera.FollowEntity = CamEntity;
|
||||
CamEntity.Position = (startupviewmode!=2) ? prevworldpos : Vector3.Zero;
|
||||
CamEntity.Orientation = Quaternion.LookAtLH(Vector3.Zero, Vector3.Up, Vector3.ForwardLH);
|
||||
|
||||
space.AddPersistentEntity(pedEntity);
|
||||
Space.AddPersistentEntity(PedEntity);
|
||||
|
||||
|
||||
LoadSettings();
|
||||
@ -413,11 +433,10 @@ namespace CodeWalker
|
||||
{
|
||||
Renderer.BuffersResized(w, h);
|
||||
|
||||
if (WindowState == FormWindowState.Minimized && gameFileCache.IsInited)
|
||||
if (WindowState == FormWindowState.Minimized && GameFileCache.IsInited)
|
||||
{
|
||||
Console.WriteLine("Clearing cache");
|
||||
gameFileCache.Clear();
|
||||
gameFileCache.IsInited = true;
|
||||
GameFileCache.Clear();
|
||||
//GC.Collect();
|
||||
}
|
||||
}
|
||||
@ -445,7 +464,7 @@ namespace CodeWalker
|
||||
{
|
||||
UpdateControlInputs(elapsed);
|
||||
|
||||
space.Update(elapsed);
|
||||
Space.Update(elapsed);
|
||||
|
||||
if (CutsceneForm != null)
|
||||
{
|
||||
@ -597,7 +616,7 @@ namespace CodeWalker
|
||||
|
||||
|
||||
Vector3 movewvec = camera.ViewInvQuaternion.Multiply(movevec);
|
||||
camEntity.Position += movewvec;
|
||||
CamEntity.Position += movewvec;
|
||||
|
||||
MapViewDragX = 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
|
||||
|
||||
pedEntity.ControlMovement = movexy;
|
||||
pedEntity.ControlJump = Input.kbjump || Input.ControllerButtonPressed(GamepadButtonFlags.X);
|
||||
pedEntity.ControlBoost = Input.ShiftPressed || Input.ControllerButtonPressed(GamepadButtonFlags.A | GamepadButtonFlags.RightShoulder | GamepadButtonFlags.LeftShoulder);
|
||||
PedEntity.ControlMovement = movexy;
|
||||
PedEntity.ControlJump = Input.kbjump || Input.ControllerButtonPressed(GamepadButtonFlags.X);
|
||||
PedEntity.ControlBoost = Input.ShiftPressed || Input.ControllerButtonPressed(GamepadButtonFlags.A | GamepadButtonFlags.RightShoulder | GamepadButtonFlags.LeftShoulder);
|
||||
|
||||
|
||||
//Vector3 pedfwd = pedEntity.Orientation.Multiply(Vector3.UnitZ);
|
||||
@ -725,9 +744,9 @@ namespace CodeWalker
|
||||
|
||||
if (renderworld)
|
||||
{
|
||||
space.GetVisibleYmaps(camera, hour, weathertype, renderworldVisibleYmapDict);
|
||||
Space.GetVisibleYmaps(camera, hour, weathertype, renderworldVisibleYmapDict);
|
||||
|
||||
spaceEnts = space.TemporaryEntities;
|
||||
spaceEnts = Space.TemporaryEntities;
|
||||
}
|
||||
|
||||
if (ProjectForm != null)
|
||||
@ -808,12 +827,12 @@ namespace CodeWalker
|
||||
//enqueue collision meshes for rendering - from the world grid
|
||||
|
||||
collisionitems.Clear();
|
||||
space.GetVisibleBounds(camera, collisionmeshrange, collisionmeshlayers, collisionitems);
|
||||
Space.GetVisibleBounds(camera, collisionmeshrange, collisionmeshlayers, collisionitems);
|
||||
|
||||
collisionybns.Clear();
|
||||
foreach (var item in collisionitems)
|
||||
{
|
||||
YbnFile ybn = gameFileCache.GetYbn(item.Name);
|
||||
YbnFile ybn = GameFileCache.GetYbn(item.Name);
|
||||
if ((ybn != null) && (ybn.Loaded))
|
||||
{
|
||||
collisionybns.Add(ybn);
|
||||
@ -825,7 +844,7 @@ namespace CodeWalker
|
||||
{
|
||||
if (mlo.Archetype == null) return;
|
||||
var hash = mlo.Archetype.Hash;
|
||||
YbnFile ybn = gameFileCache.GetYbn(hash);
|
||||
YbnFile ybn = GameFileCache.GetYbn(hash);
|
||||
if ((ybn != null) && (ybn.Loaded))
|
||||
{
|
||||
collisioninteriors[mlo] = ybn;
|
||||
@ -858,17 +877,17 @@ namespace CodeWalker
|
||||
|
||||
private void RenderWorldWaterQuads()
|
||||
{
|
||||
var quads = RenderWorldBaseWaterQuads(water.WaterQuads, MapSelectionMode.WaterQuad);
|
||||
var quads = RenderWorldBaseWaterQuads(Water.WaterQuads, MapSelectionMode.WaterQuad);
|
||||
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
|
||||
{
|
||||
List<T> renderwaterquadlist = water.GetVisibleQuads<T>(camera, quads);
|
||||
List<T> renderwaterquadlist = Water.GetVisibleQuads<T>(camera, quads);
|
||||
|
||||
ProjectForm?.GetVisibleWaterQuads<T>(camera, renderwaterquadlist);
|
||||
|
||||
@ -881,7 +900,7 @@ namespace CodeWalker
|
||||
{
|
||||
renderpathynds.Clear();
|
||||
|
||||
space.GetVisibleYnds(camera, renderpathynds);
|
||||
Space.GetVisibleYnds(camera, renderpathynds);
|
||||
|
||||
if (ProjectForm != null)
|
||||
{
|
||||
@ -895,10 +914,10 @@ namespace CodeWalker
|
||||
|
||||
private void RenderWorldTrainTracks()
|
||||
{
|
||||
if (!trains.Inited) return;
|
||||
if (!Trains.Inited) return;
|
||||
|
||||
rendertraintracklist.Clear();
|
||||
rendertraintracklist.AddRange(trains.TrainTracks);
|
||||
rendertraintracklist.AddRange(Trains.TrainTracks);
|
||||
|
||||
if (ProjectForm != null)
|
||||
{
|
||||
@ -914,7 +933,7 @@ namespace CodeWalker
|
||||
{
|
||||
|
||||
rendernavmeshynvs.Clear();
|
||||
space.GetVisibleYnvs(camera, collisionmeshrange, rendernavmeshynvs);
|
||||
Space.GetVisibleYnvs(camera, collisionmeshrange, rendernavmeshynvs);
|
||||
|
||||
if (ProjectForm != null)
|
||||
{
|
||||
@ -930,10 +949,10 @@ namespace CodeWalker
|
||||
|
||||
private void RenderWorldScenarios()
|
||||
{
|
||||
if (!scenarios.Inited) return;
|
||||
if (!Scenarios.Inited) return;
|
||||
|
||||
renderscenariolist.Clear();
|
||||
renderscenariolist.AddRange(scenarios.ScenarioRegions);
|
||||
renderscenariolist.AddRange(Scenarios.ScenarioRegions);
|
||||
|
||||
if (ProjectForm != null)
|
||||
{
|
||||
@ -947,7 +966,7 @@ namespace CodeWalker
|
||||
|
||||
private void RenderWorldPopZones()
|
||||
{
|
||||
if (!popzones.Inited) return;
|
||||
if (!PopZones.Inited) return;
|
||||
|
||||
//renderpopzonelist.Clear();
|
||||
//renderpopzonelist.AddRange(popzones.Groups.Values);
|
||||
@ -957,12 +976,12 @@ namespace CodeWalker
|
||||
//ProjectForm.GetVisiblePopZones(camera, renderpopzonelist);
|
||||
}
|
||||
|
||||
Renderer.RenderPopZones(popzones);
|
||||
Renderer.RenderPopZones(PopZones);
|
||||
}
|
||||
|
||||
private void RenderWorldHeightmaps()
|
||||
{
|
||||
if (!heightmaps.Inited) return;
|
||||
if (!Heightmaps.Inited) return;
|
||||
|
||||
//renderheightmaplist.Clear();
|
||||
//renderheightmaplist.AddRange(heightmaps.Heightmaps);
|
||||
@ -972,12 +991,12 @@ namespace CodeWalker
|
||||
//ProjectForm.GetVisibleHeightmaps(camera, renderheightmaplist);
|
||||
}
|
||||
|
||||
Renderer.RenderBasePath(heightmaps);
|
||||
Renderer.RenderBasePath(Heightmaps);
|
||||
}
|
||||
|
||||
private void RenderWorldWatermaps()
|
||||
{
|
||||
if (!watermaps.Inited) return;
|
||||
if (!Watermaps.Inited) return;
|
||||
|
||||
//renderwatermaplist.Clear();
|
||||
//renderwatermaplist.AddRange(watermaps.Watermaps);
|
||||
@ -987,12 +1006,12 @@ namespace CodeWalker
|
||||
//ProjectForm.GetVisibleWatermaps(camera, renderwatermaplist);
|
||||
}
|
||||
|
||||
Renderer.RenderBasePath(watermaps);
|
||||
Renderer.RenderBasePath(Watermaps);
|
||||
}
|
||||
|
||||
private void RenderWorldAudioZones()
|
||||
{
|
||||
if (!audiozones.Inited) return;
|
||||
if (!AudioZones.Inited) return;
|
||||
|
||||
renderaudfilelist.Clear();
|
||||
renderaudfilelist.AddRange(GameFileCache.AudioDatRelFiles);
|
||||
@ -1003,7 +1022,7 @@ namespace CodeWalker
|
||||
}
|
||||
|
||||
renderaudplacementslist.Clear();
|
||||
audiozones.GetPlacements(renderaudfilelist, renderaudplacementslist);
|
||||
AudioZones.GetPlacements(renderaudfilelist, renderaudplacementslist);
|
||||
|
||||
|
||||
|
||||
@ -1125,7 +1144,7 @@ namespace CodeWalker
|
||||
{
|
||||
hash = JenkHash.GenHash(modelname);
|
||||
}
|
||||
Archetype arche = gameFileCache.GetArchetype(hash);
|
||||
Archetype arche = GameFileCache.GetArchetype(hash);
|
||||
|
||||
Archetype selarch = null;
|
||||
DrawableBase seldrwbl = null;
|
||||
@ -1139,7 +1158,7 @@ namespace CodeWalker
|
||||
}
|
||||
else
|
||||
{
|
||||
YmapFile ymap = gameFileCache.GetYmap(hash);
|
||||
YmapFile ymap = GameFileCache.GetYmap(hash);
|
||||
if (ymap != null)
|
||||
{
|
||||
Renderer.RenderYmap(ymap);
|
||||
@ -1147,7 +1166,7 @@ namespace CodeWalker
|
||||
else
|
||||
{
|
||||
//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.Loaded)
|
||||
@ -1159,7 +1178,7 @@ namespace CodeWalker
|
||||
}
|
||||
else
|
||||
{
|
||||
YftFile yft = gameFileCache.GetYft(hash);
|
||||
YftFile yft = GameFileCache.GetYft(hash);
|
||||
if (yft != null)
|
||||
{
|
||||
if (yft.Loaded)
|
||||
@ -1186,7 +1205,7 @@ namespace CodeWalker
|
||||
|
||||
if ((selarch != null) && (seldrwbl == null))
|
||||
{
|
||||
seldrwbl = gameFileCache.TryGetDrawable(selarch);
|
||||
seldrwbl = GameFileCache.TryGetDrawable(selarch);
|
||||
}
|
||||
|
||||
//select this item for viewing by the UI...
|
||||
@ -1209,7 +1228,7 @@ namespace CodeWalker
|
||||
foreach (string lod in ymaplist)
|
||||
{
|
||||
uint hash = JenkHash.GenHash(lod);
|
||||
YmapFile ymap = gameFileCache.GetYmap(hash);
|
||||
YmapFile ymap = GameFileCache.GetYmap(hash);
|
||||
Renderer.RenderYmap(ymap);
|
||||
|
||||
UpdateMouseHits(ymap);
|
||||
@ -1763,13 +1782,13 @@ namespace CodeWalker
|
||||
float downlimit = 20.0f;
|
||||
Ray ray = new Ray(p, new Vector3(0, 0, -1.0f));
|
||||
ray.Position.Z += 0.1f;
|
||||
SpaceRayIntersectResult hit = space.RayIntersect(ray, downlimit);
|
||||
SpaceRayIntersectResult hit = Space.RayIntersect(ray, downlimit);
|
||||
if (hit.Hit)
|
||||
{
|
||||
return hit.Position;
|
||||
}
|
||||
ray.Position.Z += uplimit;
|
||||
hit = space.RayIntersect(ray, downlimit);
|
||||
hit = Space.RayIntersect(ray, downlimit);
|
||||
if (hit.Hit)
|
||||
{
|
||||
return hit.Position;
|
||||
@ -1928,12 +1947,12 @@ namespace CodeWalker
|
||||
ynd.UpdateAllNodePositions();
|
||||
ynd.BuildBVH();
|
||||
|
||||
space.BuildYndData(ynd);
|
||||
Space.BuildYndData(ynd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ynd.UpdateAllNodePositions();
|
||||
space.BuildYndVerts(ynd, selection);
|
||||
Space.BuildYndVerts(ynd, selection);
|
||||
}
|
||||
//lock (Renderer.RenderSyncRoot)
|
||||
{
|
||||
@ -1948,7 +1967,7 @@ namespace CodeWalker
|
||||
}
|
||||
public YndNode GetPathNodeFromSpace(ushort areaid, ushort nodeid)
|
||||
{
|
||||
return space.NodeGrid.GetYndNode(areaid, nodeid);
|
||||
return Space.NodeGrid.GetYndNode(areaid, nodeid);
|
||||
}
|
||||
|
||||
public void UpdateCollisionBoundsGraphics(Bounds b)
|
||||
@ -2080,7 +2099,7 @@ namespace CodeWalker
|
||||
|
||||
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)
|
||||
{
|
||||
Input.keyBindings = kb.Copy();
|
||||
Input.KeyBindings = kb.Copy();
|
||||
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);
|
||||
ToolbarMoveButton.ToolTipText = string.Format("Move ({0})", kb.EditPosition);
|
||||
ToolbarRotateButton.ToolTipText = string.Format("Rotate ({0})", kb.EditRotation);
|
||||
@ -2246,7 +2265,7 @@ namespace CodeWalker
|
||||
|
||||
private void SpawnTestEntity(bool cameraCenter = false)
|
||||
{
|
||||
if (!space.Inited) return;
|
||||
if (!Space.Inited) return;
|
||||
|
||||
Vector3 dir = (cameraCenter ? camera.ViewDirection : camera.MouseRay.Direction);
|
||||
Vector3 ofs = (cameraCenter ? Vector3.Zero : camera.MouseRay.Position);
|
||||
@ -2290,7 +2309,7 @@ namespace CodeWalker
|
||||
|
||||
lock (Renderer.RenderSyncRoot)
|
||||
{
|
||||
space.AddTemporaryEntity(e);
|
||||
Space.AddTemporaryEntity(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2318,13 +2337,13 @@ namespace CodeWalker
|
||||
|
||||
if (isfree && !wasfree)
|
||||
{
|
||||
camEntity.Position = pedEntity.Position;
|
||||
CamEntity.Position = PedEntity.Position;
|
||||
|
||||
pedEntity.Enabled = false;
|
||||
PedEntity.Enabled = false;
|
||||
|
||||
Renderer.timerunning = false;
|
||||
|
||||
camera.SetFollowEntity(camEntity);
|
||||
camera.SetFollowEntity(CamEntity);
|
||||
camera.TargetDistance = 1.0f; //default?
|
||||
camera.Smoothness = Settings.Default.CameraSmoothing;
|
||||
|
||||
@ -2332,13 +2351,13 @@ namespace CodeWalker
|
||||
}
|
||||
else if (!isfree && wasfree)
|
||||
{
|
||||
pedEntity.Position = camEntity.Position;
|
||||
pedEntity.Velocity = Vector3.Zero;
|
||||
pedEntity.Enabled = true;
|
||||
PedEntity.Position = CamEntity.Position;
|
||||
PedEntity.Velocity = Vector3.Zero;
|
||||
PedEntity.Enabled = true;
|
||||
|
||||
Renderer.timerunning = true;
|
||||
|
||||
camera.SetFollowEntity(pedEntity.CameraEntity);
|
||||
camera.SetFollowEntity(PedEntity.CameraEntity);
|
||||
camera.TargetDistance = 0.01f; //1cm
|
||||
camera.Smoothness = 20.0f;
|
||||
|
||||
@ -2403,19 +2422,19 @@ namespace CodeWalker
|
||||
public SpaceRayIntersectResult GetSpaceMouseRay()
|
||||
{
|
||||
SpaceRayIntersectResult ret = new SpaceRayIntersectResult();
|
||||
if (space.Inited && space.BoundsStore != null)
|
||||
if (Space.Inited && Space.BoundsStore != null)
|
||||
{
|
||||
Ray mray = new Ray();
|
||||
mray.Position = camera.MouseRay.Position + camera.Position;
|
||||
mray.Direction = camera.MouseRay.Direction;
|
||||
return space.RayIntersect(mray, float.MaxValue, collisionmeshlayers);
|
||||
return Space.RayIntersect(mray, float.MaxValue, collisionmeshlayers);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public SpaceRayIntersectResult Raycast(Ray ray)
|
||||
{
|
||||
return space.RayIntersect(ray, float.MaxValue, collisionmeshlayers);
|
||||
return Space.RayIntersect(ray, float.MaxValue, collisionmeshlayers);
|
||||
}
|
||||
|
||||
private void UpdateMouseHits()
|
||||
@ -3503,7 +3522,7 @@ namespace CodeWalker
|
||||
}
|
||||
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;
|
||||
@ -4212,43 +4231,43 @@ namespace CodeWalker
|
||||
{
|
||||
|
||||
UpdateStatus("Loading timecycles...");
|
||||
timecycle.Init(gameFileCache, UpdateStatus);
|
||||
timecycle.Init(GameFileCache, UpdateStatus);
|
||||
timecycle.SetTime(Renderer.timeofday);
|
||||
|
||||
UpdateStatus("Loading materials...");
|
||||
BoundsMaterialTypes.Init(gameFileCache);
|
||||
BoundsMaterialTypes.Init(GameFileCache);
|
||||
|
||||
UpdateStatus("Loading weather...");
|
||||
weather.Init(gameFileCache, UpdateStatus, timecycle);
|
||||
weather.Init(GameFileCache, UpdateStatus, timecycle);
|
||||
UpdateWeatherTypesComboBox(weather);
|
||||
|
||||
UpdateStatus("Loading clouds...");
|
||||
clouds.Init(gameFileCache, UpdateStatus, weather);
|
||||
clouds.Init(GameFileCache, UpdateStatus, weather);
|
||||
UpdateCloudTypesComboBox(clouds);
|
||||
|
||||
UpdateStatus("Loading water...");
|
||||
water.Init(gameFileCache, UpdateStatus);
|
||||
Water.Init(GameFileCache, UpdateStatus);
|
||||
|
||||
UpdateStatus("Loading trains...");
|
||||
trains.Init(gameFileCache, UpdateStatus);
|
||||
Trains.Init(GameFileCache, UpdateStatus);
|
||||
|
||||
UpdateStatus("Loading scenarios...");
|
||||
scenarios.Init(gameFileCache, UpdateStatus, timecycle);
|
||||
Scenarios.Init(GameFileCache, UpdateStatus, timecycle);
|
||||
|
||||
UpdateStatus("Loading popzones...");
|
||||
popzones.Init(gameFileCache, UpdateStatus);
|
||||
PopZones.Init(GameFileCache, UpdateStatus);
|
||||
|
||||
UpdateStatus("Loading heightmaps...");
|
||||
heightmaps.Init(gameFileCache, UpdateStatus);
|
||||
Heightmaps.Init(GameFileCache, UpdateStatus);
|
||||
|
||||
UpdateStatus("Loading watermaps...");
|
||||
watermaps.Init(gameFileCache, UpdateStatus);
|
||||
Watermaps.Init(GameFileCache, UpdateStatus);
|
||||
|
||||
UpdateStatus("Loading audio zones...");
|
||||
audiozones.Init(gameFileCache, UpdateStatus);
|
||||
AudioZones.Init(GameFileCache, UpdateStatus);
|
||||
|
||||
UpdateStatus("Loading world...");
|
||||
space.Init(gameFileCache, UpdateStatus);
|
||||
Space.Init(GameFileCache, UpdateStatus);
|
||||
|
||||
UpdateStatus("World loaded");
|
||||
|
||||
@ -4264,7 +4283,7 @@ namespace CodeWalker
|
||||
{
|
||||
lock (Renderer.RenderSyncRoot)
|
||||
{
|
||||
if (gameFileCache.SetDlcLevel(dlc, enable))
|
||||
if (GameFileCache.SetDlcLevel(dlc, enable))
|
||||
{
|
||||
LoadWorld();
|
||||
}
|
||||
@ -4283,9 +4302,9 @@ namespace CodeWalker
|
||||
{
|
||||
lock (Renderer.RenderSyncRoot)
|
||||
{
|
||||
if (gameFileCache.SetModsEnabled(enable))
|
||||
if (GameFileCache.SetModsEnabled(enable))
|
||||
{
|
||||
UpdateDlcListComboBox(gameFileCache.DlcNameList);
|
||||
UpdateDlcListComboBox(GameFileCache.DlcNameList);
|
||||
|
||||
LoadWorld();
|
||||
}
|
||||
@ -4326,18 +4345,18 @@ namespace CodeWalker
|
||||
return;
|
||||
}
|
||||
|
||||
gameFileCache.UpdateStatus += UpdateStatus;
|
||||
gameFileCache.ErrorLog += LogError;
|
||||
while (gameFileCache.IsIniting)
|
||||
GameFileCache.UpdateStatus += UpdateStatus;
|
||||
GameFileCache.ErrorLog += LogError;
|
||||
while (GameFileCache.IsIniting)
|
||||
{
|
||||
await Task.Delay(0);
|
||||
}
|
||||
if (!gameFileCache.IsInited)
|
||||
if (!GameFileCache.IsInited)
|
||||
{
|
||||
gameFileCache.Init();
|
||||
GameFileCache.Init();
|
||||
}
|
||||
|
||||
UpdateDlcListComboBox(gameFileCache.DlcNameList);
|
||||
UpdateDlcListComboBox(GameFileCache.DlcNameList);
|
||||
|
||||
EnableCacheDependentUI();
|
||||
|
||||
@ -4351,7 +4370,7 @@ namespace CodeWalker
|
||||
|
||||
EnableDLCModsUI();
|
||||
|
||||
Task.Run(async () =>
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -4373,13 +4392,13 @@ namespace CodeWalker
|
||||
Console.WriteLine("Renderer ContentThread stopped");
|
||||
});
|
||||
|
||||
Task.Run(async () =>
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
while (formopen && !IsDisposed && !CancellationToken.IsCancellationRequested) //main asset loop
|
||||
{
|
||||
bool fcItemsPending = gameFileCache.ContentThreadProc();
|
||||
bool fcItemsPending = GameFileCache.ContentThreadProc();
|
||||
|
||||
if (!fcItemsPending)
|
||||
{
|
||||
@ -4413,6 +4432,8 @@ namespace CodeWalker
|
||||
|
||||
private Stopwatch lastStatusUpdate = Stopwatch.StartNew();
|
||||
private TimeSpan updateInterval = TimeSpan.FromSeconds(0.05);
|
||||
private Renderer renderer;
|
||||
|
||||
private void UpdateStatus(string text)
|
||||
{
|
||||
try
|
||||
@ -4527,13 +4548,13 @@ namespace CodeWalker
|
||||
{
|
||||
DlcLevelComboBox.Items.Add(dlcname);
|
||||
}
|
||||
if (string.IsNullOrEmpty(gameFileCache.SelectedDlc))
|
||||
if (string.IsNullOrEmpty(GameFileCache.SelectedDlc))
|
||||
{
|
||||
DlcLevelComboBox.SelectedIndex = dlcnames.Count - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = DlcLevelComboBox.FindString(gameFileCache.SelectedDlc);
|
||||
int idx = DlcLevelComboBox.FindString(GameFileCache.SelectedDlc);
|
||||
DlcLevelComboBox.SelectedIndex = (idx > 0) ? idx : (dlcnames.Count - 1);
|
||||
}
|
||||
}
|
||||
@ -4806,7 +4827,7 @@ namespace CodeWalker
|
||||
|
||||
EnableModsCheckBox.Checked = s.EnableMods;
|
||||
DlcLevelComboBox.Text = s.DLC;
|
||||
gameFileCache.SelectedDlc = s.DLC;
|
||||
GameFileCache.SelectedDlc = s.DLC;
|
||||
EnableDlcCheckBox.Checked = !string.IsNullOrEmpty(s.DLC);
|
||||
}
|
||||
private void SaveSettings()
|
||||
@ -4849,8 +4870,8 @@ namespace CodeWalker
|
||||
s.Clouds = CloudsComboBox.Text;
|
||||
|
||||
//additional settings from gamefilecache...
|
||||
s.EnableMods = gameFileCache.EnableMods;
|
||||
s.DLC = gameFileCache.EnableDlc ? gameFileCache.SelectedDlc : "";
|
||||
s.EnableMods = GameFileCache.EnableMods;
|
||||
s.DLC = GameFileCache.EnableDlc ? GameFileCache.SelectedDlc : "";
|
||||
|
||||
s.Save();
|
||||
}
|
||||
@ -6045,9 +6066,10 @@ namespace CodeWalker
|
||||
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)
|
||||
@ -6379,7 +6401,7 @@ namespace CodeWalker
|
||||
Input.KeyDown(e, enablemove);
|
||||
|
||||
var k = e.KeyCode;
|
||||
var kb = Input.keyBindings;
|
||||
var kb = Input.KeyBindings;
|
||||
bool ctrl = Input.CtrlPressed;
|
||||
bool shift = Input.ShiftPressed;
|
||||
|
||||
@ -6977,7 +6999,7 @@ namespace CodeWalker
|
||||
|
||||
private void ToolsMenuAudioExplorer_Click(object sender, EventArgs e)
|
||||
{
|
||||
AudioExplorerForm f = new AudioExplorerForm(gameFileCache);
|
||||
AudioExplorerForm f = new AudioExplorerForm();
|
||||
f.Show(this);
|
||||
}
|
||||
|
||||
@ -6988,7 +7010,7 @@ namespace CodeWalker
|
||||
|
||||
private void ToolsMenuBinarySearch_Click(object sender, EventArgs e)
|
||||
{
|
||||
BinarySearchForm f = new BinarySearchForm(gameFileCache);
|
||||
BinarySearchForm f = new BinarySearchForm();
|
||||
f.Show(this);
|
||||
}
|
||||
|
||||
@ -7000,7 +7022,7 @@ namespace CodeWalker
|
||||
|
||||
private void ToolsMenuJenkInd_Click(object sender, EventArgs e)
|
||||
{
|
||||
JenkIndForm f = new JenkIndForm(gameFileCache);
|
||||
JenkIndForm f = new JenkIndForm();
|
||||
f.Show();
|
||||
}
|
||||
|
||||
@ -7934,6 +7956,10 @@ namespace CodeWalker
|
||||
|
||||
private void AntiAliasingTrackBar_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (AntiAliasingTrackBar.Value == Settings.Default.AntiAliasing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Settings.Default.AntiAliasing = AntiAliasingTrackBar.Value;
|
||||
Settings.Default.Save();
|
||||
AntiAliasingValue.Text = Settings.Default.AntiAliasing.ToString();
|
||||
|
Loading…
Reference in New Issue
Block a user