mirror of
https://mirror.ghproxy.com/https://github.com/dexyfex/CodeWalker
synced 2024-11-16 20:17:30 +08:00
Many optimizations and bug fixes
This commit is contained in:
parent
aed7a1e051
commit
ba72dadd16
38
CodeWalker.Benchmarks/App.config
Normal file
38
CodeWalker.Benchmarks/App.config
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||||
|
</startup>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Reflection.Metadata" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
200
CodeWalker.Benchmarks/Benchmarks.cs
Normal file
200
CodeWalker.Benchmarks/Benchmarks.cs
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
using BenchmarkDotNet.Attributes;
|
||||||
|
using BenchmarkDotNet.Configs;
|
||||||
|
using BenchmarkDotNet.Environments;
|
||||||
|
using BenchmarkDotNet.Jobs;
|
||||||
|
using CodeWalker.GameFiles;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
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>
|
||||||
|
<residentTxd>vehshare</residentTxd>
|
||||||
|
<residentAnims />
|
||||||
|
<InitDatas>
|
||||||
|
<Item>
|
||||||
|
<modelName>brabusgt600</modelName><txdName>brabusgt600</txdName>
|
||||||
|
<handlingId>brabusgt600</handlingId>
|
||||||
|
<gameName>GT 600</gameName>
|
||||||
|
<vehicleMakeName>BRABUS</vehicleMakeName>
|
||||||
|
<expressionDictName>null</expressionDictName>
|
||||||
|
<expressionName>null</expressionName>
|
||||||
|
<animConvRoofDictName>null</animConvRoofDictName>
|
||||||
|
<animConvRoofName>null</animConvRoofName>
|
||||||
|
<animConvRoofWindowsAffected />
|
||||||
|
<ptfxAssetName>null</ptfxAssetName>
|
||||||
|
<audioNameHash>ta176m177</audioNameHash>
|
||||||
|
<layout>LAYOUT_LOW</layout>
|
||||||
|
<coverBoundOffsets>BULLET_COVER_OFFSET_INFO</coverBoundOffsets>
|
||||||
|
<explosionInfo>EXPLOSION_INFO_DEFAULT</explosionInfo>
|
||||||
|
<scenarioLayout />
|
||||||
|
<cameraName>DEFAULT_FOLLOW_VEHICLE_CAMERA</cameraName>
|
||||||
|
<aimCameraName>MID_BOX_VEHICLE_AIM_CAMERA</aimCameraName>
|
||||||
|
<bonnetCameraName>VEHICLE_BONNET_CAMERA_NEAR_EXTRA_HIGH</bonnetCameraName>
|
||||||
|
<povCameraName>DEFAULT_POV_CAMERA</povCameraName>
|
||||||
|
<FirstPersonDriveByIKOffset x=""0.000000"" y=""-0.060000"" z=""-0.005000"" />
|
||||||
|
<FirstPersonDriveByUnarmedIKOffset x=""0.000000"" y=""-0.150000"" z=""0.000000"" />
|
||||||
|
<FirstPersonProjectileDriveByIKOffset x=""0.025000"" y=""-0.100000"" z=""0.050000"" />
|
||||||
|
<FirstPersonProjectileDriveByPassengerIKOffset x=""-0.025000"" y=""-0.100000"" z=""0.050000"" />
|
||||||
|
<FirstPersonDriveByLeftPassengerIKOffset x=""0.000000"" y=""0.000000"" z=""0.000000"" />
|
||||||
|
<FirstPersonDriveByRightPassengerIKOffset x=""0.000000"" y=""-0.060000"" z=""-0.005000"" />
|
||||||
|
<FirstPersonDriveByLeftPassengerUnarmedIKOffset x=""0.000000"" y=""0.000000"" z=""0.000000"" />
|
||||||
|
<FirstPersonDriveByRightPassengerUnarmedIKOffset x=""0.000000"" y=""-0.150000"" z=""0.000000"" />
|
||||||
|
<FirstPersonMobilePhoneOffset x=""0.125000"" y=""0.175000"" z=""0.513000"" />
|
||||||
|
<FirstPersonPassengerMobilePhoneOffset x=""0.136000"" y=""0.123000"" z=""0.425000"" />
|
||||||
|
<PovCameraOffset x=""0.000000"" y=""-0.200000"" z=""0.615000"" />
|
||||||
|
<PovCameraVerticalAdjustmentForRollCage value=""0.000000"" />
|
||||||
|
<PovPassengerCameraOffset x=""0.000000"" y=""0.000000"" z=""0.000000"" />
|
||||||
|
<vfxInfoName>VFXVEHICLEINFO_CAR_BULLET</vfxInfoName>
|
||||||
|
<shouldUseCinematicViewMode value=""true"" />
|
||||||
|
<shouldCameraTransitionOnClimbUpDown value=""false"" />
|
||||||
|
<shouldCameraIgnoreExiting value=""false"" />
|
||||||
|
<AllowPretendOccupants value=""true"" />
|
||||||
|
<AllowJoyriding value=""true"" />
|
||||||
|
<AllowSundayDriving value=""true"" />
|
||||||
|
<AllowBodyColorMapping value=""true"" />
|
||||||
|
<wheelScale value=""0.293500"" />
|
||||||
|
<wheelScaleRear value=""0.293500"" />
|
||||||
|
<dirtLevelMin value=""0.000000"" />
|
||||||
|
<dirtLevelMax value=""0.450000"" />
|
||||||
|
<envEffScaleMin value=""0.000000"" />
|
||||||
|
<envEffScaleMax value=""1.000000"" />
|
||||||
|
<envEffScaleMin2 value=""0.000000"" />
|
||||||
|
<envEffScaleMax2 value=""1.000000"" />
|
||||||
|
<damageMapScale value=""0.600000"" />
|
||||||
|
<damageOffsetScale value=""0.400000"" />
|
||||||
|
<diffuseTint value=""0xAA0A0A0A"" />
|
||||||
|
<steerWheelMult value=""1.000000"" />
|
||||||
|
<HDTextureDist value=""5.000000"" />
|
||||||
|
<lodDistances content=""float_array"">
|
||||||
|
60.000000
|
||||||
|
80.000000
|
||||||
|
100.000000
|
||||||
|
120.000000
|
||||||
|
500.000000
|
||||||
|
500.000000
|
||||||
|
</lodDistances>
|
||||||
|
<minSeatHeight value=""0.813"" />
|
||||||
|
<identicalModelSpawnDistance value=""80"" />
|
||||||
|
<maxNumOfSameColor value=""1"" />
|
||||||
|
<defaultBodyHealth value=""1000.000000"" />
|
||||||
|
<pretendOccupantsScale value=""1.000000"" />
|
||||||
|
<visibleSpawnDistScale value=""1.000000"" />
|
||||||
|
<trackerPathWidth value=""2.000000"" />
|
||||||
|
<weaponForceMult value=""1.000000"" />
|
||||||
|
<frequency value=""10"" />
|
||||||
|
<swankness>SWANKNESS_3</swankness>
|
||||||
|
<maxNum value=""1"" />
|
||||||
|
<flags>FLAG_SPORTS FLAG_RICH_CAR FLAG_NO_BROKEN_DOWN_SCENARIO FLAG_RECESSED_TAILLIGHT_CORONAS FLAG_NO_HEAVY_BRAKE_ANIMATION</flags>
|
||||||
|
<type>VEHICLE_TYPE_CAR</type>
|
||||||
|
<plateType>VPT_FRONT_AND_BACK_PLATES</plateType>
|
||||||
|
<dashboardType>VDT_BANSHEE</dashboardType>
|
||||||
|
<vehicleClass>VC_SPORT</vehicleClass>
|
||||||
|
<wheelType>VWT_HIEND</wheelType>
|
||||||
|
<trailers>
|
||||||
|
<Item>docktrailer</Item>
|
||||||
|
<Item>trailers</Item>
|
||||||
|
<Item>trailers2</Item>
|
||||||
|
<Item>trailers3</Item>
|
||||||
|
<Item>trailers4</Item>
|
||||||
|
<Item>tanker</Item>
|
||||||
|
<Item>trailerlogs</Item>
|
||||||
|
<Item>tr2</Item>
|
||||||
|
<Item>trflat</Item>
|
||||||
|
</trailers>
|
||||||
|
<additionalTrailers />
|
||||||
|
<drivers>
|
||||||
|
<Item>
|
||||||
|
<driverName>S_M_Y_Cop_01</driverName>
|
||||||
|
<npcName/>
|
||||||
|
</Item>
|
||||||
|
</drivers>
|
||||||
|
<extraIncludes />
|
||||||
|
<doorsWithCollisionWhenClosed />
|
||||||
|
<driveableDoors />
|
||||||
|
<bumpersNeedToCollideWithMap value=""false"" />
|
||||||
|
<needsRopeTexture value=""false"" />
|
||||||
|
<requiredExtras />
|
||||||
|
<rewards />
|
||||||
|
<cinematicPartCamera>
|
||||||
|
<Item>WHEEL_FRONT_RIGHT_CAMERA</Item>
|
||||||
|
<Item>WHEEL_FRONT_LEFT_CAMERA</Item>
|
||||||
|
<Item>WHEEL_REAR_RIGHT_CAMERA</Item>
|
||||||
|
<Item>WHEEL_REAR_LEFT_CAMERA</Item>
|
||||||
|
</cinematicPartCamera>
|
||||||
|
<NmBraceOverrideSet />
|
||||||
|
<buoyancySphereOffset x=""0.000000"" y=""0.000000"" z=""0.000000"" />
|
||||||
|
<buoyancySphereSizeScale value=""1.000000"" />
|
||||||
|
<pOverrideRagdollThreshold type=""CVehicleModelInfo__CVehicleOverrideRagdollThreshold"">
|
||||||
|
<MinComponent value=""22"" />
|
||||||
|
<MaxComponent value=""22"" />
|
||||||
|
<ThresholdMult value=""1.500000"" />
|
||||||
|
</pOverrideRagdollThreshold>
|
||||||
|
<firstPersonDrivebyData>
|
||||||
|
<Item>LOW_BULLET_FRONT_LEFT</Item>
|
||||||
|
<Item>LOW_BULLET_FRONT_RIGHT</Item>
|
||||||
|
</firstPersonDrivebyData>
|
||||||
|
</Item>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</InitDatas>
|
||||||
|
<txdRelationships>
|
||||||
|
<Item>
|
||||||
|
<parent>vehicles_banshee_interior</parent>
|
||||||
|
<child>brabusgt600</child>
|
||||||
|
</Item>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</txdRelationships>
|
||||||
|
</CVehicleModelInfo__InitDataList>";
|
||||||
|
|
||||||
|
private byte[] data;
|
||||||
|
private RpfFileEntry fileEntry;
|
||||||
|
|
||||||
|
[GlobalSetup]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
data = Encoding.UTF8.GetBytes(markup);
|
||||||
|
fileEntry = RpfFile.CreateFileEntry("kaas.meta", "saak.meta", ref data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
201
CodeWalker.Benchmarks/CodeWalker.Benchmarks.csproj
Normal file
201
CodeWalker.Benchmarks/CodeWalker.Benchmarks.csproj
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
<?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')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}</ProjectGuid>
|
||||||
|
<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>
|
||||||
|
</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>
|
||||||
|
</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>
|
17
CodeWalker.Benchmarks/Program.cs
Normal file
17
CodeWalker.Benchmarks/Program.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
using BenchmarkDotNet.Running;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CodeWalker.Benchmarks
|
||||||
|
{
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
BenchmarkRunner.Run<Benchmarks>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
CodeWalker.Benchmarks/Properties/AssemblyInfo.cs
Normal file
36
CodeWalker.Benchmarks/Properties/AssemblyInfo.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
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("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// 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")]
|
42
CodeWalker.Benchmarks/packages.config
Normal file
42
CodeWalker.Benchmarks/packages.config
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<?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>
|
@ -7,11 +7,16 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<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="directxtex_desktop_win10" Version="2023.3.30.1" />
|
||||||
|
<PackageReference Include="Microsoft.Bcl.HashCode" Version="1.1.1" />
|
||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="SharpDX" Version="4.2.0" />
|
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||||
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
|
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||||
|
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -70,10 +70,10 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(Name))
|
if (!string.IsNullOrEmpty(Name))
|
||||||
{
|
{
|
||||||
var nl = Name.ToLowerInvariant();
|
var nl = Name;
|
||||||
var fn = Path.GetFileNameWithoutExtension(nl);
|
var fn = Path.GetFileNameWithoutExtension(nl);
|
||||||
JenkIndex.Ensure(fn + "_left");
|
JenkIndex.EnsureLower(fn + "_left");
|
||||||
JenkIndex.Ensure(fn + "_right");
|
JenkIndex.EnsureLower(fn + "_right");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((data == null) || (data.Length < 8))
|
if ((data == null) || (data.Length < 8))
|
||||||
|
@ -40,7 +40,7 @@ namespace CodeWalker.GameFiles
|
|||||||
RpfFileEntry = entry;
|
RpfFileEntry = entry;
|
||||||
Name = entry.Name;
|
Name = entry.Name;
|
||||||
|
|
||||||
if (!entry.NameLower.EndsWith("_hd.dat"))
|
if (!entry.Name.EndsWith("_hd.dat", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
HD = false;
|
HD = false;
|
||||||
GridSize = 16;
|
GridSize = 16;
|
||||||
|
@ -1186,7 +1186,7 @@ namespace CodeWalker.GameFiles
|
|||||||
SlotGS = br.ReadUInt16(); //6, 5
|
SlotGS = br.ReadUInt16(); //6, 5
|
||||||
SlotHS = br.ReadUInt16(); //6, 5
|
SlotHS = br.ReadUInt16(); //6, 5
|
||||||
Name = FxcFile.ReadString(br); // <fxc name> _locals //"rage_matrices", "misc_globals", "lighting_globals", "more_stuff"
|
Name = FxcFile.ReadString(br); // <fxc name> _locals //"rage_matrices", "misc_globals", "lighting_globals", "more_stuff"
|
||||||
JenkIndex.Ensure(Name?.ToLowerInvariant()); //why not :P
|
JenkIndex.EnsureLower(Name); //why not :P
|
||||||
}
|
}
|
||||||
public void Write(BinaryWriter bw)
|
public void Write(BinaryWriter bw)
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,7 @@ namespace CodeWalker.GameFiles
|
|||||||
FilePath = Name;
|
FilePath = Name;
|
||||||
|
|
||||||
|
|
||||||
if (entry.NameLower.EndsWith(".ymt"))
|
if (entry.Name.EndsWith(".ymt", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
MemoryStream ms = new MemoryStream(data);
|
MemoryStream ms = new MemoryStream(data);
|
||||||
if (RbfFile.IsRBF(ms))
|
if (RbfFile.IsRBF(ms))
|
||||||
@ -57,7 +57,7 @@ namespace CodeWalker.GameFiles
|
|||||||
//not an RBF file...
|
//not an RBF file...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (entry.NameLower.EndsWith(".meta"))
|
else if (entry.Name.EndsWith(".meta", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
//required for update\x64\dlcpacks\mpheist\dlc.rpf\common\data\gtxd.meta and update\x64\dlcpacks\mpluxe\dlc.rpf\common\data\gtxd.meta
|
//required for update\x64\dlcpacks\mpheist\dlc.rpf\common\data\gtxd.meta and update\x64\dlcpacks\mpluxe\dlc.rpf\common\data\gtxd.meta
|
||||||
string xml = TextUtil.GetUTF8Text(data);
|
string xml = TextUtil.GetUTF8Text(data);
|
||||||
|
@ -6,6 +6,7 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
@ -172,7 +173,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public static class GlobalText
|
public static class GlobalText
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<uint, string> Index = new ();
|
public static ConcurrentDictionary<uint, string> Index = new (4, 24000);
|
||||||
private static object syncRoot = new object();
|
private static object syncRoot = new object();
|
||||||
|
|
||||||
public static volatile bool FullIndexBuilt = false;
|
public static volatile bool FullIndexBuilt = false;
|
||||||
|
@ -798,9 +798,13 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void WriteToStream(byte[] value, bool ignoreEndianess = false)
|
protected override void WriteToStream(byte[] value, bool ignoreEndianess = false, int count = -1, int offset = 0)
|
||||||
{
|
{
|
||||||
position += value.Length;
|
if (count == -1)
|
||||||
|
{
|
||||||
|
count = value.Length;
|
||||||
|
}
|
||||||
|
position += count;
|
||||||
length = Math.Max(length, position);
|
length = Math.Max(length, position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,6 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void NonMetaLoad(byte[] data)
|
private void NonMetaLoad(byte[] data)
|
||||||
{
|
{
|
||||||
//non meta not supported yet! but see what's in there...
|
//non meta not supported yet! but see what's in there...
|
||||||
@ -103,22 +102,6 @@ namespace CodeWalker.GameFiles
|
|||||||
Pso.Load(ms);
|
Pso.Load(ms);
|
||||||
LoadPso();
|
LoadPso();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ using System.Xml;
|
|||||||
|
|
||||||
using TC = System.ComponentModel.TypeConverterAttribute;
|
using TC = System.ComponentModel.TypeConverterAttribute;
|
||||||
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
using EXP = System.ComponentModel.ExpandableObjectConverter;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
@ -34,7 +35,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
//can be PSO .ymt or XML .meta
|
//can be PSO .ymt or XML .meta
|
||||||
MemoryStream ms = new MemoryStream(data);
|
using MemoryStream ms = new MemoryStream(data);
|
||||||
if (PsoFile.IsPSO(ms))
|
if (PsoFile.IsPSO(ms))
|
||||||
{
|
{
|
||||||
Pso = new PsoFile();
|
Pso = new PsoFile();
|
||||||
@ -46,26 +47,28 @@ namespace CodeWalker.GameFiles
|
|||||||
Xml = TextUtil.GetUTF8Text(data);
|
Xml = TextUtil.GetUTF8Text(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
XmlDocument xdoc = new XmlDocument();
|
using var textReader = new StringReader(Xml);
|
||||||
if (!string.IsNullOrEmpty(Xml))
|
|
||||||
{
|
//XmlDocument xdoc = new XmlDocument();
|
||||||
try
|
//if (!string.IsNullOrEmpty(Xml))
|
||||||
{
|
//{
|
||||||
xdoc.LoadXml(Xml);
|
// try
|
||||||
}
|
// {
|
||||||
catch (Exception ex)
|
// xdoc.LoadXml(Xml);
|
||||||
{
|
// }
|
||||||
var msg = ex.Message;
|
// catch (Exception ex)
|
||||||
}
|
// {
|
||||||
}
|
// var msg = ex.Message;
|
||||||
else
|
// }
|
||||||
{ }
|
//}
|
||||||
|
|
||||||
|
using var xmlReader = XmlReader.Create(textReader);
|
||||||
|
|
||||||
|
|
||||||
if (xdoc.DocumentElement != null)
|
//if (xdoc.DocumentElement != null)
|
||||||
{
|
//{
|
||||||
InitDataList = new CPedModelInfo__InitDataList(xdoc.DocumentElement);
|
InitDataList = new CPedModelInfo__InitDataList(xmlReader);
|
||||||
}
|
//}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -84,6 +87,87 @@ namespace CodeWalker.GameFiles
|
|||||||
public CTxdRelationship[] txdRelationships { get; set; }
|
public CTxdRelationship[] txdRelationships { get; set; }
|
||||||
public CMultiTxdRelationship[] multiTxdRelationships { get; set; }
|
public CMultiTxdRelationship[] multiTxdRelationships { get; set; }
|
||||||
|
|
||||||
|
public CPedModelInfo__InitDataList(XmlReader reader)
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
reader.MoveToContent();
|
||||||
|
|
||||||
|
//var _ = xmlReader.Name switch
|
||||||
|
//{
|
||||||
|
// "residentTxd" => ResidentTxd = Xml.GetChildInnerText(xmlReader, "residentTxd"),
|
||||||
|
// "InitDatas" => LoadInitDatas(xmlReader),
|
||||||
|
// "txdRelationships" => LoadTxdRelationships(xmlReader),
|
||||||
|
// _ => throw new Exception()
|
||||||
|
//};
|
||||||
|
|
||||||
|
switch (reader.Name)
|
||||||
|
{
|
||||||
|
case string Name when Name.Equals("residentTxd", StringComparison.OrdinalIgnoreCase):
|
||||||
|
residentTxd = Xml.GetChildInnerText(reader, "residentTxd");
|
||||||
|
break;
|
||||||
|
case string Name when Name.Equals("InitDatas", StringComparison.OrdinalIgnoreCase):
|
||||||
|
if (reader.IsEmptyElement)
|
||||||
|
{
|
||||||
|
reader.ReadStartElement();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reader.ReadStartElement();
|
||||||
|
var initDatasList = new List<CPedModelInfo__InitData>();
|
||||||
|
|
||||||
|
while (reader.IsItemElement())
|
||||||
|
{
|
||||||
|
initDatasList.Add(new CPedModelInfo__InitData(reader));
|
||||||
|
}
|
||||||
|
if (initDatasList.Count > 0)
|
||||||
|
{
|
||||||
|
InitDatas = initDatasList.ToArray();
|
||||||
|
}
|
||||||
|
reader.ReadEndElement();
|
||||||
|
break;
|
||||||
|
case string Name when Name.Equals("txdRelationships", StringComparison.OrdinalIgnoreCase):
|
||||||
|
if (reader.IsEmptyElement)
|
||||||
|
{
|
||||||
|
reader.ReadStartElement();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reader.ReadStartElement();
|
||||||
|
var txdRelationshipsList = new List<CTxdRelationship>();
|
||||||
|
|
||||||
|
while (reader.IsItemElement())
|
||||||
|
{
|
||||||
|
txdRelationshipsList.Add(new CTxdRelationship(reader));
|
||||||
|
}
|
||||||
|
reader.ReadEndElement();
|
||||||
|
if (txdRelationshipsList.Count > 0)
|
||||||
|
{
|
||||||
|
txdRelationships = txdRelationshipsList.ToArray();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case string Name when Name.Equals("multiTxdRelationships", StringComparison.OrdinalIgnoreCase):
|
||||||
|
if (reader.IsEmptyElement)
|
||||||
|
{
|
||||||
|
reader.ReadStartElement();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
reader.ReadStartElement();
|
||||||
|
var multiTxdList = new List<CMultiTxdRelationship>();
|
||||||
|
while (reader.IsItemElement())
|
||||||
|
{
|
||||||
|
multiTxdList.Add(new CMultiTxdRelationship(reader));
|
||||||
|
}
|
||||||
|
reader.ReadEndElement();
|
||||||
|
if (multiTxdList.Count > 0)
|
||||||
|
{
|
||||||
|
multiTxdRelationships = multiTxdList.ToArray();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CPedModelInfo__InitDataList(XmlNode node)
|
public CPedModelInfo__InitDataList(XmlNode node)
|
||||||
{
|
{
|
||||||
XmlNodeList items;
|
XmlNodeList items;
|
||||||
@ -126,7 +210,6 @@ namespace CodeWalker.GameFiles
|
|||||||
multiTxdRelationships[i] = new CMultiTxdRelationship(items[i]);
|
multiTxdRelationships[i] = new CMultiTxdRelationship(items[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,6 +287,249 @@ namespace CodeWalker.GameFiles
|
|||||||
public float DefaultRemoveRangeMultiplier { get; set; }
|
public float DefaultRemoveRangeMultiplier { get; set; }
|
||||||
public bool AllowCloseSpawning { get; set; }
|
public bool AllowCloseSpawning { get; set; }
|
||||||
|
|
||||||
|
public CPedModelInfo__InitData(XmlReader reader)
|
||||||
|
{
|
||||||
|
reader.ReadStartElement("Item");
|
||||||
|
while (reader.Name != "Item" && reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Item")
|
||||||
|
{
|
||||||
|
reader.ReadEndElement();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (reader.MoveToContent() != XmlNodeType.Element && reader.Read())
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (reader.Name)
|
||||||
|
{
|
||||||
|
case "Name":
|
||||||
|
Name = Xml.GetChildInnerText(reader, "Name");
|
||||||
|
break;
|
||||||
|
case "PropsName":
|
||||||
|
PropsName = Xml.GetChildInnerText(reader, "PropsName");
|
||||||
|
break;
|
||||||
|
case "ClipDictionaryName":
|
||||||
|
ClipDictionaryName = Xml.GetChildInnerText(reader, "ClipDictionaryName");
|
||||||
|
break;
|
||||||
|
case "BlendShapeFileName":
|
||||||
|
BlendShapeFileName = Xml.GetChildInnerText(reader, "BlendShapeFileName");
|
||||||
|
break;
|
||||||
|
case "ExpressionSetName":
|
||||||
|
ExpressionSetName = Xml.GetChildInnerText(reader, "ExpressionSetName");
|
||||||
|
break;
|
||||||
|
case "ExpressionDictionaryName":
|
||||||
|
ExpressionDictionaryName = Xml.GetChildInnerText(reader, "ExpressionDictionaryName");
|
||||||
|
break;
|
||||||
|
case "ExpressionName":
|
||||||
|
ExpressionName = Xml.GetChildInnerText(reader, "ExpressionName");
|
||||||
|
break;
|
||||||
|
case "Pedtype":
|
||||||
|
Pedtype = Xml.GetChildInnerText(reader, "Pedtype");
|
||||||
|
break;
|
||||||
|
case "MovementClipSet":
|
||||||
|
MovementClipSet = Xml.GetChildInnerText(reader, "MovementClipSet");
|
||||||
|
break;
|
||||||
|
case "MovementClipSets":
|
||||||
|
var clipSetsList = new List<string>();
|
||||||
|
foreach(var item in Xml.IterateItems(reader, "MovementClipSets"))
|
||||||
|
{
|
||||||
|
clipSetsList.Add(item.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
MovementClipSets = clipSetsList.ToArray();
|
||||||
|
break;
|
||||||
|
case "StrafeClipSet":
|
||||||
|
StrafeClipSet = Xml.GetChildInnerText(reader, "StrafeClipSet");
|
||||||
|
break;
|
||||||
|
case "MovementToStrafeClipSet":
|
||||||
|
MovementToStrafeClipSet = Xml.GetChildInnerText(reader, "MovementToStrafeClipSet");
|
||||||
|
break;
|
||||||
|
case "InjuredStrafeClipSet":
|
||||||
|
InjuredStrafeClipSet = Xml.GetChildInnerText(reader, "InjuredStrafeClipSet");
|
||||||
|
break;
|
||||||
|
case "FullBodyDamageClipSet":
|
||||||
|
FullBodyDamageClipSet = Xml.GetChildInnerText(reader, "FullBodyDamageClipSet");
|
||||||
|
break;
|
||||||
|
case "AdditiveDamageClipSet":
|
||||||
|
AdditiveDamageClipSet = Xml.GetChildInnerText(reader, "AdditiveDamageClipSet");
|
||||||
|
break;
|
||||||
|
case "DefaultGestureClipSet":
|
||||||
|
DefaultGestureClipSet = Xml.GetChildInnerText(reader, "DefaultGestureClipSet");
|
||||||
|
break;
|
||||||
|
case "FacialClipsetGroupName":
|
||||||
|
FacialClipsetGroupName = Xml.GetChildInnerText(reader, "FacialClipsetGroupName");
|
||||||
|
break;
|
||||||
|
case "DefaultVisemeClipSet":
|
||||||
|
DefaultVisemeClipSet = Xml.GetChildInnerText(reader, "DefaultVisemeClipSet");
|
||||||
|
break;
|
||||||
|
case "SidestepClipSet":
|
||||||
|
SidestepClipSet = Xml.GetChildInnerText(reader, "SidestepClipSet");
|
||||||
|
break;
|
||||||
|
case "PoseMatcherName":
|
||||||
|
PoseMatcherName = Xml.GetChildInnerText(reader, "PoseMatcherName");
|
||||||
|
break;
|
||||||
|
case "PoseMatcherProneName":
|
||||||
|
PoseMatcherProneName = Xml.GetChildInnerText(reader, "PoseMatcherProneName");
|
||||||
|
break;
|
||||||
|
case "GetupSetHash":
|
||||||
|
GetupSetHash = Xml.GetChildInnerText(reader, "GetupSetHash");
|
||||||
|
break;
|
||||||
|
case "CreatureMetadataName":
|
||||||
|
CreatureMetadataName = Xml.GetChildInnerText(reader, "CreatureMetadataName");
|
||||||
|
break;
|
||||||
|
case "DecisionMakerName":
|
||||||
|
DecisionMakerName = Xml.GetChildInnerText(reader, "DecisionMakerName");
|
||||||
|
break;
|
||||||
|
case "MotionTaskDataSetName":
|
||||||
|
MotionTaskDataSetName = Xml.GetChildInnerText(reader, "MotionTaskDataSetName");
|
||||||
|
break;
|
||||||
|
case "DefaultTaskDataSetName":
|
||||||
|
DefaultTaskDataSetName = Xml.GetChildInnerText(reader, "DefaultTaskDataSetName");
|
||||||
|
break;
|
||||||
|
case "PedCapsuleName":
|
||||||
|
PedCapsuleName = Xml.GetChildInnerText(reader, "PedCapsuleName");
|
||||||
|
break;
|
||||||
|
case "PedLayoutName":
|
||||||
|
PedLayoutName = Xml.GetChildInnerText(reader, "PedLayoutName");
|
||||||
|
break;
|
||||||
|
case "PedComponentSetName":
|
||||||
|
PedComponentSetName = Xml.GetChildInnerText(reader, "PedComponentSetName");
|
||||||
|
break;
|
||||||
|
case "PedComponentClothName":
|
||||||
|
PedComponentClothName = Xml.GetChildInnerText(reader, "PedComponentClothName");
|
||||||
|
break;
|
||||||
|
case "PedIKSettingsName":
|
||||||
|
PedIKSettingsName = Xml.GetChildInnerText(reader, "PedIKSettingsName");
|
||||||
|
break;
|
||||||
|
case "TaskDataName":
|
||||||
|
TaskDataName = Xml.GetChildInnerText(reader, "TaskDataName");
|
||||||
|
break;
|
||||||
|
case "IsStreamedGfx":
|
||||||
|
IsStreamedGfx = Xml.GetChildBoolAttribute(reader, "IsStreamedGfx", "value");
|
||||||
|
break;
|
||||||
|
case "AmbulanceShouldRespondTo":
|
||||||
|
AmbulanceShouldRespondTo = Xml.GetChildBoolAttribute(reader, "AmbulanceShouldRespondTo", "value");
|
||||||
|
break;
|
||||||
|
case "CanRideBikeWithNoHelmet":
|
||||||
|
CanRideBikeWithNoHelmet = Xml.GetChildBoolAttribute(reader, "CanRideBikeWithNoHelmet", "value");
|
||||||
|
break;
|
||||||
|
case "CanSpawnInCar":
|
||||||
|
CanSpawnInCar = Xml.GetChildBoolAttribute(reader, "CanSpawnInCar", "value");
|
||||||
|
break;
|
||||||
|
case "IsHeadBlendPed":
|
||||||
|
IsHeadBlendPed = Xml.GetChildBoolAttribute(reader, "IsHeadBlendPed", "value");
|
||||||
|
break;
|
||||||
|
case "bOnlyBulkyItemVariations":
|
||||||
|
bOnlyBulkyItemVariations = Xml.GetChildBoolAttribute(reader, "bOnlyBulkyItemVariations", "value");
|
||||||
|
break;
|
||||||
|
case "RelationshipGroup":
|
||||||
|
RelationshipGroup = Xml.GetChildInnerText(reader, "RelationshipGroup");
|
||||||
|
break;
|
||||||
|
case "NavCapabilitiesName":
|
||||||
|
NavCapabilitiesName = Xml.GetChildInnerText(reader, "NavCapabilitiesName");
|
||||||
|
break;
|
||||||
|
case "PerceptionInfo":
|
||||||
|
PerceptionInfo = Xml.GetChildInnerText(reader, "PerceptionInfo");
|
||||||
|
break;
|
||||||
|
case "DefaultBrawlingStyle":
|
||||||
|
DefaultBrawlingStyle = Xml.GetChildInnerText(reader, "DefaultBrawlingStyle");
|
||||||
|
break;
|
||||||
|
case "DefaultUnarmedWeapon":
|
||||||
|
DefaultUnarmedWeapon = Xml.GetChildInnerText(reader, "DefaultUnarmedWeapon");
|
||||||
|
break;
|
||||||
|
case "Personality":
|
||||||
|
Personality = Xml.GetChildInnerText(reader, "Personality");
|
||||||
|
break;
|
||||||
|
case "CombatInfo":
|
||||||
|
CombatInfo = Xml.GetChildInnerText(reader, "CombatInfo");
|
||||||
|
break;
|
||||||
|
case "VfxInfoName":
|
||||||
|
VfxInfoName = Xml.GetChildInnerText(reader, "VfxInfoName");
|
||||||
|
break;
|
||||||
|
case "AmbientClipsForFlee":
|
||||||
|
AmbientClipsForFlee = Xml.GetChildInnerText(reader, "AmbientClipsForFlee");
|
||||||
|
break;
|
||||||
|
case "Radio1":
|
||||||
|
Radio1 = Xml.GetChildInnerText(reader, "Radio1"); // MetaName.ePedRadioGenre
|
||||||
|
break;
|
||||||
|
case "Radio2":
|
||||||
|
Radio2 = Xml.GetChildInnerText(reader, "Radio2"); // MetaName.ePedRadioGenre
|
||||||
|
break;
|
||||||
|
case "FUpOffset":
|
||||||
|
FUpOffset = Xml.GetChildFloatAttribute(reader, "FUpOffset", "value");
|
||||||
|
break;
|
||||||
|
case "RUpOffset":
|
||||||
|
RUpOffset = Xml.GetChildFloatAttribute(reader, "RUpOffset", "value");
|
||||||
|
break;
|
||||||
|
case "FFrontOffset":
|
||||||
|
FFrontOffset = Xml.GetChildFloatAttribute(reader, "FFrontOffset", "value");
|
||||||
|
break;
|
||||||
|
case "RFrontOffset":
|
||||||
|
RFrontOffset = Xml.GetChildFloatAttribute(reader, "RFrontOffset", "value");
|
||||||
|
break;
|
||||||
|
case "MinActivationImpulse":
|
||||||
|
MinActivationImpulse = Xml.GetChildFloatAttribute(reader, "MinActivationImpulse", "value");
|
||||||
|
break;
|
||||||
|
case "Stubble":
|
||||||
|
Stubble = Xml.GetChildFloatAttribute(reader, "Stubble", "value");
|
||||||
|
break;
|
||||||
|
case "HDDist":
|
||||||
|
HDDist = Xml.GetChildFloatAttribute(reader, "HDDist", "value");
|
||||||
|
break;
|
||||||
|
case "TargetingThreatModifier":
|
||||||
|
TargetingThreatModifier = Xml.GetChildFloatAttribute(reader, "TargetingThreatModifier", "value");
|
||||||
|
break;
|
||||||
|
case "KilledPerceptionRangeModifer":
|
||||||
|
KilledPerceptionRangeModifer = Xml.GetChildFloatAttribute(reader, "KilledPerceptionRangeModifer", "value");
|
||||||
|
break;
|
||||||
|
case "Sexiness":
|
||||||
|
Sexiness = Xml.GetChildInnerText(reader, "Sexiness"); // MetaTypeName.ARRAYINFO MetaName.eSexinessFlags
|
||||||
|
break;
|
||||||
|
case "Age":
|
||||||
|
Age = (byte)Xml.GetChildUIntAttribute(reader, "Age", "value");
|
||||||
|
break;
|
||||||
|
case "MaxPassengersInCar":
|
||||||
|
MaxPassengersInCar = (byte)Xml.GetChildUIntAttribute(reader, "MaxPassengersInCar", "value");
|
||||||
|
break;
|
||||||
|
case "ExternallyDrivenDOFs":
|
||||||
|
ExternallyDrivenDOFs = Xml.GetChildInnerText(reader, "ExternallyDrivenDOFs"); // MetaTypeName.ARRAYINFO MetaName.eExternallyDrivenDOFs
|
||||||
|
break;
|
||||||
|
case "PedVoiceGroup":
|
||||||
|
PedVoiceGroup = Xml.GetChildInnerText(reader, "PedVoiceGroup");
|
||||||
|
break;
|
||||||
|
case "AnimalAudioObject":
|
||||||
|
AnimalAudioObject = Xml.GetChildInnerText(reader, "AnimalAudioObject");
|
||||||
|
break;
|
||||||
|
case "AbilityType":
|
||||||
|
AbilityType = Xml.GetChildInnerText(reader, "AbilityType"); // MetaName.SpecialAbilityType
|
||||||
|
break;
|
||||||
|
case "ThermalBehaviour":
|
||||||
|
ThermalBehaviour = Xml.GetChildInnerText(reader, "ThermalBehaviour"); // MetaName.ThermalBehaviour
|
||||||
|
break;
|
||||||
|
case "SuperlodType":
|
||||||
|
SuperlodType = Xml.GetChildInnerText(reader, "SuperlodType"); // MetaName.eSuperlodType
|
||||||
|
break;
|
||||||
|
case "ScenarioPopStreamingSlot":
|
||||||
|
ScenarioPopStreamingSlot = Xml.GetChildInnerText(reader, "ScenarioPopStreamingSlot"); // MetaName.eScenarioPopStreamingSlot
|
||||||
|
break;
|
||||||
|
case "DefaultSpawningPreference":
|
||||||
|
DefaultSpawningPreference = Xml.GetChildInnerText(reader, "DefaultSpawningPreference"); // MetaName.DefaultSpawnPreference
|
||||||
|
break;
|
||||||
|
case "DefaultRemoveRangeMultiplier":
|
||||||
|
DefaultRemoveRangeMultiplier = Xml.GetChildFloatAttribute(reader, "DefaultRemoveRangeMultiplier", "value");
|
||||||
|
break;
|
||||||
|
case "AllowCloseSpawning":
|
||||||
|
AllowCloseSpawning = Xml.GetChildBoolAttribute(reader, "AllowCloseSpawning", "value");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public CPedModelInfo__InitData(XmlNode node)
|
public CPedModelInfo__InitData(XmlNode node)
|
||||||
{
|
{
|
||||||
@ -300,6 +626,25 @@ namespace CodeWalker.GameFiles
|
|||||||
public string parent { get; set; }
|
public string parent { get; set; }
|
||||||
public string child { get; set; }
|
public string child { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
public CTxdRelationship(XmlReader reader)
|
||||||
|
{
|
||||||
|
if (reader.Name == "parent")
|
||||||
|
{
|
||||||
|
parent = Xml.GetChildInnerText(reader, "parent");
|
||||||
|
} else if (reader.Name == "child")
|
||||||
|
{
|
||||||
|
child = Xml.GetChildInnerText(reader, "child");
|
||||||
|
}
|
||||||
|
if (reader.Name == "parent")
|
||||||
|
{
|
||||||
|
parent = Xml.GetChildInnerText(reader, "parent");
|
||||||
|
}
|
||||||
|
else if (reader.Name == "child")
|
||||||
|
{
|
||||||
|
child = Xml.GetChildInnerText(reader, "child");
|
||||||
|
}
|
||||||
|
}
|
||||||
public CTxdRelationship(XmlNode node)
|
public CTxdRelationship(XmlNode node)
|
||||||
{
|
{
|
||||||
parent = Xml.GetChildInnerText(node, "parent");
|
parent = Xml.GetChildInnerText(node, "parent");
|
||||||
@ -331,6 +676,34 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CMultiTxdRelationship(XmlReader reader)
|
||||||
|
{
|
||||||
|
reader.ReadStartElement("Item");
|
||||||
|
while (reader.MoveToContent() == XmlNodeType.Element && reader.Name != "Item")
|
||||||
|
{
|
||||||
|
switch (reader.Name)
|
||||||
|
{
|
||||||
|
case "children":
|
||||||
|
var childrenList = new List<string>();
|
||||||
|
foreach (var item in Xml.IterateItems(reader, "children"))
|
||||||
|
{
|
||||||
|
childrenList.Add(item.Value);
|
||||||
|
}
|
||||||
|
if (childrenList.Count > 0)
|
||||||
|
{
|
||||||
|
children = childrenList.ToArray();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "parent":
|
||||||
|
parent = Xml.GetChildInnerText(reader, "parent");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidOperationException($"Found invalid XML Element \"{reader.Name}\" of type \"{reader.NodeType}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader.ReadEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return parent + ": " + (children?.Length ?? 0).ToString() + " children";
|
return parent + ": " + (children?.Length ?? 0).ToString() + " children";
|
||||||
|
@ -105,7 +105,26 @@ namespace CodeWalker.GameFiles
|
|||||||
RpfFileEntry = entry;
|
RpfFileEntry = entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Load(byte[] data, RpfFileEntry entry)
|
public unsafe string ReadString(BinaryReader br, int length, bool ignoreNullTerminator = false)
|
||||||
|
{
|
||||||
|
var bytes = stackalloc char[length];
|
||||||
|
var currentLength = 0;
|
||||||
|
while (currentLength < length)
|
||||||
|
{
|
||||||
|
var c = (char)br.ReadByte();
|
||||||
|
if (c != 0)
|
||||||
|
{
|
||||||
|
bytes[currentLength] = c;
|
||||||
|
currentLength++;
|
||||||
|
}
|
||||||
|
else if (!ignoreNullTerminator)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string(bytes, 0, currentLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe void Load(byte[] data, RpfFileEntry entry)
|
||||||
{
|
{
|
||||||
RawFileData = data;
|
RawFileData = data;
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
@ -114,8 +133,8 @@ namespace CodeWalker.GameFiles
|
|||||||
Name = entry.Name;
|
Name = entry.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryStream ms = new MemoryStream(data);
|
using MemoryStream ms = new MemoryStream(data);
|
||||||
BinaryReader br = new BinaryReader(ms);
|
using BinaryReader br = new BinaryReader(ms);
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
RelType = (RelDatFileType)br.ReadUInt32(); //type
|
RelType = (RelDatFileType)br.ReadUInt32(); //type
|
||||||
@ -134,19 +153,25 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
NameTableOffsets = ntoffsets;
|
NameTableOffsets = ntoffsets;
|
||||||
string[] names = new string[NameTableCount];
|
string[] names = new string[NameTableCount];
|
||||||
|
var remainingLength = (int)NameTableLength;
|
||||||
for (uint i = 0; i < NameTableCount; i++)
|
for (uint i = 0; i < NameTableCount; i++)
|
||||||
{
|
{
|
||||||
sb.Clear();
|
int length = 0;
|
||||||
while (true)
|
if (i < NameTableCount - 1)
|
||||||
{
|
{
|
||||||
char c = (char)br.ReadByte();
|
length = (int)(NameTableOffsets[i + 1] - NameTableOffsets[i]);
|
||||||
if (c != 0) sb.Append(c);
|
|
||||||
else break;
|
|
||||||
}
|
}
|
||||||
names[i] = sb.ToString();
|
else
|
||||||
|
{
|
||||||
|
length = remainingLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
names[i] = ReadString(br, length);
|
||||||
|
|
||||||
//JenkIndex.Ensure(names[i]); //really need both here..?
|
//JenkIndex.Ensure(names[i]); //really need both here..?
|
||||||
JenkIndex.Ensure(names[i].ToLowerInvariant());
|
JenkIndex.EnsureLower(names[i]);
|
||||||
|
remainingLength -= length;
|
||||||
}
|
}
|
||||||
NameTable = names;
|
NameTable = names;
|
||||||
}
|
}
|
||||||
@ -164,18 +189,13 @@ namespace CodeWalker.GameFiles
|
|||||||
for (uint i = 0; i < IndexCount; i++)
|
for (uint i = 0; i < IndexCount; i++)
|
||||||
{
|
{
|
||||||
byte sl = br.ReadByte();
|
byte sl = br.ReadByte();
|
||||||
sb.Clear();
|
var str = ReadString(br, (int)sl, true);
|
||||||
for (int j = 0; j < sl; j++)
|
|
||||||
{
|
|
||||||
char c = (char)br.ReadByte();
|
|
||||||
if (c != 0) sb.Append(c);
|
|
||||||
}
|
|
||||||
RelIndexString ristr = new RelIndexString();
|
RelIndexString ristr = new RelIndexString();
|
||||||
ristr.Name = sb.ToString();
|
ristr.Name = str;
|
||||||
ristr.Offset = br.ReadUInt32();
|
ristr.Offset = br.ReadUInt32();
|
||||||
ristr.Length = br.ReadUInt32();
|
ristr.Length = br.ReadUInt32();
|
||||||
indexstrs[i] = ristr;
|
indexstrs[i] = ristr;
|
||||||
JenkIndex.Ensure(ristr.Name.ToLowerInvariant());
|
JenkIndex.EnsureLower(ristr.Name);
|
||||||
}
|
}
|
||||||
IndexStrings = indexstrs;
|
IndexStrings = indexstrs;
|
||||||
}
|
}
|
||||||
@ -235,9 +255,6 @@ namespace CodeWalker.GameFiles
|
|||||||
{ }
|
{ }
|
||||||
//EOF!
|
//EOF!
|
||||||
|
|
||||||
br.Dispose();
|
|
||||||
ms.Dispose();
|
|
||||||
|
|
||||||
|
|
||||||
ParseDataBlock();
|
ParseDataBlock();
|
||||||
|
|
||||||
@ -253,8 +270,8 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
MemoryStream ms = new MemoryStream(DataBlock);
|
using MemoryStream ms = new MemoryStream(DataBlock);
|
||||||
BinaryReader br = new BinaryReader(ms);
|
using BinaryReader br = new BinaryReader(ms);
|
||||||
|
|
||||||
DataUnkVal = br.ReadUInt32(); //3 bytes used... for? ..version? flags?
|
DataUnkVal = br.ReadUInt32(); //3 bytes used... for? ..version? flags?
|
||||||
#region DataUnkVal unk values test
|
#region DataUnkVal unk values test
|
||||||
@ -315,12 +332,6 @@ namespace CodeWalker.GameFiles
|
|||||||
RelDatasSorted = reldatas.ToArray();
|
RelDatasSorted = reldatas.ToArray();
|
||||||
|
|
||||||
|
|
||||||
br.Dispose();
|
|
||||||
ms.Dispose();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RelDataDict.Clear();
|
RelDataDict.Clear();
|
||||||
foreach (var reldata in RelDatas)
|
foreach (var reldata in RelDatas)
|
||||||
{
|
{
|
||||||
@ -328,7 +339,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
reldata.NameHash = JenkHash.GenHash(reldata.Name); //should this be lower case?
|
reldata.NameHash = JenkHash.GenHash(reldata.Name); //should this be lower case?
|
||||||
JenkIndex.Ensure(reldata.Name);
|
JenkIndex.Ensure(reldata.Name);
|
||||||
JenkIndex.Ensure(reldata.Name.ToLowerInvariant()); //which one to use?
|
JenkIndex.EnsureLower(reldata.Name); //which one to use?
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (reldata.NameHash == 0)
|
//if (reldata.NameHash == 0)
|
||||||
@ -349,24 +360,10 @@ namespace CodeWalker.GameFiles
|
|||||||
for (int i = 0; i < snd.ChildSoundsCount; i++)
|
for (int i = 0; i < snd.ChildSoundsCount; i++)
|
||||||
{
|
{
|
||||||
var audhash = snd.ChildSoundsHashes[i];
|
var audhash = snd.ChildSoundsHashes[i];
|
||||||
RelData auddata = null;
|
if (RelDataDict.TryGetValue(audhash, out var auddata))
|
||||||
if (RelDataDict.TryGetValue(audhash, out auddata))
|
|
||||||
{
|
{
|
||||||
snd.ChildSounds[i] = auddata;
|
snd.ChildSounds[i] = auddata;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (snd.AudioContainers != null)
|
|
||||||
{
|
|
||||||
foreach (var cnt in snd.AudioContainers)
|
|
||||||
{
|
|
||||||
string cname = JenkIndex.TryGetString(cnt.Hash);
|
|
||||||
if (!string.IsNullOrEmpty(cname))
|
|
||||||
{ }
|
|
||||||
else
|
|
||||||
{ }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,8 +382,6 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
speechDict[speechData.DataOffset] = speechData;
|
speechDict[speechData.DataOffset] = speechData;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ }
|
|
||||||
|
|
||||||
speechData.Type = Dat4SpeechType.ByteArray;
|
speechData.Type = Dat4SpeechType.ByteArray;
|
||||||
speechData.TypeID = 0; //will be set again after this
|
speechData.TypeID = 0; //will be set again after this
|
||||||
@ -397,32 +392,24 @@ namespace CodeWalker.GameFiles
|
|||||||
var hashOffset = HashTableOffsets[i];
|
var hashOffset = HashTableOffsets[i];
|
||||||
var hash = HashTable[i];
|
var hash = HashTable[i];
|
||||||
var itemOffset = hashOffset - 8;
|
var itemOffset = hashOffset - 8;
|
||||||
Dat4SpeechData speechData = null;
|
if (speechDict.TryGetValue(itemOffset, out var speechData) && speechData != null)
|
||||||
speechDict.TryGetValue(itemOffset, out speechData);
|
|
||||||
if (speechData != null)
|
|
||||||
{
|
{
|
||||||
speechData.Type = Dat4SpeechType.Hash;
|
speechData.Type = Dat4SpeechType.Hash;
|
||||||
speechData.TypeID = 4;
|
speechData.TypeID = 4;
|
||||||
speechData.Hash = hash;
|
speechData.Hash = hash;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ }
|
|
||||||
}
|
}
|
||||||
for (uint i = 0; i < PackTableCount; i++)
|
for (uint i = 0; i < PackTableCount; i++)
|
||||||
{
|
{
|
||||||
var packOffset = PackTableOffsets[i];
|
var packOffset = PackTableOffsets[i];
|
||||||
var pack = PackTable[i];
|
var pack = PackTable[i];
|
||||||
var itemOffset = packOffset - 12;
|
var itemOffset = packOffset - 12;
|
||||||
Dat4SpeechData speechData = null;
|
if (speechDict.TryGetValue(itemOffset, out var speechData) && speechData != null)
|
||||||
speechDict.TryGetValue(itemOffset, out speechData);
|
|
||||||
if (speechData != null)
|
|
||||||
{
|
{
|
||||||
speechData.Type = Dat4SpeechType.Container;
|
speechData.Type = Dat4SpeechType.Container;
|
||||||
speechData.TypeID = 8;
|
speechData.TypeID = 8;
|
||||||
speechData.ContainerHash = pack;
|
speechData.ContainerHash = pack;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ }//shouldn't happen!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -456,8 +443,7 @@ namespace CodeWalker.GameFiles
|
|||||||
d.Data = data;
|
d.Data = data;
|
||||||
|
|
||||||
|
|
||||||
using (BinaryReader dbr = new BinaryReader(new MemoryStream(data)))
|
using BinaryReader dbr = new BinaryReader(new MemoryStream(data));
|
||||||
{
|
|
||||||
d.ReadType(dbr);
|
d.ReadType(dbr);
|
||||||
|
|
||||||
switch (RelType)
|
switch (RelType)
|
||||||
@ -484,7 +470,6 @@ namespace CodeWalker.GameFiles
|
|||||||
return d; //shouldn't get here...
|
return d; //shouldn't get here...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -25334,7 +25319,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (str.StartsWith("hash_"))
|
if (str.StartsWith("hash_", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return Convert.ToUInt32(str.Substring(5), 16);
|
return Convert.ToUInt32(str.Substring(5), 16);
|
||||||
}
|
}
|
||||||
|
@ -26,16 +26,14 @@ namespace CodeWalker.GameFiles
|
|||||||
public static bool Ensure(string str)
|
public static bool Ensure(string str)
|
||||||
{
|
{
|
||||||
uint hash = JenkHash.GenHash(str);
|
uint hash = JenkHash.GenHash(str);
|
||||||
if (hash == 0) return true;
|
return Ensure(str, hash);
|
||||||
lock (syncRoot)
|
|
||||||
{
|
|
||||||
if (!Index.ContainsKey(hash))
|
|
||||||
{
|
|
||||||
Index.Add(hash, str);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return true;
|
public static bool EnsureLower(string str)
|
||||||
|
{
|
||||||
|
uint hash = JenkHash.GenHashLower(str);
|
||||||
|
|
||||||
|
return Ensure(str, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Ensure(string str, uint hash)
|
public static bool Ensure(string str, uint hash)
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
using SharpDX;
|
using CodeWalker.World;
|
||||||
|
using SharpDX;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
{
|
{
|
||||||
@ -28,14 +33,14 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void Load(byte[] data, RpfFileEntry entry)
|
public void LoadOld(byte[] data, RpfFileEntry entry)
|
||||||
{
|
{
|
||||||
RpfFileEntry = entry;
|
RpfFileEntry = entry;
|
||||||
Name = entry.Name;
|
Name = entry.Name;
|
||||||
FilePath = Name;
|
FilePath = Name;
|
||||||
|
|
||||||
|
|
||||||
if (entry.NameLower.EndsWith(".meta"))
|
if (entry.IsExtension(".meta"))
|
||||||
{
|
{
|
||||||
string xml = TextUtil.GetUTF8Text(data);
|
string xml = TextUtil.GetUTF8Text(data);
|
||||||
|
|
||||||
@ -53,12 +58,64 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Load(byte[] data, RpfFileEntry entry)
|
||||||
|
{
|
||||||
|
RpfFileEntry = entry;
|
||||||
|
Name = entry.Name;
|
||||||
|
FilePath = Name;
|
||||||
|
|
||||||
|
|
||||||
|
if (entry.IsExtension(".meta"))
|
||||||
|
{
|
||||||
|
using var textReader = new StreamReader(new MemoryStream(data), Encoding.UTF8);
|
||||||
|
|
||||||
|
using var xmlReader = XmlReader.Create(textReader);
|
||||||
|
|
||||||
|
while (xmlReader.Read())
|
||||||
|
{
|
||||||
|
xmlReader.MoveToContent();
|
||||||
|
|
||||||
|
//var _ = xmlReader.Name switch
|
||||||
|
//{
|
||||||
|
// "residentTxd" => ResidentTxd = Xml.GetChildInnerText(xmlReader, "residentTxd"),
|
||||||
|
// "InitDatas" => LoadInitDatas(xmlReader),
|
||||||
|
// "txdRelationships" => LoadTxdRelationships(xmlReader),
|
||||||
|
// _ => throw new Exception()
|
||||||
|
//};
|
||||||
|
|
||||||
|
switch (xmlReader.Name)
|
||||||
|
{
|
||||||
|
case string Name when Name.Equals("residentTxd", StringComparison.OrdinalIgnoreCase):
|
||||||
|
ResidentTxd = Xml.GetChildInnerText(xmlReader, "residentTxd");
|
||||||
|
break;
|
||||||
|
case string Name when Name.Equals("InitDatas", StringComparison.OrdinalIgnoreCase):
|
||||||
|
LoadInitDatas(xmlReader);
|
||||||
|
break;
|
||||||
|
case string Name when Name.Equals("txdRelationships", StringComparison.OrdinalIgnoreCase):
|
||||||
|
LoadTxdRelationships(xmlReader);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//ResidentTxd = Xml.GetChildInnerText(xmldoc.SelectSingleNode("CVehicleModelInfo__InitDataList"), "residentTxd");
|
||||||
|
|
||||||
|
//LoadInitDatas(xmldoc);
|
||||||
|
|
||||||
|
//LoadTxdRelationships(xmldoc);
|
||||||
|
|
||||||
|
Loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void LoadInitDatas(XmlDocument xmldoc)
|
private void LoadInitDatas(XmlDocument xmldoc)
|
||||||
{
|
{
|
||||||
XmlNodeList items = xmldoc.SelectNodes("CVehicleModelInfo__InitDataList/InitDatas/Item | CVehicleModelInfo__InitDataList/InitDatas/item");
|
XmlNodeList items = xmldoc.SelectNodes("CVehicleModelInfo__InitDataList/InitDatas/Item | CVehicleModelInfo__InitDataList/InitDatas/item");
|
||||||
|
|
||||||
InitDatas = new List<VehicleInitData>();
|
InitDatas = new List<VehicleInitData>(items.Count);
|
||||||
for (int i = 0; i < items.Count; i++)
|
for (int i = 0; i < items.Count; i++)
|
||||||
{
|
{
|
||||||
var node = items[i];
|
var node = items[i];
|
||||||
@ -68,6 +125,53 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LoadInitDatas(XmlReader reader)
|
||||||
|
{
|
||||||
|
if (!reader.IsStartElement() || reader.Name != "InitDatas")
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("XmlReader is not at start element of \"InitDatas\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
InitDatas = new List<VehicleInitData>();
|
||||||
|
|
||||||
|
reader.ReadStartElement("InitDatas");
|
||||||
|
|
||||||
|
while (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "Item")
|
||||||
|
{
|
||||||
|
if (reader.IsStartElement())
|
||||||
|
{
|
||||||
|
VehicleInitData d = new VehicleInitData();
|
||||||
|
d.Load(reader);
|
||||||
|
InitDatas.Add(d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadTxdRelationships(XmlReader reader)
|
||||||
|
{
|
||||||
|
if (reader.IsEmptyElement)
|
||||||
|
{
|
||||||
|
TxdRelationships = new Dictionary<string, string>();
|
||||||
|
reader.ReadStartElement();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TxdRelationships = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
foreach(var item in Xml.IterateItems(reader, "txdRelationships"))
|
||||||
|
{
|
||||||
|
var childstr = item.Element("child")?.Value;
|
||||||
|
var parentstr = item.Element("parent")?.Value;
|
||||||
|
|
||||||
|
if ((!string.IsNullOrEmpty(parentstr)) && (!string.IsNullOrEmpty(childstr)))
|
||||||
|
{
|
||||||
|
if (!TxdRelationships.ContainsKey(childstr))
|
||||||
|
{
|
||||||
|
TxdRelationships.Add(childstr, parentstr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void LoadTxdRelationships(XmlDocument xmldoc)
|
private void LoadTxdRelationships(XmlDocument xmldoc)
|
||||||
{
|
{
|
||||||
XmlNodeList items = xmldoc.SelectNodes("CVehicleModelInfo__InitDataList/txdRelationships/Item | CVehicleModelInfo__InitDataList/txdRelationships/item");
|
XmlNodeList items = xmldoc.SelectNodes("CVehicleModelInfo__InitDataList/txdRelationships/Item | CVehicleModelInfo__InitDataList/txdRelationships/item");
|
||||||
@ -89,8 +193,6 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -106,7 +208,7 @@ namespace CodeWalker.GameFiles
|
|||||||
public string expressionName { get; set; } //<expressionName>null</expressionName>
|
public string expressionName { get; set; } //<expressionName>null</expressionName>
|
||||||
public string animConvRoofDictName { get; set; } //<animConvRoofDictName>null</animConvRoofDictName>
|
public string animConvRoofDictName { get; set; } //<animConvRoofDictName>null</animConvRoofDictName>
|
||||||
public string animConvRoofName { get; set; } //<animConvRoofName>null</animConvRoofName>
|
public string animConvRoofName { get; set; } //<animConvRoofName>null</animConvRoofName>
|
||||||
public string animConvRoofWindowsAffected { get; set; } //<animConvRoofWindowsAffected />
|
public string[] animConvRoofWindowsAffected { get; set; } //<animConvRoofWindowsAffected />
|
||||||
public string ptfxAssetName { get; set; } //<ptfxAssetName>weap_xs_vehicle_weapons</ptfxAssetName>
|
public string ptfxAssetName { get; set; } //<ptfxAssetName>weap_xs_vehicle_weapons</ptfxAssetName>
|
||||||
public string audioNameHash { get; set; } //<audioNameHash />
|
public string audioNameHash { get; set; } //<audioNameHash />
|
||||||
public string layout { get; set; } //<layout>LAYOUT_STD_ARENA_1HONLY</layout>
|
public string layout { get; set; } //<layout>LAYOUT_STD_ARENA_1HONLY</layout>
|
||||||
@ -185,6 +287,354 @@ namespace CodeWalker.GameFiles
|
|||||||
public VehicleOverrideRagdollThreshold pOverrideRagdollThreshold { get; set; } //<pOverrideRagdollThreshold type="NULL" />
|
public VehicleOverrideRagdollThreshold pOverrideRagdollThreshold { get; set; } //<pOverrideRagdollThreshold type="NULL" />
|
||||||
public string[] firstPersonDrivebyData { get; set; } //<firstPersonDrivebyData>// <Item>STD_IMPALER2_FRONT_LEFT</Item>// <Item>STD_IMPALER2_FRONT_RIGHT</Item>//</firstPersonDrivebyData>
|
public string[] firstPersonDrivebyData { get; set; } //<firstPersonDrivebyData>// <Item>STD_IMPALER2_FRONT_LEFT</Item>// <Item>STD_IMPALER2_FRONT_RIGHT</Item>//</firstPersonDrivebyData>
|
||||||
|
|
||||||
|
public void Load(XmlReader reader)
|
||||||
|
{
|
||||||
|
reader.ReadStartElement("Item");
|
||||||
|
while (reader.Name != "Item" && reader.Read())
|
||||||
|
{
|
||||||
|
if (reader.NodeType == XmlNodeType.EndElement && reader.Name == "Item")
|
||||||
|
{
|
||||||
|
reader.ReadEndElement();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (reader.IsStartElement())
|
||||||
|
{
|
||||||
|
while (reader.IsStartElement())
|
||||||
|
{
|
||||||
|
switch (reader.Name)
|
||||||
|
{
|
||||||
|
case "modelName":
|
||||||
|
modelName = Xml.GetChildInnerText(reader, "modelName");
|
||||||
|
break;
|
||||||
|
case "txdName":
|
||||||
|
txdName = Xml.GetChildInnerText(reader, "txdName");
|
||||||
|
break;
|
||||||
|
case "handlingId":
|
||||||
|
handlingId = Xml.GetChildInnerText(reader, "handlingId");
|
||||||
|
break;
|
||||||
|
case "gameName":
|
||||||
|
gameName = Xml.GetChildInnerText(reader, "gameName");
|
||||||
|
break;
|
||||||
|
case "vehicleMakeName":
|
||||||
|
vehicleMakeName = Xml.GetChildInnerText(reader, "vehicleMakeName");
|
||||||
|
break;
|
||||||
|
case "expressionDictName":
|
||||||
|
expressionDictName = Xml.GetChildInnerText(reader, "expressionDictName");
|
||||||
|
break;
|
||||||
|
case "expressionName":
|
||||||
|
expressionName = Xml.GetChildInnerText(reader, "expressionName");
|
||||||
|
break;
|
||||||
|
case "animConvRoofDictName":
|
||||||
|
animConvRoofDictName = Xml.GetChildInnerText(reader, "animConvRoofDictName");
|
||||||
|
break;
|
||||||
|
case "animConvRoofName":
|
||||||
|
animConvRoofName = Xml.GetChildInnerText(reader, "animConvRoofName");
|
||||||
|
break;
|
||||||
|
case "animConvRoofWindowsAffected":
|
||||||
|
animConvRoofWindowsAffected = GetStringItemArray(reader, "animConvRoofWindowsAffected");
|
||||||
|
break;
|
||||||
|
case "ptfxAssetName":
|
||||||
|
ptfxAssetName = Xml.GetChildInnerText(reader, "ptfxAssetName");
|
||||||
|
break;
|
||||||
|
case "audioNameHash":
|
||||||
|
audioNameHash = Xml.GetChildInnerText(reader, "audioNameHash");
|
||||||
|
break;
|
||||||
|
case "layout":
|
||||||
|
layout = Xml.GetChildInnerText(reader, "layout");
|
||||||
|
break;
|
||||||
|
case "coverBoundOffsets":
|
||||||
|
coverBoundOffsets = Xml.GetChildInnerText(reader, "coverBoundOffsets");
|
||||||
|
break;
|
||||||
|
case "explosionInfo":
|
||||||
|
explosionInfo = Xml.GetChildInnerText(reader, "explosionInfo");
|
||||||
|
break;
|
||||||
|
case "scenarioLayout":
|
||||||
|
scenarioLayout = Xml.GetChildInnerText(reader, "scenarioLayout");
|
||||||
|
break;
|
||||||
|
case "cameraName":
|
||||||
|
cameraName = Xml.GetChildInnerText(reader, "cameraName");
|
||||||
|
break;
|
||||||
|
case "aimCameraName":
|
||||||
|
aimCameraName = Xml.GetChildInnerText(reader, "aimCameraName");
|
||||||
|
break;
|
||||||
|
case "bonnetCameraName":
|
||||||
|
bonnetCameraName = Xml.GetChildInnerText(reader, "bonnetCameraName");
|
||||||
|
break;
|
||||||
|
case "povCameraName":
|
||||||
|
povCameraName = Xml.GetChildInnerText(reader, "povCameraName");
|
||||||
|
break;
|
||||||
|
case "FirstPersonDriveByIKOffset":
|
||||||
|
FirstPersonDriveByIKOffset = Xml.GetChildVector3Attributes(reader, "FirstPersonDriveByIKOffset");
|
||||||
|
break;
|
||||||
|
case "FirstPersonDriveByUnarmedIKOffset":
|
||||||
|
FirstPersonDriveByUnarmedIKOffset = Xml.GetChildVector3Attributes(reader, "FirstPersonDriveByUnarmedIKOffset");
|
||||||
|
break;
|
||||||
|
case "FirstPersonProjectileDriveByIKOffset":
|
||||||
|
FirstPersonProjectileDriveByIKOffset = Xml.GetChildVector3Attributes(reader, "FirstPersonProjectileDriveByIKOffset");
|
||||||
|
break;
|
||||||
|
case "FirstPersonProjectileDriveByPassengerIKOffset":
|
||||||
|
FirstPersonProjectileDriveByPassengerIKOffset = Xml.GetChildVector3Attributes(reader, "FirstPersonProjectileDriveByPassengerIKOffset");
|
||||||
|
break;
|
||||||
|
case "FirstPersonDriveByRightPassengerIKOffset":
|
||||||
|
FirstPersonDriveByRightPassengerIKOffset = Xml.GetChildVector3Attributes(reader, "FirstPersonDriveByRightPassengerIKOffset");
|
||||||
|
break;
|
||||||
|
case "FirstPersonDriveByRightPassengerUnarmedIKOffset":
|
||||||
|
FirstPersonDriveByRightPassengerUnarmedIKOffset = Xml.GetChildVector3Attributes(reader, "FirstPersonDriveByRightPassengerUnarmedIKOffset");
|
||||||
|
break;
|
||||||
|
case "FirstPersonMobilePhoneOffset":
|
||||||
|
FirstPersonMobilePhoneOffset = Xml.GetChildVector3Attributes(reader, "FirstPersonMobilePhoneOffset");
|
||||||
|
break;
|
||||||
|
case "FirstPersonPassengerMobilePhoneOffset":
|
||||||
|
FirstPersonPassengerMobilePhoneOffset = Xml.GetChildVector3Attributes(reader, "FirstPersonPassengerMobilePhoneOffset");
|
||||||
|
break;
|
||||||
|
case "PovCameraOffset":
|
||||||
|
PovCameraOffset = Xml.GetChildVector3Attributes(reader, "PovCameraOffset");
|
||||||
|
break;
|
||||||
|
case "PovCameraVerticalAdjustmentForRollCage":
|
||||||
|
PovCameraVerticalAdjustmentForRollCage = Xml.GetChildVector3Attributes(reader, "PovCameraVerticalAdjustmentForRollCage");
|
||||||
|
break;
|
||||||
|
case "PovPassengerCameraOffset":
|
||||||
|
PovPassengerCameraOffset = Xml.GetChildVector3Attributes(reader, "PovPassengerCameraOffset");
|
||||||
|
break;
|
||||||
|
case "PovRearPassengerCameraOffset":
|
||||||
|
PovRearPassengerCameraOffset = Xml.GetChildVector3Attributes(reader, "PovRearPassengerCameraOffset");
|
||||||
|
break;
|
||||||
|
case "vfxInfoName":
|
||||||
|
vfxInfoName = Xml.GetChildInnerText(reader, "vfxInfoName");
|
||||||
|
break;
|
||||||
|
case "shouldUseCinematicViewMode":
|
||||||
|
shouldUseCinematicViewMode = Xml.GetChildBoolAttribute(reader, "shouldUseCinematicViewMode");
|
||||||
|
break;
|
||||||
|
case "shouldCameraTransitionOnClimbUpDown":
|
||||||
|
shouldCameraTransitionOnClimbUpDown = Xml.GetChildBoolAttribute(reader, "shouldCameraTransitionOnClimbUpDown");
|
||||||
|
break;
|
||||||
|
case "shouldCameraIgnoreExiting":
|
||||||
|
shouldCameraIgnoreExiting = Xml.GetChildBoolAttribute(reader, "shouldCameraIgnoreExiting");
|
||||||
|
break;
|
||||||
|
case "AllowPretendOccupants":
|
||||||
|
AllowPretendOccupants = Xml.GetChildBoolAttribute(reader, "AllowPretendOccupants");
|
||||||
|
break;
|
||||||
|
case "AllowJoyriding":
|
||||||
|
AllowJoyriding = Xml.GetChildBoolAttribute(reader, "AllowJoyriding");
|
||||||
|
break;
|
||||||
|
case "AllowSundayDriving":
|
||||||
|
AllowSundayDriving = Xml.GetChildBoolAttribute(reader, "AllowSundayDriving");
|
||||||
|
break;
|
||||||
|
case "AllowBodyColorMapping":
|
||||||
|
AllowBodyColorMapping = Xml.GetChildBoolAttribute(reader, "AllowBodyColorMapping");
|
||||||
|
break;
|
||||||
|
case "wheelScale":
|
||||||
|
wheelScale = Xml.GetChildFloatAttribute(reader, "wheelScale");
|
||||||
|
break;
|
||||||
|
case "wheelScaleRear":
|
||||||
|
wheelScaleRear = Xml.GetChildFloatAttribute(reader, "wheelScaleRear");
|
||||||
|
break;
|
||||||
|
case "dirtLevelMin":
|
||||||
|
dirtLevelMin = Xml.GetChildFloatAttribute(reader, "dirtLevelMin");
|
||||||
|
break;
|
||||||
|
case "dirtLevelMax":
|
||||||
|
dirtLevelMax = Xml.GetChildFloatAttribute(reader, "dirtLevelMax");
|
||||||
|
break;
|
||||||
|
case "envEffScaleMin":
|
||||||
|
envEffScaleMin = Xml.GetChildFloatAttribute(reader, "envEffScaleMin");
|
||||||
|
break;
|
||||||
|
case "envEffScaleMax":
|
||||||
|
envEffScaleMax = Xml.GetChildFloatAttribute(reader, "envEffScaleMax");
|
||||||
|
break;
|
||||||
|
case "envEffScaleMin2":
|
||||||
|
envEffScaleMin2 = Xml.GetChildFloatAttribute(reader, "envEffScaleMin2");
|
||||||
|
break;
|
||||||
|
case "envEffScaleMax2":
|
||||||
|
envEffScaleMax2 = Xml.GetChildFloatAttribute(reader, "envEffScaleMax2");
|
||||||
|
break;
|
||||||
|
case "damageMapScale":
|
||||||
|
damageMapScale = Xml.GetChildFloatAttribute(reader, "damageMapScale");
|
||||||
|
break;
|
||||||
|
case "damageOffsetScale":
|
||||||
|
damageOffsetScale = Xml.GetChildFloatAttribute(reader, "damageOffsetScale");
|
||||||
|
break;
|
||||||
|
case "diffuseTint":
|
||||||
|
diffuseTint = new Color4(Convert.ToUInt32(Xml.GetChildStringAttribute(reader, "diffuseTint", "value").Replace("0x", ""), 16)); ;
|
||||||
|
break;
|
||||||
|
case "steerWheelMult":
|
||||||
|
steerWheelMult = Xml.GetChildFloatAttribute(reader, "steerWheelMult");
|
||||||
|
break;
|
||||||
|
case "HDTextureDist":
|
||||||
|
HDTextureDist = Xml.GetChildFloatAttribute(reader, "HDTextureDist");
|
||||||
|
break;
|
||||||
|
case "lodDistances":
|
||||||
|
lodDistances = GetFloatArray(reader, "lodDistances", '\n');
|
||||||
|
break;
|
||||||
|
case "minSeatHeight":
|
||||||
|
minSeatHeight = Xml.GetChildFloatAttribute(reader, "minSeatHeight");
|
||||||
|
break;
|
||||||
|
case "identicalModelSpawnDistance":
|
||||||
|
identicalModelSpawnDistance = Xml.GetChildFloatAttribute(reader, "identicalModelSpawnDistance");
|
||||||
|
break;
|
||||||
|
case "maxNumOfSameColor":
|
||||||
|
maxNumOfSameColor = Xml.GetChildIntAttribute(reader, "maxNumOfSameColor");
|
||||||
|
break;
|
||||||
|
case "defaultBodyHealth":
|
||||||
|
defaultBodyHealth = Xml.GetChildFloatAttribute(reader, "defaultBodyHealth");
|
||||||
|
break;
|
||||||
|
case "pretendOccupantsScale":
|
||||||
|
pretendOccupantsScale = Xml.GetChildFloatAttribute(reader, "pretendOccupantsScale");
|
||||||
|
break;
|
||||||
|
case "visibleSpawnDistScale":
|
||||||
|
visibleSpawnDistScale = Xml.GetChildFloatAttribute(reader, "visibleSpawnDistScale");
|
||||||
|
break;
|
||||||
|
case "trackerPathWidth":
|
||||||
|
trackerPathWidth = Xml.GetChildFloatAttribute(reader, "trackerPathWidth");
|
||||||
|
break;
|
||||||
|
case "weaponForceMult":
|
||||||
|
weaponForceMult = Xml.GetChildFloatAttribute(reader, "weaponForceMult");
|
||||||
|
break;
|
||||||
|
case "frequency":
|
||||||
|
frequency = Xml.GetChildFloatAttribute(reader, "frequency");
|
||||||
|
break;
|
||||||
|
case "swankness":
|
||||||
|
swankness = Xml.GetChildInnerText(reader, "swankness");
|
||||||
|
break;
|
||||||
|
case "maxNum":
|
||||||
|
maxNum = Xml.GetChildIntAttribute(reader, "maxNum", "value");
|
||||||
|
break;
|
||||||
|
case "flags":
|
||||||
|
flags = GetStringArray(reader, "flags", ' ');
|
||||||
|
break;
|
||||||
|
case "type":
|
||||||
|
type = Xml.GetChildInnerText(reader, "type");
|
||||||
|
break;
|
||||||
|
case "plateType":
|
||||||
|
plateType = Xml.GetChildInnerText(reader, "plateType");
|
||||||
|
break;
|
||||||
|
case "dashboardType":
|
||||||
|
dashboardType = Xml.GetChildInnerText(reader, "dashboardType");
|
||||||
|
break;
|
||||||
|
case "vehicleClass":
|
||||||
|
vehicleClass = Xml.GetChildInnerText(reader, "vehicleClass");
|
||||||
|
break;
|
||||||
|
case "wheelType":
|
||||||
|
wheelType = Xml.GetChildInnerText(reader, "wheelType");
|
||||||
|
break;
|
||||||
|
case "trailers":
|
||||||
|
trailers = GetStringItemArray(reader, "trailers");
|
||||||
|
break;
|
||||||
|
case "additionalTrailers":
|
||||||
|
additionalTrailers = GetStringItemArray(reader, "additionalTrailers");
|
||||||
|
break;
|
||||||
|
case "drivers":
|
||||||
|
if (reader.IsEmptyElement)
|
||||||
|
{
|
||||||
|
reader.ReadStartElement();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _drivers = new List<VehicleDriver>();
|
||||||
|
|
||||||
|
foreach (var item in Xml.IterateItems(reader, "drivers"))
|
||||||
|
{
|
||||||
|
var driver = new VehicleDriver();
|
||||||
|
driver.driverName = item.Element("driverName")?.Value ?? string.Empty;
|
||||||
|
driver.npcName = item.Element("npcName")?.Value ?? string.Empty;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(driver.npcName) || !string.IsNullOrEmpty(driver.driverName))
|
||||||
|
{
|
||||||
|
_drivers.Add(driver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drivers = _drivers.ToArray();
|
||||||
|
break;
|
||||||
|
case "doorsWithCollisionWhenClosed":
|
||||||
|
doorsWithCollisionWhenClosed = GetStringItemArray(reader, "doorsWithCollisionWhenClosed");
|
||||||
|
break;
|
||||||
|
case "driveableDoors":
|
||||||
|
driveableDoors = GetStringItemArray(reader, "driveableDoors");
|
||||||
|
break;
|
||||||
|
case "bumpersNeedToCollideWithMap":
|
||||||
|
bumpersNeedToCollideWithMap = Xml.GetChildBoolAttribute(reader, "bumpersNeedToCollideWithMap", "value");
|
||||||
|
break;
|
||||||
|
case "needsRopeTexture":
|
||||||
|
needsRopeTexture = Xml.GetChildBoolAttribute(reader, "needsRopeTexture", "value");
|
||||||
|
break;
|
||||||
|
case "requiredExtras":
|
||||||
|
requiredExtras = GetStringArray(reader, "requiredExtras", ' ');
|
||||||
|
break;
|
||||||
|
case "rewards":
|
||||||
|
rewards = GetStringItemArray(reader, "rewards");
|
||||||
|
break;
|
||||||
|
case "cinematicPartCamera":
|
||||||
|
cinematicPartCamera = GetStringItemArray(reader, "cinematicPartCamera");
|
||||||
|
break;
|
||||||
|
case "NmBraceOverrideSet":
|
||||||
|
NmBraceOverrideSet = Xml.GetChildInnerText(reader, "NmBraceOverrideSet");
|
||||||
|
break;
|
||||||
|
case "buoyancySphereOffset":
|
||||||
|
buoyancySphereOffset = Xml.GetChildVector3Attributes(reader, "buoyancySphereOffset");
|
||||||
|
break;
|
||||||
|
case "buoyancySphereSizeScale":
|
||||||
|
buoyancySphereSizeScale = Xml.GetChildFloatAttribute(reader, "buoyancySphereSizeScale", "value");
|
||||||
|
break;
|
||||||
|
case "pOverrideRagdollThreshold":
|
||||||
|
if (reader.IsEmptyElement)
|
||||||
|
{
|
||||||
|
reader.ReadStartElement();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (reader.GetAttribute("type"))
|
||||||
|
{
|
||||||
|
case "NULL":
|
||||||
|
break;
|
||||||
|
case "CVehicleModelInfo__CVehicleOverrideRagdollThreshold":
|
||||||
|
reader.ReadStartElement();
|
||||||
|
pOverrideRagdollThreshold = new VehicleOverrideRagdollThreshold();
|
||||||
|
while (reader.MoveToContent() == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
if (reader.Name == "MinComponent")
|
||||||
|
{
|
||||||
|
pOverrideRagdollThreshold.MinComponent = Xml.GetChildIntAttribute(reader, "MinComponent", "value");
|
||||||
|
}
|
||||||
|
else if (reader.Name == "MaxComponent")
|
||||||
|
{
|
||||||
|
pOverrideRagdollThreshold.MaxComponent = Xml.GetChildIntAttribute(reader, "MaxComponent", "value");
|
||||||
|
}
|
||||||
|
else if (reader.Name == "ThresholdMult")
|
||||||
|
{
|
||||||
|
pOverrideRagdollThreshold.ThresholdMult = Xml.GetChildFloatAttribute(reader, "ThresholdMult", "value");
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.ReadEndElement();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "firstPersonDrivebyData":
|
||||||
|
firstPersonDrivebyData = GetStringItemArray(reader, "firstPersonDrivebyData");
|
||||||
|
break;
|
||||||
|
case "extraIncludes":
|
||||||
|
extraIncludes = GetStringItemArray(reader, "extraIncludes");
|
||||||
|
break;
|
||||||
|
case "FirstPersonDriveByLeftPassengerIKOffset":
|
||||||
|
case "FirstPersonDriveByLeftPassengerUnarmedIKOffset":
|
||||||
|
default:
|
||||||
|
reader.Skip();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
reader.Read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.ReadEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
public void Load(XmlNode node)
|
public void Load(XmlNode node)
|
||||||
{
|
{
|
||||||
@ -197,7 +647,7 @@ namespace CodeWalker.GameFiles
|
|||||||
expressionName = Xml.GetChildInnerText(node, "expressionName");
|
expressionName = Xml.GetChildInnerText(node, "expressionName");
|
||||||
animConvRoofDictName = Xml.GetChildInnerText(node, "animConvRoofDictName");
|
animConvRoofDictName = Xml.GetChildInnerText(node, "animConvRoofDictName");
|
||||||
animConvRoofName = Xml.GetChildInnerText(node, "animConvRoofName");
|
animConvRoofName = Xml.GetChildInnerText(node, "animConvRoofName");
|
||||||
animConvRoofWindowsAffected = Xml.GetChildInnerText(node, "animConvRoofWindowsAffected");//?
|
animConvRoofWindowsAffected = GetStringItemArray(node, "animConvRoofWindowsAffected");//?
|
||||||
ptfxAssetName = Xml.GetChildInnerText(node, "ptfxAssetName");
|
ptfxAssetName = Xml.GetChildInnerText(node, "ptfxAssetName");
|
||||||
audioNameHash = Xml.GetChildInnerText(node, "audioNameHash");
|
audioNameHash = Xml.GetChildInnerText(node, "audioNameHash");
|
||||||
layout = Xml.GetChildInnerText(node, "layout");
|
layout = Xml.GetChildInnerText(node, "layout");
|
||||||
@ -327,11 +777,41 @@ namespace CodeWalker.GameFiles
|
|||||||
if (getStringArrayList.Count == 0) return null;
|
if (getStringArrayList.Count == 0) return null;
|
||||||
return getStringArrayList.ToArray();
|
return getStringArrayList.ToArray();
|
||||||
}
|
}
|
||||||
private string[] GetStringArray(XmlNode node, string childName, char delimiter)
|
|
||||||
|
private string[] GetStringItemArray(XmlReader node, string childName)
|
||||||
|
{
|
||||||
|
if (node.IsEmptyElement)
|
||||||
|
{
|
||||||
|
node.ReadStartElement();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock(getStringArrayList)
|
||||||
|
{
|
||||||
|
getStringArrayList.Clear();
|
||||||
|
node.ReadStartElement();
|
||||||
|
while (node.MoveToContent() == XmlNodeType.Element && node.Name == "Item")
|
||||||
|
{
|
||||||
|
var istr = node.ReadElementContentAsString();
|
||||||
|
if (!string.IsNullOrEmpty(istr))
|
||||||
|
{
|
||||||
|
getStringArrayList.Add(istr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.ReadEndElement();
|
||||||
|
|
||||||
|
if (getStringArrayList.Count == 0)
|
||||||
|
return null;
|
||||||
|
return getStringArrayList.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string[] GetStringArray(string ldastr, char delimiter)
|
||||||
{
|
{
|
||||||
var ldastr = Xml.GetChildInnerText(node, childName);
|
|
||||||
var ldarr = ldastr?.Split(delimiter);
|
var ldarr = ldastr?.Split(delimiter);
|
||||||
if (ldarr == null) return null;
|
if (ldarr == null) return null;
|
||||||
|
lock(getStringArrayList)
|
||||||
|
{
|
||||||
getStringArrayList.Clear();
|
getStringArrayList.Clear();
|
||||||
foreach (var ldstr in ldarr)
|
foreach (var ldstr in ldarr)
|
||||||
{
|
{
|
||||||
@ -344,12 +824,26 @@ namespace CodeWalker.GameFiles
|
|||||||
if (getStringArrayList.Count == 0) return null;
|
if (getStringArrayList.Count == 0) return null;
|
||||||
return getStringArrayList.ToArray();
|
return getStringArrayList.ToArray();
|
||||||
}
|
}
|
||||||
private float[] GetFloatArray(XmlNode node, string childName, char delimiter)
|
}
|
||||||
|
|
||||||
|
private string[] GetStringArray(XmlNode node, string childName, char delimiter)
|
||||||
{
|
{
|
||||||
var ldastr = Xml.GetChildInnerText(node, childName);
|
var ldastr = Xml.GetChildInnerText(node, childName);
|
||||||
|
return GetStringArray(ldastr, delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string[] GetStringArray(XmlReader reader, string childName, char delimiter)
|
||||||
|
{
|
||||||
|
var ldastr = Xml.GetChildInnerText(reader, childName);
|
||||||
|
return GetStringArray(ldastr, delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe float[] GetFloatArray(string ldastr, char delimiter)
|
||||||
|
{
|
||||||
var ldarr = ldastr?.Split(delimiter);
|
var ldarr = ldastr?.Split(delimiter);
|
||||||
if (ldarr == null) return null;
|
if (ldarr == null) return null;
|
||||||
getFloatArrayList.Clear();
|
var floats = stackalloc float[ldarr.Length];
|
||||||
|
var i = 0;
|
||||||
foreach (var ldstr in ldarr)
|
foreach (var ldstr in ldarr)
|
||||||
{
|
{
|
||||||
var ldt = ldstr?.Trim();
|
var ldt = ldstr?.Trim();
|
||||||
@ -358,12 +852,30 @@ namespace CodeWalker.GameFiles
|
|||||||
float f;
|
float f;
|
||||||
if (FloatUtil.TryParse(ldt, out f))
|
if (FloatUtil.TryParse(ldt, out f))
|
||||||
{
|
{
|
||||||
getFloatArrayList.Add(f);
|
floats[i] = f;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (getFloatArrayList.Count == 0) return null;
|
if (i == 0) return null;
|
||||||
return getFloatArrayList.ToArray();
|
|
||||||
|
var result = new float[i];
|
||||||
|
|
||||||
|
Marshal.Copy((IntPtr)floats, result, 0, i);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float[] GetFloatArray(XmlNode node, string childName, char delimiter)
|
||||||
|
{
|
||||||
|
var ldastr = Xml.GetChildInnerText(node, childName);
|
||||||
|
return GetFloatArray(ldastr, delimiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private float[] GetFloatArray(XmlReader reader, string childName, char delimiter)
|
||||||
|
{
|
||||||
|
var ldastr = Xml.GetChildInnerText(reader, childName);
|
||||||
|
return GetFloatArray(ldastr, delimiter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<string> getStringArrayList = new List<string>(); //kinda hacky..
|
private static List<string> getStringArrayList = new List<string>(); //kinda hacky..
|
||||||
@ -374,28 +886,283 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return modelName;
|
return modelName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is VehicleInitData data &&
|
||||||
|
modelName == data.modelName &&
|
||||||
|
txdName == data.txdName &&
|
||||||
|
handlingId == data.handlingId &&
|
||||||
|
gameName == data.gameName &&
|
||||||
|
vehicleMakeName == data.vehicleMakeName &&
|
||||||
|
expressionDictName == data.expressionDictName &&
|
||||||
|
expressionName == data.expressionName &&
|
||||||
|
animConvRoofDictName == data.animConvRoofDictName &&
|
||||||
|
animConvRoofName == data.animConvRoofName &&
|
||||||
|
animConvRoofWindowsAffected == data.animConvRoofWindowsAffected &&
|
||||||
|
ptfxAssetName == data.ptfxAssetName &&
|
||||||
|
audioNameHash == data.audioNameHash &&
|
||||||
|
layout == data.layout &&
|
||||||
|
coverBoundOffsets == data.coverBoundOffsets &&
|
||||||
|
explosionInfo == data.explosionInfo &&
|
||||||
|
scenarioLayout == data.scenarioLayout &&
|
||||||
|
cameraName == data.cameraName &&
|
||||||
|
aimCameraName == data.aimCameraName &&
|
||||||
|
bonnetCameraName == data.bonnetCameraName &&
|
||||||
|
povCameraName == data.povCameraName &&
|
||||||
|
FirstPersonDriveByIKOffset.Equals(data.FirstPersonDriveByIKOffset) &&
|
||||||
|
FirstPersonDriveByUnarmedIKOffset.Equals(data.FirstPersonDriveByUnarmedIKOffset) &&
|
||||||
|
FirstPersonProjectileDriveByIKOffset.Equals(data.FirstPersonProjectileDriveByIKOffset) &&
|
||||||
|
FirstPersonProjectileDriveByPassengerIKOffset.Equals(data.FirstPersonProjectileDriveByPassengerIKOffset) &&
|
||||||
|
FirstPersonDriveByRightPassengerIKOffset.Equals(data.FirstPersonDriveByRightPassengerIKOffset) &&
|
||||||
|
FirstPersonDriveByRightPassengerUnarmedIKOffset.Equals(data.FirstPersonDriveByRightPassengerUnarmedIKOffset) &&
|
||||||
|
FirstPersonMobilePhoneOffset.Equals(data.FirstPersonMobilePhoneOffset) &&
|
||||||
|
FirstPersonPassengerMobilePhoneOffset.Equals(data.FirstPersonPassengerMobilePhoneOffset) &&
|
||||||
|
PovCameraOffset.Equals(data.PovCameraOffset) &&
|
||||||
|
PovCameraVerticalAdjustmentForRollCage.Equals(data.PovCameraVerticalAdjustmentForRollCage) &&
|
||||||
|
PovPassengerCameraOffset.Equals(data.PovPassengerCameraOffset) &&
|
||||||
|
PovRearPassengerCameraOffset.Equals(data.PovRearPassengerCameraOffset) &&
|
||||||
|
vfxInfoName == data.vfxInfoName &&
|
||||||
|
shouldUseCinematicViewMode == data.shouldUseCinematicViewMode &&
|
||||||
|
shouldCameraTransitionOnClimbUpDown == data.shouldCameraTransitionOnClimbUpDown &&
|
||||||
|
shouldCameraIgnoreExiting == data.shouldCameraIgnoreExiting &&
|
||||||
|
AllowPretendOccupants == data.AllowPretendOccupants &&
|
||||||
|
AllowJoyriding == data.AllowJoyriding &&
|
||||||
|
AllowSundayDriving == data.AllowSundayDriving &&
|
||||||
|
AllowBodyColorMapping == data.AllowBodyColorMapping &&
|
||||||
|
wheelScale == data.wheelScale &&
|
||||||
|
wheelScaleRear == data.wheelScaleRear &&
|
||||||
|
dirtLevelMin == data.dirtLevelMin &&
|
||||||
|
dirtLevelMax == data.dirtLevelMax &&
|
||||||
|
envEffScaleMin == data.envEffScaleMin &&
|
||||||
|
envEffScaleMax == data.envEffScaleMax &&
|
||||||
|
envEffScaleMin2 == data.envEffScaleMin2 &&
|
||||||
|
envEffScaleMax2 == data.envEffScaleMax2 &&
|
||||||
|
damageMapScale == data.damageMapScale &&
|
||||||
|
damageOffsetScale == data.damageOffsetScale &&
|
||||||
|
diffuseTint.Equals(data.diffuseTint) &&
|
||||||
|
steerWheelMult == data.steerWheelMult &&
|
||||||
|
HDTextureDist == data.HDTextureDist &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(lodDistances, data.lodDistances) &&
|
||||||
|
minSeatHeight == data.minSeatHeight &&
|
||||||
|
identicalModelSpawnDistance == data.identicalModelSpawnDistance &&
|
||||||
|
maxNumOfSameColor == data.maxNumOfSameColor &&
|
||||||
|
defaultBodyHealth == data.defaultBodyHealth &&
|
||||||
|
pretendOccupantsScale == data.pretendOccupantsScale &&
|
||||||
|
visibleSpawnDistScale == data.visibleSpawnDistScale &&
|
||||||
|
trackerPathWidth == data.trackerPathWidth &&
|
||||||
|
weaponForceMult == data.weaponForceMult &&
|
||||||
|
frequency == data.frequency &&
|
||||||
|
swankness == data.swankness &&
|
||||||
|
maxNum == data.maxNum &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(flags, data.flags) &&
|
||||||
|
type == data.type &&
|
||||||
|
plateType == data.plateType &&
|
||||||
|
dashboardType == data.dashboardType &&
|
||||||
|
vehicleClass == data.vehicleClass &&
|
||||||
|
wheelType == data.wheelType &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(trailers, data.trailers) &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(additionalTrailers, data.additionalTrailers) &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(drivers, data.drivers) &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(extraIncludes, data.extraIncludes) &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(doorsWithCollisionWhenClosed, data.doorsWithCollisionWhenClosed) &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(driveableDoors, data.driveableDoors) &&
|
||||||
|
bumpersNeedToCollideWithMap == data.bumpersNeedToCollideWithMap &&
|
||||||
|
needsRopeTexture == data.needsRopeTexture &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(requiredExtras, data.requiredExtras) &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(rewards, data.rewards) &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(cinematicPartCamera, data.cinematicPartCamera) &&
|
||||||
|
NmBraceOverrideSet == data.NmBraceOverrideSet &&
|
||||||
|
buoyancySphereOffset.Equals(data.buoyancySphereOffset) &&
|
||||||
|
buoyancySphereSizeScale == data.buoyancySphereSizeScale &&
|
||||||
|
EqualityComparer<VehicleOverrideRagdollThreshold>.Default.Equals(pOverrideRagdollThreshold, data.pOverrideRagdollThreshold) &&
|
||||||
|
StructuralComparisons.StructuralEqualityComparer.Equals(firstPersonDrivebyData, data.firstPersonDrivebyData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class VehicleOverrideRagdollThreshold
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = 1102137281;
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(modelName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(txdName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(handlingId);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(gameName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(vehicleMakeName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(expressionDictName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(expressionName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(animConvRoofDictName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(animConvRoofName);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(animConvRoofWindowsAffected);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(ptfxAssetName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(audioNameHash);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(layout);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(coverBoundOffsets);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(explosionInfo);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(scenarioLayout);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(cameraName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(aimCameraName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(bonnetCameraName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(povCameraName);
|
||||||
|
hashCode = hashCode * -1521134295 + FirstPersonDriveByIKOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + FirstPersonDriveByUnarmedIKOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + FirstPersonProjectileDriveByIKOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + FirstPersonProjectileDriveByPassengerIKOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + FirstPersonDriveByRightPassengerIKOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + FirstPersonDriveByRightPassengerUnarmedIKOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + FirstPersonMobilePhoneOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + FirstPersonPassengerMobilePhoneOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + PovCameraOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + PovCameraVerticalAdjustmentForRollCage.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + PovPassengerCameraOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + PovRearPassengerCameraOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(vfxInfoName);
|
||||||
|
hashCode = hashCode * -1521134295 + shouldUseCinematicViewMode.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + shouldCameraTransitionOnClimbUpDown.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + shouldCameraIgnoreExiting.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + AllowPretendOccupants.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + AllowJoyriding.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + AllowSundayDriving.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + AllowBodyColorMapping.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + wheelScale.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + wheelScaleRear.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + dirtLevelMin.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + dirtLevelMax.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + envEffScaleMin.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + envEffScaleMax.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + envEffScaleMin2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + envEffScaleMax2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + damageMapScale.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + damageOffsetScale.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + diffuseTint.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + steerWheelMult.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + HDTextureDist.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(lodDistances);
|
||||||
|
hashCode = hashCode * -1521134295 + minSeatHeight.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + identicalModelSpawnDistance.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + maxNumOfSameColor.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + defaultBodyHealth.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + pretendOccupantsScale.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + visibleSpawnDistScale.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + trackerPathWidth.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + weaponForceMult.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + frequency.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(swankness);
|
||||||
|
hashCode = hashCode * -1521134295 + maxNum.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(flags);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(type);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(plateType);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(dashboardType);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(vehicleClass);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(wheelType);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(trailers);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(additionalTrailers);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(drivers);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(extraIncludes);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(doorsWithCollisionWhenClosed);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(driveableDoors);
|
||||||
|
hashCode = hashCode * -1521134295 + bumpersNeedToCollideWithMap.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + needsRopeTexture.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(requiredExtras);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(rewards);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(cinematicPartCamera);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(NmBraceOverrideSet);
|
||||||
|
hashCode = hashCode * -1521134295 + buoyancySphereOffset.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + buoyancySphereSizeScale.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<VehicleOverrideRagdollThreshold>.Default.GetHashCode(pOverrideRagdollThreshold);
|
||||||
|
hashCode = hashCode * -1521134295 + StructuralComparisons.StructuralEqualityComparer.GetHashCode(firstPersonDrivebyData);
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(VehicleInitData left, VehicleInitData right)
|
||||||
|
{
|
||||||
|
return EqualityComparer<VehicleInitData>.Default.Equals(left, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(VehicleInitData left, VehicleInitData right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VehicleOverrideRagdollThreshold : IEquatable<VehicleOverrideRagdollThreshold>
|
||||||
{
|
{
|
||||||
public int MinComponent { get; set; }
|
public int MinComponent { get; set; }
|
||||||
public int MaxComponent { get; set; }
|
public int MaxComponent { get; set; }
|
||||||
public float ThresholdMult { get; set; }
|
public float ThresholdMult { get; set; }
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is VehicleOverrideRagdollThreshold threshold && Equals(threshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(VehicleOverrideRagdollThreshold other)
|
||||||
|
{
|
||||||
|
return MinComponent == other.MinComponent &&
|
||||||
|
MaxComponent == other.MaxComponent &&
|
||||||
|
ThresholdMult == other.ThresholdMult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = 1172526364;
|
||||||
|
hashCode = hashCode * -1521134295 + MinComponent.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + MaxComponent.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + ThresholdMult.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return MinComponent.ToString() + ", " + MaxComponent.ToString() + ", " + ThresholdMult.ToString();
|
return MinComponent.ToString() + ", " + MaxComponent.ToString() + ", " + ThresholdMult.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(VehicleOverrideRagdollThreshold left, VehicleOverrideRagdollThreshold right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
}
|
}
|
||||||
public class VehicleDriver
|
|
||||||
|
public static bool operator !=(VehicleOverrideRagdollThreshold left, VehicleOverrideRagdollThreshold right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class VehicleDriver : IEquatable<VehicleDriver>
|
||||||
{
|
{
|
||||||
public string driverName { get; set; }
|
public string driverName { get; set; }
|
||||||
public string npcName { get; set; }
|
public string npcName { get; set; }
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is VehicleDriver driver && Equals(driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(VehicleDriver other)
|
||||||
|
{
|
||||||
|
return driverName == other.driverName &&
|
||||||
|
npcName == other.npcName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = -1906737521;
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(driverName);
|
||||||
|
hashCode = hashCode * -1521134295 + EqualityComparer<string>.Default.GetHashCode(npcName);
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return driverName + ", " + npcName;
|
return driverName + ", " + npcName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(VehicleDriver left, VehicleDriver right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(VehicleDriver left, VehicleDriver right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -75,20 +75,17 @@ namespace CodeWalker.GameFiles
|
|||||||
var drawable = drawables[i];
|
var drawable = drawables[i];
|
||||||
var hash = hashes[i];
|
var hash = hashes[i];
|
||||||
drawable.Hash = hash;
|
drawable.Hash = hash;
|
||||||
if ((drawable.Name == null) || (drawable.Name.EndsWith("#dd")))
|
if (drawable.Name == null || drawable.Name.EndsWith("#dd", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
string hstr = JenkIndex.TryGetString(hash);
|
string hstr = JenkIndex.TryGetString(hash);
|
||||||
if (!string.IsNullOrEmpty(hstr))
|
if (!string.IsNullOrEmpty(hstr))
|
||||||
{
|
{
|
||||||
drawable.Name = hstr;
|
drawable.Name = hstr;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Drawables = Dict.Values.ToArray();
|
Drawables = Dict.Values.ToArray();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Loaded = true;
|
Loaded = true;
|
||||||
|
@ -862,6 +862,7 @@ namespace CodeWalker.GameFiles
|
|||||||
ChildYmaps[i] = gfc.GetYmap(chash);
|
ChildYmaps[i] = gfc.GetYmap(chash);
|
||||||
if (ChildYmaps[i] == null)
|
if (ChildYmaps[i] == null)
|
||||||
{
|
{
|
||||||
|
Console.WriteLine($"Couldn't find child ymap! {chash} for {Name}");
|
||||||
//couldn't find child ymap..
|
//couldn't find child ymap..
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -895,7 +896,10 @@ namespace CodeWalker.GameFiles
|
|||||||
for (int i = 0; i < ChildYmaps.Length; i++)
|
for (int i = 0; i < ChildYmaps.Length; i++)
|
||||||
{
|
{
|
||||||
var cmap = ChildYmaps[i];
|
var cmap = ChildYmaps[i];
|
||||||
if (cmap == null) continue; //nothing here..
|
if (cmap == null)
|
||||||
|
{
|
||||||
|
continue; //nothing here..
|
||||||
|
}
|
||||||
//cmap.EnsureChildYmaps();
|
//cmap.EnsureChildYmaps();
|
||||||
if ((cmap.Loaded) && (!cmap.MergedWithParent))
|
if ((cmap.Loaded) && (!cmap.MergedWithParent))
|
||||||
{
|
{
|
||||||
@ -956,7 +960,7 @@ namespace CodeWalker.GameFiles
|
|||||||
YmapEntityDef p = null;
|
YmapEntityDef p = null;
|
||||||
if ((pymap != null) && (pymap.AllEntities != null))
|
if ((pymap != null) && (pymap.AllEntities != null))
|
||||||
{
|
{
|
||||||
if ((pind < pymap.AllEntities.Length))
|
if (pind < pymap.AllEntities.Length)
|
||||||
{
|
{
|
||||||
p = pymap.AllEntities[pind];
|
p = pymap.AllEntities[pind];
|
||||||
ent.Parent = p;
|
ent.Parent = p;
|
||||||
@ -964,7 +968,9 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ }//should only happen if parent ymap not loaded yet...
|
{
|
||||||
|
Console.WriteLine($"Parent not loaded yet for {pymap.Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -974,8 +980,6 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
LODLights.Init(Parent.DistantLODLights);
|
LODLights.Init(Parent.DistantLODLights);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,8 +991,11 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//used by the editor to add to the ymap.
|
//used by the editor to add to the ymap.
|
||||||
|
|
||||||
List<YmapEntityDef> allents = new List<YmapEntityDef>();
|
List<YmapEntityDef> allents;
|
||||||
if (AllEntities != null) allents.AddRange(AllEntities);
|
if (AllEntities != null)
|
||||||
|
allents = new List<YmapEntityDef>(AllEntities);
|
||||||
|
else
|
||||||
|
allents = new List<YmapEntityDef>();
|
||||||
ent.Index = allents.Count;
|
ent.Index = allents.Count;
|
||||||
ent.Ymap = this;
|
ent.Ymap = this;
|
||||||
allents.Add(ent);
|
allents.Add(ent);
|
||||||
@ -999,8 +1006,11 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//root entity, add to roots.
|
//root entity, add to roots.
|
||||||
|
|
||||||
List<YmapEntityDef> rootents = new List<YmapEntityDef>();
|
List<YmapEntityDef> rootents;
|
||||||
if (RootEntities != null) rootents.AddRange(RootEntities);
|
if (RootEntities != null)
|
||||||
|
rootents = new List<YmapEntityDef>(RootEntities);
|
||||||
|
else
|
||||||
|
rootents = new List<YmapEntityDef>();
|
||||||
rootents.Add(ent);
|
rootents.Add(ent);
|
||||||
RootEntities = rootents.ToArray();
|
RootEntities = rootents.ToArray();
|
||||||
}
|
}
|
||||||
@ -1012,7 +1022,8 @@ namespace CodeWalker.GameFiles
|
|||||||
public bool RemoveEntity(YmapEntityDef ent)
|
public bool RemoveEntity(YmapEntityDef ent)
|
||||||
{
|
{
|
||||||
//used by the editor to remove from the ymap.
|
//used by the editor to remove from the ymap.
|
||||||
if (ent == null) return false;
|
if (ent == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
var res = true;
|
var res = true;
|
||||||
|
|
||||||
@ -1020,23 +1031,32 @@ namespace CodeWalker.GameFiles
|
|||||||
List<YmapEntityDef> newAllEntities = new List<YmapEntityDef>();
|
List<YmapEntityDef> newAllEntities = new List<YmapEntityDef>();
|
||||||
List<YmapEntityDef> newRootEntities = new List<YmapEntityDef>();
|
List<YmapEntityDef> newRootEntities = new List<YmapEntityDef>();
|
||||||
|
|
||||||
|
if (AllEntities != null)
|
||||||
|
{
|
||||||
for (int i = 0; i < AllEntities.Length; i++)
|
for (int i = 0; i < AllEntities.Length; i++)
|
||||||
{
|
{
|
||||||
var oent = AllEntities[i];
|
var oent = AllEntities[i];
|
||||||
oent.Index = newAllEntities.Count;
|
oent.Index = newAllEntities.Count;
|
||||||
if (oent != ent) newAllEntities.Add(oent);
|
if (oent != ent)
|
||||||
|
{
|
||||||
|
newAllEntities.Add(oent);
|
||||||
|
}
|
||||||
else if (i != idx)
|
else if (i != idx)
|
||||||
{
|
{
|
||||||
res = false; //indexes didn't match.. this shouldn't happen!
|
res = false; //indexes didn't match.. this shouldn't happen!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (RootEntities != null)
|
||||||
|
{
|
||||||
for (int i = 0; i < RootEntities.Length; i++)
|
for (int i = 0; i < RootEntities.Length; i++)
|
||||||
{
|
{
|
||||||
var oent = RootEntities[i];
|
var oent = RootEntities[i];
|
||||||
if (oent != ent) newRootEntities.Add(oent);
|
if (oent != ent) newRootEntities.Add(oent);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((AllEntities.Length == newAllEntities.Count) || (RootEntities.Length == newRootEntities.Count))
|
if (AllEntities == null || AllEntities.Length == newAllEntities.Count || RootEntities == null || RootEntities.Length == newRootEntities.Count)
|
||||||
{
|
{
|
||||||
res = false;
|
res = false;
|
||||||
}
|
}
|
||||||
@ -1055,7 +1075,8 @@ namespace CodeWalker.GameFiles
|
|||||||
public void AddCarGen(YmapCarGen cargen)
|
public void AddCarGen(YmapCarGen cargen)
|
||||||
{
|
{
|
||||||
List<YmapCarGen> cargens = new List<YmapCarGen>();
|
List<YmapCarGen> cargens = new List<YmapCarGen>();
|
||||||
if (CarGenerators != null) cargens.AddRange(CarGenerators);
|
if (CarGenerators != null)
|
||||||
|
cargens.AddRange(CarGenerators);
|
||||||
cargen.Ymap = this;
|
cargen.Ymap = this;
|
||||||
cargens.Add(cargen);
|
cargens.Add(cargen);
|
||||||
CarGenerators = cargens.ToArray();
|
CarGenerators = cargens.ToArray();
|
||||||
@ -1334,10 +1355,9 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public void SetName(string newname)
|
public void SetName(string newname)
|
||||||
{
|
{
|
||||||
var newnamel = newname.ToLowerInvariant();
|
|
||||||
var newnamex = newname + ".ymap";
|
var newnamex = newname + ".ymap";
|
||||||
var newhash = JenkHash.GenHash(newnamel);
|
var newhash = JenkHash.GenHashLower(newname);
|
||||||
JenkIndex.Ensure(newnamel);
|
JenkIndex.EnsureLower(newname);
|
||||||
if (RpfFileEntry != null)
|
if (RpfFileEntry != null)
|
||||||
{
|
{
|
||||||
RpfFileEntry.Name = newnamex;
|
RpfFileEntry.Name = newnamex;
|
||||||
@ -1692,7 +1712,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public int Index { get; set; }
|
public int Index { get; set; }
|
||||||
public float Distance { get; set; } //used for rendering
|
public float Distance { get; set; } //used for rendering
|
||||||
public bool IsVisible; //used for rendering
|
public bool IsWithinLodDist; //used for rendering
|
||||||
public bool ChildrenVisible; //used for rendering
|
public bool ChildrenVisible; //used for rendering
|
||||||
public bool ChildrenRendered; //used when rendering ymap mode to reduce LOD flashing...
|
public bool ChildrenRendered; //used when rendering ymap mode to reduce LOD flashing...
|
||||||
public YmapEntityDef Parent { get; set; } //for browsing convenience, also used/updated for rendering
|
public YmapEntityDef Parent { get; set; } //for browsing convenience, also used/updated for rendering
|
||||||
|
@ -1890,7 +1890,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (str.StartsWith("hash_"))
|
if (str.StartsWith("hash_", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return Convert.ToUInt32(str.Substring(5), 16);
|
return Convert.ToUInt32(str.Substring(5), 16);
|
||||||
}
|
}
|
||||||
|
@ -288,16 +288,16 @@ namespace CodeWalker.GameFiles
|
|||||||
{ }
|
{ }
|
||||||
|
|
||||||
NameHash = _CMapTypes.name;
|
NameHash = _CMapTypes.name;
|
||||||
if ((NameHash == 0) && (entry.NameLower != null))
|
if ((NameHash == 0) && (entry.Name != null))
|
||||||
{
|
{
|
||||||
int ind = entry.NameLower.LastIndexOf('.');
|
int ind = entry.Name.LastIndexOf('.');
|
||||||
if (ind > 0)
|
if (ind > 0)
|
||||||
{
|
{
|
||||||
NameHash = JenkHash.GenHash(entry.NameLower.Substring(0, ind));
|
NameHash = JenkHash.GenHashLower(entry.Name.AsSpan(0, ind));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NameHash = JenkHash.GenHash(entry.NameLower);
|
NameHash = JenkHash.GenHashLower(entry.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -10,6 +10,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
public volatile bool Loaded = false;
|
public volatile bool Loaded = false;
|
||||||
public volatile bool LoadQueued = false;
|
public volatile bool LoadQueued = false;
|
||||||
|
public DateTime LastLoadTime = DateTime.MinValue;
|
||||||
public RpfFileEntry RpfFileEntry { get; set; }
|
public RpfFileEntry RpfFileEntry { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string FilePath { get; set; } //used by the project form.
|
public string FilePath { get; set; } //used by the project form.
|
||||||
@ -91,7 +92,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public struct GameFileCacheKey
|
public struct GameFileCacheKey : IEquatable<GameFileCacheKey>
|
||||||
{
|
{
|
||||||
public uint Hash { get; set; }
|
public uint Hash { get; set; }
|
||||||
public GameFileType Type { get; set; }
|
public GameFileType Type { get; set; }
|
||||||
@ -102,13 +103,22 @@ namespace CodeWalker.GameFiles
|
|||||||
Type = type;
|
Type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override readonly bool Equals(object obj)
|
||||||
{
|
{
|
||||||
if (obj == null) return false;
|
if (obj == null)
|
||||||
if (obj is not GameFileCacheKey gameFileCacheKey) return false;
|
return false;
|
||||||
|
if (obj is not GameFileCacheKey gameFileCacheKey)
|
||||||
|
return false;
|
||||||
return gameFileCacheKey.Hash == Hash && gameFileCacheKey.Type == Type;
|
return gameFileCacheKey.Hash == Hash && gameFileCacheKey.Type == Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly bool Equals(GameFileCacheKey obj)
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
return obj.Hash == Hash && obj.Type == Type;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool operator ==(GameFileCacheKey first, GameFileCacheKey second)
|
public static bool operator ==(GameFileCacheKey first, GameFileCacheKey second)
|
||||||
{
|
{
|
||||||
return first.Equals(second);
|
return first.Equals(second);
|
||||||
@ -119,12 +129,9 @@ namespace CodeWalker.GameFiles
|
|||||||
return !first.Equals(second);
|
return !first.Equals(second);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override readonly int GetHashCode()
|
||||||
{
|
{
|
||||||
return (int)Hash;
|
return (int)Hash;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -393,11 +393,11 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
foreach (var portal in portals)
|
foreach (var portal in portals)
|
||||||
{
|
{
|
||||||
List<uint> newAttachedObjects = new List<uint>();
|
if (portal.AttachedObjects == null || portal.AttachedObjects.Length == 0)
|
||||||
if (portal.AttachedObjects == null)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
foreach(var objIndex in portal.AttachedObjects)
|
List<uint> newAttachedObjects = new List<uint>();
|
||||||
|
foreach (var objIndex in portal.AttachedObjects)
|
||||||
{
|
{
|
||||||
if (objIndex == deletedIndex) continue;
|
if (objIndex == deletedIndex) continue;
|
||||||
if (objIndex > deletedIndex)
|
if (objIndex > deletedIndex)
|
||||||
@ -411,9 +411,10 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
foreach (var room in rooms)
|
foreach (var room in rooms)
|
||||||
{
|
{
|
||||||
List<uint> newAttachedObjects = new List<uint>();
|
if (room.AttachedObjects == null || room.AttachedObjects.Length == 0)
|
||||||
if (room.AttachedObjects == null)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
List<uint> newAttachedObjects = new List<uint>();
|
||||||
foreach (var objIndex in room.AttachedObjects)
|
foreach (var objIndex in room.AttachedObjects)
|
||||||
{
|
{
|
||||||
if (objIndex == deletedIndex) continue;
|
if (objIndex == deletedIndex) continue;
|
||||||
@ -532,10 +533,12 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
public MCMloRoomDef GetEntityRoom(MCEntityDef ent)
|
public MCMloRoomDef GetEntityRoom(MCEntityDef ent)
|
||||||
{
|
{
|
||||||
if (rooms == null) return null;
|
if (rooms == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
int objectIndex = GetEntityObjectIndex(ent);
|
int objectIndex = GetEntityObjectIndex(ent);
|
||||||
if (objectIndex < 0) return null;
|
if (objectIndex < 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
for (int i = 0; i < rooms.Length; i++)
|
for (int i = 0; i < rooms.Length; i++)
|
||||||
{
|
{
|
||||||
@ -684,10 +687,15 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
var ient = Entities[j];
|
var ient = Entities[j];
|
||||||
var iarch = gfc.GetArchetype(ient._CEntityDef.archetypeName);
|
var iarch = gfc.GetArchetype(ient._CEntityDef.archetypeName);
|
||||||
ient.SetArchetype(iarch);
|
|
||||||
|
|
||||||
if (iarch == null)
|
if (iarch == null)
|
||||||
{ } //can't find archetype - des stuff eg {des_prologue_door}
|
{
|
||||||
|
Console.WriteLine($"Can't find archetype for {ient._CEntityDef.archetypeName}!");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ient.SetArchetype(iarch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateBBs(arch);
|
UpdateBBs(arch);
|
||||||
@ -708,7 +716,13 @@ namespace CodeWalker.GameFiles
|
|||||||
ient.SetArchetype(iarch);
|
ient.SetArchetype(iarch);
|
||||||
|
|
||||||
if (iarch == null)
|
if (iarch == null)
|
||||||
{ } //can't find archetype - des stuff eg {des_prologue_door}
|
{
|
||||||
|
Console.WriteLine($"Couldn't find archetype {ient._CEntityDef.archetypeName}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ient.SetArchetype(iarch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -729,7 +743,8 @@ namespace CodeWalker.GameFiles
|
|||||||
for (int j = 0; j < rooms.Length; j++)
|
for (int j = 0; j < rooms.Length; j++)
|
||||||
{
|
{
|
||||||
var room = rooms[j];
|
var room = rooms[j];
|
||||||
if ((room.AttachedObjects == null) || (room.AttachedObjects.Length == 0)) continue;
|
if (room.AttachedObjects == null || room.AttachedObjects.Length == 0)
|
||||||
|
continue;
|
||||||
Vector3 min = new Vector3(float.MaxValue);
|
Vector3 min = new Vector3(float.MaxValue);
|
||||||
Vector3 max = new Vector3(float.MinValue);
|
Vector3 max = new Vector3(float.MinValue);
|
||||||
for (int k = 0; k < room.AttachedObjects.Length; k++)
|
for (int k = 0; k < room.AttachedObjects.Length; k++)
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -675,6 +674,35 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return "Array_StructurePointer: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
return "Array_StructurePointer: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is Array_StructurePointer pointer &&
|
||||||
|
Pointer == pointer.Pointer &&
|
||||||
|
Count1 == pointer.Count1 &&
|
||||||
|
Count2 == pointer.Count2 &&
|
||||||
|
Unk1 == pointer.Unk1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = -1900453823;
|
||||||
|
hashCode = hashCode * -1521134295 + Pointer.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count1.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unk1.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Array_StructurePointer left, Array_StructurePointer right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Array_StructurePointer left, Array_StructurePointer right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[TC(typeof(EXP))] public struct Array_Structure //16 bytes - pointer for a structure array
|
[TC(typeof(EXP))] public struct Array_Structure //16 bytes - pointer for a structure array
|
||||||
{
|
{
|
||||||
@ -717,6 +745,37 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return "Array_Structure: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
return "Array_Structure: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Array_Structure x, Array_Structure y)
|
||||||
|
{
|
||||||
|
return x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Array_Structure x, Array_Structure y)
|
||||||
|
{
|
||||||
|
return !x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is null || obj is not Array_Structure arrObj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return arrObj.Pointer == this.Pointer
|
||||||
|
&& arrObj.Count1 == this.Count1
|
||||||
|
&& arrObj.Count2 == this.Count2
|
||||||
|
&& arrObj.Unk1 == this.Unk1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = -1900453823;
|
||||||
|
hashCode = hashCode * -1521134295 + Pointer.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count1.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unk1.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[TC(typeof(EXP))] public struct Array_uint //16 bytes - pointer for a uint array
|
[TC(typeof(EXP))] public struct Array_uint //16 bytes - pointer for a uint array
|
||||||
{
|
{
|
||||||
@ -757,6 +816,37 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return "Array_uint: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
return "Array_uint: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Array_uint x, Array_uint y)
|
||||||
|
{
|
||||||
|
return x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Array_uint x, Array_uint y)
|
||||||
|
{
|
||||||
|
return !x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is null || obj is not Array_uint arrObj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return arrObj.Pointer == this.Pointer
|
||||||
|
&& arrObj.Count1 == this.Count1
|
||||||
|
&& arrObj.Count2 == this.Count2
|
||||||
|
&& arrObj.Unk1 == this.Unk1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = -1900453823;
|
||||||
|
hashCode = hashCode * -1521134295 + Pointer.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count1.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unk1.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[TC(typeof(EXP))] public struct Array_ushort //16 bytes - pointer for a ushort array
|
[TC(typeof(EXP))] public struct Array_ushort //16 bytes - pointer for a ushort array
|
||||||
{
|
{
|
||||||
@ -797,6 +887,37 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return "Array_ushort: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
return "Array_ushort: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Array_ushort x, Array_ushort y)
|
||||||
|
{
|
||||||
|
return x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Array_ushort x, Array_ushort y)
|
||||||
|
{
|
||||||
|
return !x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is null || obj is not Array_ushort arrObj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return arrObj.Pointer == this.Pointer
|
||||||
|
&& arrObj.Count1 == this.Count1
|
||||||
|
&& arrObj.Count2 == this.Count2
|
||||||
|
&& arrObj.Unk1 == this.Unk1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = -1900453823;
|
||||||
|
hashCode = hashCode * -1521134295 + Pointer.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count1.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unk1.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[TC(typeof(EXP))] public struct Array_byte //16 bytes - pointer for a byte array
|
[TC(typeof(EXP))] public struct Array_byte //16 bytes - pointer for a byte array
|
||||||
{
|
{
|
||||||
@ -836,6 +957,35 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return "Array_byte: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
return "Array_byte: " + PointerDataIndex.ToString() + " (" + Count1.ToString() + "/" + Count2.ToString() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is Array_byte @byte &&
|
||||||
|
Pointer == @byte.Pointer &&
|
||||||
|
Count1 == @byte.Count1 &&
|
||||||
|
Count2 == @byte.Count2 &&
|
||||||
|
Unk1 == @byte.Unk1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = -1900453823;
|
||||||
|
hashCode = hashCode * -1521134295 + Pointer.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count1.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Count2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unk1.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Array_byte left, Array_byte right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Array_byte left, Array_byte right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[TC(typeof(EXP))] public struct Array_float //16 bytes - pointer for a float array
|
[TC(typeof(EXP))] public struct Array_float //16 bytes - pointer for a float array
|
||||||
{
|
{
|
||||||
@ -1118,7 +1268,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[TC(typeof(EXP))] public struct MetaHash
|
[TC(typeof(EXP))] public struct MetaHash : IEquatable<MetaHash>
|
||||||
{
|
{
|
||||||
public uint Hash { get; set; }
|
public uint Hash { get; set; }
|
||||||
|
|
||||||
@ -1180,7 +1330,7 @@ namespace CodeWalker.GameFiles
|
|||||||
return new MetaHash(v);
|
return new MetaHash(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override readonly bool Equals(object obj)
|
||||||
{
|
{
|
||||||
if (obj == null) return false;
|
if (obj == null) return false;
|
||||||
if (obj is not MetaHash metaHash) return false;
|
if (obj is not MetaHash metaHash) return false;
|
||||||
@ -1188,7 +1338,14 @@ namespace CodeWalker.GameFiles
|
|||||||
return metaHash.Hash == Hash;
|
return metaHash.Hash == Hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode()
|
public readonly bool Equals(MetaHash obj)
|
||||||
|
{
|
||||||
|
if (obj == null) return false;
|
||||||
|
|
||||||
|
return obj.Hash == Hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override readonly int GetHashCode()
|
||||||
{
|
{
|
||||||
return (int)Hash;
|
return (int)Hash;
|
||||||
}
|
}
|
||||||
|
@ -153,19 +153,22 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public Array_Vector3 AddPaddedVector3ArrayPtr(Vector4[] items)
|
public Array_Vector3 AddPaddedVector3ArrayPtr(Vector4[] items)
|
||||||
{
|
{
|
||||||
if ((items == null) || (items.Length == 0)) return new Array_Vector3();
|
if (items == null || items.Length == 0)
|
||||||
|
return new Array_Vector3();
|
||||||
var ptr = AddItemArray((MetaName)MetaTypeName.VECTOR4, items); //padded to vec4...
|
var ptr = AddItemArray((MetaName)MetaTypeName.VECTOR4, items); //padded to vec4...
|
||||||
return new Array_Vector3(ptr);
|
return new Array_Vector3(ptr);
|
||||||
}
|
}
|
||||||
public Array_uint AddHashArrayPtr(MetaHash[] items)
|
public Array_uint AddHashArrayPtr(MetaHash[] items)
|
||||||
{
|
{
|
||||||
if ((items == null) || (items.Length == 0)) return new Array_uint();
|
if (items == null || items.Length == 0)
|
||||||
|
return new Array_uint();
|
||||||
var ptr = AddItemArray((MetaName)MetaTypeName.HASH, items);
|
var ptr = AddItemArray((MetaName)MetaTypeName.HASH, items);
|
||||||
return new Array_uint(ptr);
|
return new Array_uint(ptr);
|
||||||
}
|
}
|
||||||
public Array_uint AddUintArrayPtr(uint[] items)
|
public Array_uint AddUintArrayPtr(uint[] items)
|
||||||
{
|
{
|
||||||
if ((items == null) || (items.Length == 0)) return new Array_uint();
|
if (items == null || items.Length == 0)
|
||||||
|
return new Array_uint();
|
||||||
var ptr = AddItemArray((MetaName)MetaTypeName.UINT, items);
|
var ptr = AddItemArray((MetaName)MetaTypeName.UINT, items);
|
||||||
return new Array_uint(ptr);
|
return new Array_uint(ptr);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -10,7 +11,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public static class MetaNames
|
public static class MetaNames
|
||||||
{
|
{
|
||||||
public static Dictionary<uint, string> stringCache = new Dictionary<uint, string>();
|
public static ConcurrentDictionary<uint, string> stringCache = new ConcurrentDictionary<uint, string>();
|
||||||
public static bool TryGetString(uint h, out string str)
|
public static bool TryGetString(uint h, out string str)
|
||||||
{
|
{
|
||||||
if (stringCache.TryGetValue(h, out str))
|
if (stringCache.TryGetValue(h, out str))
|
||||||
@ -21,10 +22,10 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
str = ((MetaName)h).ToString();
|
str = ((MetaName)h).ToString();
|
||||||
if (str.StartsWith("@")) str = str.Substring(1); //mainly to handle the @null entry
|
if (str.StartsWith("@")) str = str.Substring(1); //mainly to handle the @null entry
|
||||||
stringCache.Add(h, str);
|
stringCache.TryAdd(h, str);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
stringCache.Add(h, str);
|
stringCache.TryAdd(h, str);
|
||||||
str = null;
|
str = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1438,26 +1438,39 @@ namespace CodeWalker.GameFiles
|
|||||||
public static byte[] ConvertToBytes<T>(T item) where T : struct
|
public static byte[] ConvertToBytes<T>(T item) where T : struct
|
||||||
{
|
{
|
||||||
int size = Marshal.SizeOf(typeof(T));
|
int size = Marshal.SizeOf(typeof(T));
|
||||||
int offset = 0;
|
//int offset = 0;
|
||||||
byte[] arr = new byte[size];
|
byte[] arr = new byte[size];
|
||||||
IntPtr ptr = Marshal.AllocHGlobal(size);
|
MemoryMarshal.TryWrite(arr.AsSpan(), ref item);
|
||||||
Marshal.StructureToPtr(item, ptr, true);
|
|
||||||
Marshal.Copy(ptr, arr, 0, size);
|
|
||||||
Marshal.FreeHGlobal(ptr);
|
|
||||||
offset += size;
|
|
||||||
return arr;
|
return arr;
|
||||||
|
//IntPtr ptr = Marshal.AllocHGlobal(size);
|
||||||
|
//Marshal.StructureToPtr(item, ptr, true);
|
||||||
|
//Marshal.Copy(ptr, arr, 0, size);
|
||||||
|
//Marshal.FreeHGlobal(ptr);
|
||||||
|
//offset += size;
|
||||||
|
//return arr;
|
||||||
}
|
}
|
||||||
public static byte[] ConvertArrayToBytes<T>(params T[] items) where T : struct
|
public static byte[] ConvertArrayToBytes<T>(params T[] items) where T : struct
|
||||||
{
|
{
|
||||||
if (items == null) return null;
|
if (items == null) return null;
|
||||||
|
|
||||||
var size = Marshal.SizeOf(typeof(T)) * items.Length;
|
return MemoryMarshal.AsBytes(items.AsSpan()).ToArray();
|
||||||
var b = new byte[size];
|
|
||||||
GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
//var size = Marshal.SizeOf(typeof(T)) * items.Length;
|
||||||
var h = handle.AddrOfPinnedObject();
|
//var b = new byte[size];
|
||||||
Marshal.Copy(h, b, 0, size);
|
//GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
||||||
handle.Free();
|
//var h = handle.AddrOfPinnedObject();
|
||||||
return b;
|
//Marshal.Copy(h, b, 0, size);
|
||||||
|
//handle.Free();
|
||||||
|
//return b;
|
||||||
|
|
||||||
|
//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 size = Marshal.SizeOf(typeof(T));
|
||||||
@ -1502,20 +1515,33 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
public static Span<T> ConvertDataArray<T>(byte[] data, int offset, int count) where T : struct
|
public static Span<T> ConvertDataArray<T>(byte[] data, int offset, int count) where T : struct
|
||||||
{
|
{
|
||||||
|
//T[] items = new T[count];
|
||||||
|
//int itemsize = Marshal.SizeOf(typeof(T));
|
||||||
|
////for (int i = 0; i < count; i++)
|
||||||
|
////{
|
||||||
|
//// int off = offset + i * itemsize;
|
||||||
|
//// items[i] = ConvertData<T>(data, off);
|
||||||
|
////}
|
||||||
|
//GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
||||||
|
//var h = handle.AddrOfPinnedObject();
|
||||||
|
//Marshal.Copy(data, offset, h, itemsize * count);
|
||||||
|
//handle.Free();
|
||||||
|
|
||||||
|
//return items;
|
||||||
return MemoryMarshal.Cast<byte, T>(data.AsSpan(offset, count * Marshal.SizeOf(typeof(T))));
|
return MemoryMarshal.Cast<byte, T>(data.AsSpan(offset, count * Marshal.SizeOf(typeof(T))));
|
||||||
T[] items = new T[count];
|
//T[] items = new T[count];
|
||||||
int itemsize = Marshal.SizeOf(typeof(T));
|
//int itemsize = Marshal.SizeOf(typeof(T));
|
||||||
//for (int i = 0; i < count; i++)
|
//for (int i = 0; i < count; i++)
|
||||||
//{
|
//{
|
||||||
// int off = offset + i * itemsize;
|
// int off = offset + i * itemsize;
|
||||||
// items[i] = ConvertData<T>(data, off);
|
// items[i] = ConvertData<T>(data, off);
|
||||||
//}
|
//}
|
||||||
GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
//GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
||||||
var h = handle.AddrOfPinnedObject();
|
//var h = handle.AddrOfPinnedObject();
|
||||||
Marshal.Copy(data, offset, h, itemsize * count);
|
//Marshal.Copy(data, offset, h, itemsize * count);
|
||||||
handle.Free();
|
//handle.Free();
|
||||||
|
|
||||||
return items;
|
//return items;
|
||||||
}
|
}
|
||||||
public static T[] ConvertDataArray<T>(Meta meta, MetaName name, Array_StructurePointer array) where T : struct
|
public static T[] ConvertDataArray<T>(Meta meta, MetaName name, Array_StructurePointer array) where T : struct
|
||||||
{
|
{
|
||||||
@ -1583,13 +1609,13 @@ namespace CodeWalker.GameFiles
|
|||||||
} //don't try to read too many items..
|
} //don't try to read too many items..
|
||||||
|
|
||||||
|
|
||||||
ConvertDataArray<T>(ptrblock.Data, itemoffset * Marshal.SizeOf(typeof(T)), itemcount).CopyTo(items.AsSpan(curi));
|
//ConvertDataArray<T>(ptrblock.Data, itemoffset * Marshal.SizeOf(typeof(T)), itemcount).CopyTo(items.AsSpan(curi));
|
||||||
//for (int i = 0; i < itemcount; i++)
|
for (int i = 0; i < itemcount; i++)
|
||||||
//{
|
{
|
||||||
// int offset = (itemoffset + i) * itemsize;
|
int offset = (itemoffset + i) * itemsize;
|
||||||
// int index = curi + i;
|
int index = curi + i;
|
||||||
// items[index] = ConvertData<T>(ptrblock.Data, offset);
|
items[index] = ConvertData<T>(ptrblock.Data, offset);
|
||||||
//}
|
}
|
||||||
itemoffset = 0; //start at beginning of next block..
|
itemoffset = 0; //start at beginning of next block..
|
||||||
curi += itemcount;
|
curi += itemcount;
|
||||||
itemsleft -= itemcount;
|
itemsleft -= itemcount;
|
||||||
@ -2500,7 +2526,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
_Data = data;
|
_Data = data;
|
||||||
RoomName = MetaTypes.GetString(meta, _Data.name);
|
RoomName = MetaTypes.GetString(meta, _Data.name);
|
||||||
AttachedObjects = MetaTypes.GetUintArray(meta, _Data.attachedObjects);
|
AttachedObjects = MetaTypes.GetUintArray(meta, _Data.attachedObjects) ?? Array.Empty<uint>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Load(Meta meta, MetaPOINTER ptr)
|
public override void Load(Meta meta, MetaPOINTER ptr)
|
||||||
@ -2521,14 +2547,7 @@ namespace CodeWalker.GameFiles
|
|||||||
_Data.name = new CharPointer();
|
_Data.name = new CharPointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (AttachedObjects != null)
|
|
||||||
{
|
|
||||||
_Data.attachedObjects = mb.AddUintArrayPtr(AttachedObjects);
|
_Data.attachedObjects = mb.AddUintArrayPtr(AttachedObjects);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_Data.attachedObjects = new Array_uint();
|
|
||||||
}
|
|
||||||
|
|
||||||
mb.AddStructureInfo(MetaName.CMloRoomDef);
|
mb.AddStructureInfo(MetaName.CMloRoomDef);
|
||||||
return mb.AddItemPtr(MetaName.CMloRoomDef, _Data);
|
return mb.AddItemPtr(MetaName.CMloRoomDef, _Data);
|
||||||
@ -4101,6 +4120,61 @@ namespace CodeWalker.GameFiles
|
|||||||
MaxCellY = (int)Math.Floor(gv.Y);
|
MaxCellY = (int)Math.Floor(gv.Y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(rage__spdGrid2D x, rage__spdGrid2D y)
|
||||||
|
{
|
||||||
|
return x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(rage__spdGrid2D x, rage__spdGrid2D y)
|
||||||
|
{
|
||||||
|
return x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is null || obj is not rage__spdGrid2D arrObj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return arrObj.MaxCellX == this.MaxCellX
|
||||||
|
&& arrObj.MaxCellY == this.MaxCellY
|
||||||
|
&& arrObj.MinCellX == this.MinCellX
|
||||||
|
&& arrObj.MinCellY == this.MinCellY
|
||||||
|
&& arrObj.CellDimX == this.CellDimX
|
||||||
|
&& arrObj.CellDimY == this.CellDimY
|
||||||
|
&& arrObj.Unused0 == this.Unused0
|
||||||
|
&& arrObj.Unused1 == this.Unused1
|
||||||
|
&& arrObj.Unused2 == this.Unused2
|
||||||
|
&& arrObj.Unused3 == this.Unused3
|
||||||
|
&& arrObj.Unused4 == this.Unused4
|
||||||
|
&& arrObj.Unused5 == this.Unused5
|
||||||
|
&& arrObj.Unused6 == this.Unused6
|
||||||
|
&& arrObj.Unused7 == this.Unused7
|
||||||
|
&& arrObj.Unused8 == this.Unused8
|
||||||
|
&& arrObj.Unused9 == this.Unused9;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = 418850833;
|
||||||
|
hashCode = hashCode * -1521134295 + Unused0.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused1.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + MinCellX.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + MaxCellX.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + MinCellY.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + MaxCellY.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused3.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused4.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused5.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused6.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + CellDimX.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + CellDimY.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused7.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused8.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused9.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[TC(typeof(EXP))] public struct rage__spdAABB //32 bytes, Key:1158138379
|
[TC(typeof(EXP))] public struct rage__spdAABB //32 bytes, Key:1158138379
|
||||||
@ -4150,6 +4224,57 @@ namespace CodeWalker.GameFiles
|
|||||||
public Array_ushort Unk_3844724227 { get; set; } //248 248: Array: 0: 3844724227 {0: UnsignedShort: 0: 256}
|
public Array_ushort Unk_3844724227 { get; set; } //248 248: Array: 0: 3844724227 {0: UnsignedShort: 0: 256}
|
||||||
public Array_Structure Clusters { get; set; } //264 264: Array: 0: Clusters//3587988394 {0: Structure: CScenarioPointCluster//750308016: 256}
|
public Array_Structure Clusters { get; set; } //264 264: Array: 0: Clusters//3587988394 {0: Structure: CScenarioPointCluster//750308016: 256}
|
||||||
public CScenarioPointLookUps LookUps { get; set; } //280 280: Structure: CScenarioPointLookUps//3019621867: LookUps//1097626284
|
public CScenarioPointLookUps LookUps { get; set; } //280 280: Structure: CScenarioPointLookUps//3019621867: LookUps//1097626284
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is CScenarioPointRegion region &&
|
||||||
|
VersionNumber == region.VersionNumber &&
|
||||||
|
Unused0 == region.Unused0 &&
|
||||||
|
EqualityComparer<CScenarioPointContainer>.Default.Equals(Points, region.Points) &&
|
||||||
|
Unused1 == region.Unused1 &&
|
||||||
|
Unused2 == region.Unused2 &&
|
||||||
|
Unused3 == region.Unused3 &&
|
||||||
|
Unused4 == region.Unused4 &&
|
||||||
|
EqualityComparer<Array_Structure>.Default.Equals(EntityOverrides, region.EntityOverrides) &&
|
||||||
|
Unused5 == region.Unused5 &&
|
||||||
|
Unused6 == region.Unused6 &&
|
||||||
|
EqualityComparer<CScenarioChainingGraph>.Default.Equals(ChainingGraph, region.ChainingGraph) &&
|
||||||
|
EqualityComparer<rage__spdGrid2D>.Default.Equals(AccelGrid, region.AccelGrid) &&
|
||||||
|
EqualityComparer<Array_ushort>.Default.Equals(Unk_3844724227, region.Unk_3844724227) &&
|
||||||
|
EqualityComparer<Array_Structure>.Default.Equals(Clusters, region.Clusters) &&
|
||||||
|
EqualityComparer<CScenarioPointLookUps>.Default.Equals(LookUps, region.LookUps);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = 1436693857;
|
||||||
|
hashCode = hashCode * -1521134295 + VersionNumber.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused0.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Points.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused1.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused3.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused4.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + EntityOverrides.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused5.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused6.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + ChainingGraph.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + AccelGrid.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unk_3844724227.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Clusters.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + LookUps.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(CScenarioPointRegion left, CScenarioPointRegion right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(CScenarioPointRegion left, CScenarioPointRegion right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[TC(typeof(EXP))] public class MCScenarioPointRegion : MetaWrapper
|
[TC(typeof(EXP))] public class MCScenarioPointRegion : MetaWrapper
|
||||||
{
|
{
|
||||||
@ -4531,10 +4656,43 @@ namespace CodeWalker.GameFiles
|
|||||||
public uint Unused2 { get; set; }//40
|
public uint Unused2 { get; set; }//40
|
||||||
public uint Unused3 { get; set; }//44
|
public uint Unused3 { get; set; }//44
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is CScenarioPointContainer container &&
|
||||||
|
EqualityComparer<Array_Structure>.Default.Equals(LoadSavePoints, container.LoadSavePoints) &&
|
||||||
|
EqualityComparer<Array_Structure>.Default.Equals(MyPoints, container.MyPoints) &&
|
||||||
|
Unused0 == container.Unused0 &&
|
||||||
|
Unused1 == container.Unused1 &&
|
||||||
|
Unused2 == container.Unused2 &&
|
||||||
|
Unused3 == container.Unused3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = 746587205;
|
||||||
|
hashCode = hashCode * -1521134295 + LoadSavePoints.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + MyPoints.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused0.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused1.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused3.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return LoadSavePoints.Count1.ToString() + " LoadSavePoints, " + MyPoints.Count1.ToString() + " MyPoints";
|
return LoadSavePoints.Count1.ToString() + " LoadSavePoints, " + MyPoints.Count1.ToString() + " MyPoints";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(CScenarioPointContainer left, CScenarioPointContainer right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(CScenarioPointContainer left, CScenarioPointContainer right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[TC(typeof(EXP))] public class MCScenarioPointContainer : MetaWrapper
|
[TC(typeof(EXP))] public class MCScenarioPointContainer : MetaWrapper
|
||||||
{
|
{
|
||||||
@ -5032,6 +5190,45 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return Nodes.Count1.ToString() + " Nodes, " + Edges.Count1.ToString() + " Edges, " + Chains.Count1.ToString() + " Chains";
|
return Nodes.Count1.ToString() + " Nodes, " + Edges.Count1.ToString() + " Edges, " + Chains.Count1.ToString() + " Chains";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(CScenarioChainingGraph x, CScenarioChainingGraph y)
|
||||||
|
{
|
||||||
|
return !x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(CScenarioChainingGraph x, CScenarioChainingGraph y)
|
||||||
|
{
|
||||||
|
return x.Equals(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is null || obj is not CScenarioChainingGraph arrObj)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return arrObj.Nodes == this.Nodes
|
||||||
|
&& arrObj.Edges == this.Edges
|
||||||
|
&& arrObj.Chains == this.Chains;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = -1851298727;
|
||||||
|
hashCode = hashCode * -1521134295 + Nodes.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Edges.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Chains.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused0.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused1.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused2.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused3.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused4.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused5.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused6.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused7.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused8.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + Unused9.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[TC(typeof(EXP))] public class MCScenarioChainingGraph : MetaWrapper
|
[TC(typeof(EXP))] public class MCScenarioChainingGraph : MetaWrapper
|
||||||
{
|
{
|
||||||
@ -5731,6 +5928,39 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
return "CScenarioPointLookUps";
|
return "CScenarioPointLookUps";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is CScenarioPointLookUps ups &&
|
||||||
|
EqualityComparer<Array_uint>.Default.Equals(TypeNames, ups.TypeNames) &&
|
||||||
|
EqualityComparer<Array_uint>.Default.Equals(PedModelSetNames, ups.PedModelSetNames) &&
|
||||||
|
EqualityComparer<Array_uint>.Default.Equals(VehicleModelSetNames, ups.VehicleModelSetNames) &&
|
||||||
|
EqualityComparer<Array_uint>.Default.Equals(GroupNames, ups.GroupNames) &&
|
||||||
|
EqualityComparer<Array_uint>.Default.Equals(InteriorNames, ups.InteriorNames) &&
|
||||||
|
EqualityComparer<Array_uint>.Default.Equals(RequiredIMapNames, ups.RequiredIMapNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
int hashCode = -153113894;
|
||||||
|
hashCode = hashCode * -1521134295 + TypeNames.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + PedModelSetNames.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + VehicleModelSetNames.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + GroupNames.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + InteriorNames.GetHashCode();
|
||||||
|
hashCode = hashCode * -1521134295 + RequiredIMapNames.GetHashCode();
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(CScenarioPointLookUps left, CScenarioPointLookUps right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(CScenarioPointLookUps left, CScenarioPointLookUps right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
[TC(typeof(EXP))] public class MCScenarioPointLookUps : MetaWrapper
|
[TC(typeof(EXP))] public class MCScenarioPointLookUps : MetaWrapper
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using SharpDX;
|
|
||||||
|
|
||||||
|
using SharpDX;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -15,144 +17,143 @@ namespace CodeWalker.GameFiles
|
|||||||
public static string GetXml(RpfFileEntry e, byte[] data, out string filename, string outputfolder = "")
|
public static string GetXml(RpfFileEntry e, byte[] data, out string filename, string outputfolder = "")
|
||||||
{
|
{
|
||||||
var fn = e.Name;
|
var fn = e.Name;
|
||||||
var fnl = fn.ToLowerInvariant();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(outputfolder))
|
if (!string.IsNullOrEmpty(outputfolder))
|
||||||
{
|
{
|
||||||
outputfolder = Path.Combine(outputfolder, e.GetShortName());
|
outputfolder = Path.Combine(outputfolder, e.ShortName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fnl.EndsWith(".ymt"))
|
if (fn.EndsWith(".ymt", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YmtFile ymt = RpfFile.GetFile<YmtFile>(e, data);
|
YmtFile ymt = RpfFile.GetFile<YmtFile>(e, data);
|
||||||
return GetXml(ymt, out filename);
|
return GetXml(ymt, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ymf"))
|
else if (fn.EndsWith(".ymf", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YmfFile ymf = RpfFile.GetFile<YmfFile>(e, data);
|
YmfFile ymf = RpfFile.GetFile<YmfFile>(e, data);
|
||||||
return GetXml(ymf, out filename);
|
return GetXml(ymf, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ymap"))
|
else if (fn.EndsWith(".ymap", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YmapFile ymap = RpfFile.GetFile<YmapFile>(e, data);
|
YmapFile ymap = RpfFile.GetFile<YmapFile>(e, data);
|
||||||
return GetXml(ymap, out filename);
|
return GetXml(ymap, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ytyp"))
|
else if (fn.EndsWith(".ytyp", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YtypFile ytyp = RpfFile.GetFile<YtypFile>(e, data);
|
YtypFile ytyp = RpfFile.GetFile<YtypFile>(e, data);
|
||||||
return GetXml(ytyp, out filename);
|
return GetXml(ytyp, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".pso"))
|
else if (fn.EndsWith(".pso", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
JPsoFile pso = RpfFile.GetFile<JPsoFile>(e, data);
|
JPsoFile pso = RpfFile.GetFile<JPsoFile>(e, data);
|
||||||
return GetXml(pso, out filename);
|
return GetXml(pso, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".cut"))
|
else if (fn.EndsWith(".cut", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
CutFile cut = RpfFile.GetFile<CutFile>(e, data);
|
CutFile cut = RpfFile.GetFile<CutFile>(e, data);
|
||||||
return GetXml(cut, out filename);
|
return GetXml(cut, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".rel"))
|
else if (fn.EndsWith(".rel", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
RelFile rel = RpfFile.GetFile<RelFile>(e, data);
|
RelFile rel = RpfFile.GetFile<RelFile>(e, data);
|
||||||
return GetXml(rel, out filename);
|
return GetXml(rel, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ynd"))
|
else if (fn.EndsWith(".ynd", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YndFile ynd = RpfFile.GetFile<YndFile>(e, data);
|
YndFile ynd = RpfFile.GetFile<YndFile>(e, data);
|
||||||
return GetXml(ynd, out filename);
|
return GetXml(ynd, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ynv"))
|
else if (fn.EndsWith(".ynv", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YnvFile ynv = RpfFile.GetFile<YnvFile>(e, data);
|
YnvFile ynv = RpfFile.GetFile<YnvFile>(e, data);
|
||||||
return GetXml(ynv, out filename);
|
return GetXml(ynv, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ycd"))
|
else if (fn.EndsWith(".ycd", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YcdFile ycd = RpfFile.GetFile<YcdFile>(e, data);
|
YcdFile ycd = RpfFile.GetFile<YcdFile>(e, data);
|
||||||
return GetXml(ycd, out filename);
|
return GetXml(ycd, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ybn"))
|
else if (fn.EndsWith(".ybn", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YbnFile ybn = RpfFile.GetFile<YbnFile>(e, data);
|
YbnFile ybn = RpfFile.GetFile<YbnFile>(e, data);
|
||||||
return GetXml(ybn, out filename);
|
return GetXml(ybn, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ytd"))
|
else if (fn.EndsWith(".ytd", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YtdFile ytd = RpfFile.GetFile<YtdFile>(e, data);
|
YtdFile ytd = RpfFile.GetFile<YtdFile>(e, data);
|
||||||
return GetXml(ytd, out filename, outputfolder);
|
return GetXml(ytd, out filename, outputfolder);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ydr"))
|
else if (fn.EndsWith(".ydr", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YdrFile ydr = RpfFile.GetFile<YdrFile>(e, data);
|
YdrFile ydr = RpfFile.GetFile<YdrFile>(e, data);
|
||||||
return GetXml(ydr, out filename, outputfolder);
|
return GetXml(ydr, out filename, outputfolder);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ydd"))
|
else if (fn.EndsWith(".ydd", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YddFile ydd = RpfFile.GetFile<YddFile>(e, data);
|
YddFile ydd = RpfFile.GetFile<YddFile>(e, data);
|
||||||
return GetXml(ydd, out filename, outputfolder);
|
return GetXml(ydd, out filename, outputfolder);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".yft"))
|
else if (fn.EndsWith(".yft", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YftFile yft = RpfFile.GetFile<YftFile>(e, data);
|
YftFile yft = RpfFile.GetFile<YftFile>(e, data);
|
||||||
return GetXml(yft, out filename, outputfolder);
|
return GetXml(yft, out filename, outputfolder);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ypt"))
|
else if (fn.EndsWith(".ypt", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YptFile ypt = RpfFile.GetFile<YptFile>(e, data);
|
YptFile ypt = RpfFile.GetFile<YptFile>(e, data);
|
||||||
return GetXml(ypt, out filename, outputfolder);
|
return GetXml(ypt, out filename, outputfolder);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".yld"))
|
else if (fn.EndsWith(".yld", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YldFile yld = RpfFile.GetFile<YldFile>(e, data);
|
YldFile yld = RpfFile.GetFile<YldFile>(e, data);
|
||||||
return GetXml(yld, out filename);
|
return GetXml(yld, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".yed"))
|
else if (fn.EndsWith(".yed", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YedFile yed = RpfFile.GetFile<YedFile>(e, data);
|
YedFile yed = RpfFile.GetFile<YedFile>(e, data);
|
||||||
return GetXml(yed, out filename);
|
return GetXml(yed, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ywr"))
|
else if (fn.EndsWith(".ywr", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YwrFile ywr = RpfFile.GetFile<YwrFile>(e, data);
|
YwrFile ywr = RpfFile.GetFile<YwrFile>(e, data);
|
||||||
return GetXml(ywr, out filename);
|
return GetXml(ywr, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".yvr"))
|
else if (fn.EndsWith(".yvr", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YvrFile yvr = RpfFile.GetFile<YvrFile>(e, data);
|
YvrFile yvr = RpfFile.GetFile<YvrFile>(e, data);
|
||||||
return GetXml(yvr, out filename);
|
return GetXml(yvr, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".ypdb"))
|
else if (fn.EndsWith(".ypdb", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YpdbFile ypdb = RpfFile.GetFile<YpdbFile>(e, data);
|
YpdbFile ypdb = RpfFile.GetFile<YpdbFile>(e, data);
|
||||||
return GetXml(ypdb, out filename);
|
return GetXml(ypdb, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".yfd"))
|
else if (fn.EndsWith(".yfd", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
YfdFile yfd = RpfFile.GetFile<YfdFile>(e, data);
|
YfdFile yfd = RpfFile.GetFile<YfdFile>(e, data);
|
||||||
return GetXml(yfd, out filename);
|
return GetXml(yfd, out filename);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".awc"))
|
else if (fn.EndsWith(".awc", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
AwcFile awc = RpfFile.GetFile<AwcFile>(e, data);
|
AwcFile awc = RpfFile.GetFile<AwcFile>(e, data);
|
||||||
return GetXml(awc, out filename, outputfolder);
|
return GetXml(awc, out filename, outputfolder);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".fxc"))
|
else if (fn.EndsWith(".fxc", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
FxcFile fxc = RpfFile.GetFile<FxcFile>(e, data);
|
FxcFile fxc = RpfFile.GetFile<FxcFile>(e, data);
|
||||||
return GetXml(fxc, out filename, outputfolder);
|
return GetXml(fxc, out filename, outputfolder);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith("cache_y.dat"))
|
else if (fn.EndsWith("cache_y.dat", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
CacheDatFile cdf = RpfFile.GetFile<CacheDatFile>(e, data);
|
CacheDatFile cdf = RpfFile.GetFile<CacheDatFile>(e, data);
|
||||||
return GetXml(cdf, out filename, outputfolder);
|
return GetXml(cdf, out filename, outputfolder);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".dat") && fnl.StartsWith("heightmap"))
|
else if (fn.EndsWith(".dat", StringComparison.OrdinalIgnoreCase) && fn.StartsWith("heightmap", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
HeightmapFile hmf = RpfFile.GetFile<HeightmapFile>(e, data);
|
HeightmapFile hmf = RpfFile.GetFile<HeightmapFile>(e, data);
|
||||||
return GetXml(hmf, out filename, outputfolder);
|
return GetXml(hmf, out filename, outputfolder);
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".mrf"))
|
else if (fn.EndsWith(".mrf", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
MrfFile mrf = RpfFile.GetFile<MrfFile>(e, data);
|
MrfFile mrf = RpfFile.GetFile<MrfFile>(e, data);
|
||||||
return GetXml(mrf, out filename, outputfolder);
|
return GetXml(mrf, out filename, outputfolder);
|
||||||
@ -1653,10 +1654,8 @@ namespace CodeWalker.GameFiles
|
|||||||
for (int i = 0; i < pso.SchemaSection.Entries.Length; i++)
|
for (int i = 0; i < pso.SchemaSection.Entries.Length; i++)
|
||||||
{
|
{
|
||||||
var entry = pso.SchemaSection.Entries[i];
|
var entry = pso.SchemaSection.Entries[i];
|
||||||
var enuminfo = entry as PsoEnumInfo;
|
|
||||||
var structinfo = entry as PsoStructureInfo;
|
|
||||||
|
|
||||||
if (enuminfo != null)
|
if (entry is PsoEnumInfo enuminfo)
|
||||||
{
|
{
|
||||||
if (!EnumDict.ContainsKey(enuminfo.IndexInfo.NameHash))
|
if (!EnumDict.ContainsKey(enuminfo.IndexInfo.NameHash))
|
||||||
{
|
{
|
||||||
@ -1670,7 +1669,7 @@ namespace CodeWalker.GameFiles
|
|||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (structinfo != null)
|
else if (entry is PsoStructureInfo structinfo)
|
||||||
{
|
{
|
||||||
if (!StructDict.ContainsKey(structinfo.IndexInfo.NameHash))
|
if (!StructDict.ContainsKey(structinfo.IndexInfo.NameHash))
|
||||||
{
|
{
|
||||||
@ -1691,14 +1690,12 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public PsoStructureInfo GetStructureInfo(MetaName name)
|
public PsoStructureInfo GetStructureInfo(MetaName name)
|
||||||
{
|
{
|
||||||
PsoStructureInfo i = null;
|
StructDict.TryGetValue(name, out PsoStructureInfo i);
|
||||||
StructDict.TryGetValue(name, out i);
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
public PsoEnumInfo GetEnumInfo(MetaName name)
|
public PsoEnumInfo GetEnumInfo(MetaName name)
|
||||||
{
|
{
|
||||||
PsoEnumInfo i = null;
|
EnumDict.TryGetValue(name, out PsoEnumInfo i);
|
||||||
EnumDict.TryGetValue(name, out i);
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2004,7 +2001,7 @@ namespace CodeWalker.GameFiles
|
|||||||
var aind = ind + 1;
|
var aind = ind + 1;
|
||||||
if (itemCount > 0)
|
if (itemCount > 0)
|
||||||
{
|
{
|
||||||
OpenTag(sb, ind, arrTag);
|
OpenTag(sb, ind, arrTag, metaName: typeName);
|
||||||
for (int n = 0; n < itemCount; n++)
|
for (int n = 0; n < itemCount; n++)
|
||||||
{
|
{
|
||||||
Indent(sb, aind);
|
Indent(sb, aind);
|
||||||
|
@ -337,16 +337,26 @@ namespace CodeWalker.GameFiles
|
|||||||
var reader = new DataReader(stream, Endianess.BigEndian);
|
var reader = new DataReader(stream, Endianess.BigEndian);
|
||||||
var identInt = reader.ReadUInt32();
|
var identInt = reader.ReadUInt32();
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
return ((identInt ) == 1347635534); //"PSIN"
|
return IsPSO(identInt); //"PSIN"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsPSO(uint identInt)
|
||||||
|
{
|
||||||
|
return identInt == 1347635534;
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsRBF(Stream stream)
|
public static bool IsRBF(Stream stream)
|
||||||
{
|
{
|
||||||
var reader = new DataReader(stream, Endianess.BigEndian);
|
var reader = new DataReader(stream, Endianess.BigEndian);
|
||||||
var identInt = reader.ReadUInt32();
|
var identInt = reader.ReadUInt32();
|
||||||
stream.Position = 0;
|
stream.Position = 0;
|
||||||
return ((identInt & 0xFFFFFF00) == 0x52424600);
|
return IsRBF(identInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsRBF(uint identInt)
|
||||||
|
{
|
||||||
|
return (identInt & 0xFFFFFF00) == 0x52424600;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,15 +881,15 @@ namespace CodeWalker.GameFiles
|
|||||||
foreach (var str in strs)
|
foreach (var str in strs)
|
||||||
{
|
{
|
||||||
JenkIndex.Ensure(str);
|
JenkIndex.Ensure(str);
|
||||||
JenkIndex.Ensure(str.ToLowerInvariant());
|
JenkIndex.EnsureLower(str);
|
||||||
}
|
}
|
||||||
Strings = strs.ToArray();
|
Strings = strs.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(DataWriter writer)
|
public void Write(DataWriter writer)
|
||||||
{
|
{
|
||||||
var strStream = new MemoryStream();
|
using var strStream = new MemoryStream();
|
||||||
var strWriter = new DataWriter(strStream, Endianess.BigEndian);
|
using var strWriter = new DataWriter(strStream, Endianess.BigEndian);
|
||||||
foreach (var str in Strings)
|
foreach (var str in Strings)
|
||||||
{
|
{
|
||||||
strWriter.Write(str);
|
strWriter.Write(str);
|
||||||
@ -926,7 +936,7 @@ namespace CodeWalker.GameFiles
|
|||||||
foreach (var str in strs)
|
foreach (var str in strs)
|
||||||
{
|
{
|
||||||
JenkIndex.Ensure(str);
|
JenkIndex.Ensure(str);
|
||||||
JenkIndex.Ensure(str.ToLowerInvariant());
|
JenkIndex.EnsureLower(str);
|
||||||
}
|
}
|
||||||
Strings = strs.ToArray();
|
Strings = strs.ToArray();
|
||||||
}
|
}
|
||||||
|
@ -15819,46 +15819,52 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public static T ConvertDataRaw<T>(byte[] data) where T : struct
|
public static T ConvertDataRaw<T>(byte[] data) where T : struct
|
||||||
{
|
{
|
||||||
MemoryMarshal.TryRead<T>(data.AsSpan(), out T value);
|
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||||
|
var h = handle.AddrOfPinnedObject();
|
||||||
return value;
|
var r = Marshal.PtrToStructure<T>(h);
|
||||||
|
handle.Free();
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
public static T ConvertDataRawOld<T>(byte[] data, int offset) where T : struct
|
||||||
|
{
|
||||||
|
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||||
|
var h = handle.AddrOfPinnedObject();
|
||||||
|
var r = Marshal.PtrToStructure<T>(h + offset);
|
||||||
|
handle.Free();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
public static T ConvertDataRaw<T>(byte[] data, int offset) where T : struct
|
public static T ConvertDataRaw<T>(byte[] data, int offset) where T : struct
|
||||||
{
|
{
|
||||||
MemoryMarshal.TryRead<T>(data.AsSpan(offset), out T value);
|
MemoryMarshal.TryRead<T>(data.AsSpan(offset), out var value);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
//return MemoryMarshal.GetReference<T>(data.AsSpan(offset));
|
|
||||||
//GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
|
||||||
//var h = handle.AddrOfPinnedObject();
|
|
||||||
//var r = Marshal.PtrToStructure<T>(h + offset);
|
|
||||||
//handle.Free();
|
|
||||||
//return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static T ConvertData<T>(byte[] data, int offset) where T : struct, IPsoSwapEnd
|
public static T ConvertData<T>(byte[] data, int offset) where T : struct, IPsoSwapEnd
|
||||||
{
|
{
|
||||||
MemoryMarshal.TryRead<T>(data.AsSpan(offset), out T value);
|
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
||||||
|
var h = handle.AddrOfPinnedObject();
|
||||||
value.SwapEnd();
|
var r = Marshal.PtrToStructure<T>(h + offset);
|
||||||
|
handle.Free();
|
||||||
return value;
|
r.SwapEnd();
|
||||||
//GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
return r;
|
||||||
//var h = handle.AddrOfPinnedObject();
|
|
||||||
//var r = Marshal.PtrToStructure<T>(h + offset);
|
|
||||||
//handle.Free();
|
|
||||||
//r.SwapEnd();
|
|
||||||
//return r;
|
|
||||||
}
|
}
|
||||||
public static Span<T>ConvertDataArrayRaw<T>(byte[] data, int offset, int count) where T : struct
|
public static Span<T> ConvertDataArrayRaw<T>(byte[] data, int offset, int count) where T : struct
|
||||||
{
|
{
|
||||||
return MemoryMarshal.Cast<byte, T>(data.AsSpan(offset, count * Marshal.SizeOf(typeof(T))));
|
T[] items = new T[count];
|
||||||
|
int itemsize = Marshal.SizeOf(typeof(T));
|
||||||
|
//for (int i = 0; i < count; i++)
|
||||||
|
//{
|
||||||
|
// int off = offset + i * itemsize;
|
||||||
|
// items[i] = ConvertDataRaw<T>(data, off);
|
||||||
|
//}
|
||||||
|
|
||||||
//GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
GCHandle handle = GCHandle.Alloc(items, GCHandleType.Pinned);
|
||||||
//var h = handle.AddrOfPinnedObject();
|
var h = handle.AddrOfPinnedObject();
|
||||||
//Marshal.Copy(data, offset, h, itemsize * count);
|
Marshal.Copy(data, offset, h, itemsize * count);
|
||||||
//handle.Free();
|
handle.Free();
|
||||||
|
|
||||||
//return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -108,8 +108,8 @@ namespace CodeWalker.GameFiles
|
|||||||
if (descriptorIndex == descriptors.Count) // new descriptor + data
|
if (descriptorIndex == descriptors.Count) // new descriptor + data
|
||||||
{
|
{
|
||||||
var nameLength = reader.ReadInt16();
|
var nameLength = reader.ReadInt16();
|
||||||
var nameBytes = reader.ReadBytes(nameLength);
|
var name = reader.ReadStringLength(nameLength);
|
||||||
var name = Encoding.ASCII.GetString(nameBytes);
|
//var name = Encoding.ASCII.GetString(nameBytes);
|
||||||
|
|
||||||
var descriptor = new RbfEntryDescription();
|
var descriptor = new RbfEntryDescription();
|
||||||
descriptor.Name = name;
|
descriptor.Name = name;
|
||||||
@ -203,8 +203,7 @@ namespace CodeWalker.GameFiles
|
|||||||
case 0x60:
|
case 0x60:
|
||||||
{
|
{
|
||||||
var valueLength = reader.ReadInt16();
|
var valueLength = reader.ReadInt16();
|
||||||
var valueBytes = reader.ReadBytes(valueLength);
|
var value = reader.ReadStringLength(valueLength);
|
||||||
var value = Encoding.ASCII.GetString(valueBytes);
|
|
||||||
var stringValue = new RbfString();
|
var stringValue = new RbfString();
|
||||||
stringValue.Name = descriptor.Name;
|
stringValue.Name = descriptor.Name;
|
||||||
stringValue.Value = value;
|
stringValue.Value = value;
|
||||||
|
@ -5044,8 +5044,8 @@ namespace CodeWalker.GameFiles
|
|||||||
var line = lines[i];
|
var line = lines[i];
|
||||||
|
|
||||||
if (line[0] == '#') continue;
|
if (line[0] == '#') continue;
|
||||||
if (line.StartsWith(startLine)) continue;
|
if (line.StartsWith(startLine, StringComparison.OrdinalIgnoreCase)) continue;
|
||||||
if (line.StartsWith(endLine)) break;
|
if (line.StartsWith(endLine, StringComparison.OrdinalIgnoreCase)) break;
|
||||||
|
|
||||||
string[] parts = line.Split(new[] { '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
string[] parts = line.Split(new[] { '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
@ -4719,6 +4719,8 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableBase : ResourceFileBase
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class DrawableBase : ResourceFileBase
|
||||||
{
|
{
|
||||||
|
private DrawableModel[] allModels;
|
||||||
|
|
||||||
public override long BlockLength
|
public override long BlockLength
|
||||||
{
|
{
|
||||||
get { return 168; }
|
get { return 168; }
|
||||||
@ -4800,7 +4802,17 @@ namespace CodeWalker.GameFiles
|
|||||||
public DrawableModelsBlock DrawableModels { get; set; }
|
public DrawableModelsBlock DrawableModels { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public DrawableModel[] AllModels { get; set; }
|
public DrawableModel[] AllModels {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (allModels is null)
|
||||||
|
{
|
||||||
|
BuildAllModels();
|
||||||
|
}
|
||||||
|
return allModels;
|
||||||
|
}
|
||||||
|
set => allModels = value;
|
||||||
|
}
|
||||||
public Dictionary<ulong, VertexDeclaration> VertexDecls { get; set; }
|
public Dictionary<ulong, VertexDeclaration> VertexDecls { get; set; }
|
||||||
|
|
||||||
public object Owner { get; set; }
|
public object Owner { get; set; }
|
||||||
@ -4867,7 +4879,7 @@ namespace CodeWalker.GameFiles
|
|||||||
this.DrawableModels = reader.ReadBlockAt<DrawableModelsBlock>((DrawableModelsPointer == 0) ? DrawableModelsHighPointer : DrawableModelsPointer, this);
|
this.DrawableModels = reader.ReadBlockAt<DrawableModelsBlock>((DrawableModelsPointer == 0) ? DrawableModelsHighPointer : DrawableModelsPointer, this);
|
||||||
|
|
||||||
|
|
||||||
BuildAllModels();
|
//BuildAllModels();
|
||||||
BuildVertexDecls();
|
BuildVertexDecls();
|
||||||
AssignGeometryShaders(ShaderGroup);
|
AssignGeometryShaders(ShaderGroup);
|
||||||
|
|
||||||
@ -5185,7 +5197,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
|
|
||||||
BuildRenderMasks();
|
BuildRenderMasks();
|
||||||
BuildAllModels();
|
//BuildAllModels();
|
||||||
BuildVertexDecls();
|
BuildVertexDecls();
|
||||||
|
|
||||||
FileVFT = 1079456120;
|
FileVFT = 1079456120;
|
||||||
@ -5236,13 +5248,54 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public void BuildAllModels()
|
public void BuildAllModels()
|
||||||
{
|
{
|
||||||
var allModels = new List<DrawableModel>();
|
if (DrawableModels is null)
|
||||||
if (DrawableModels?.High != null) allModels.AddRange(DrawableModels.High);
|
{
|
||||||
if (DrawableModels?.Med != null) allModels.AddRange(DrawableModels.Med);
|
allModels = Array.Empty<DrawableModel>();
|
||||||
if (DrawableModels?.Low != null) allModels.AddRange(DrawableModels.Low);
|
return;
|
||||||
if (DrawableModels?.VLow != null) allModels.AddRange(DrawableModels.VLow);
|
}
|
||||||
if (DrawableModels?.Extra != null) allModels.AddRange(DrawableModels.Extra);
|
var length = (DrawableModels.High?.Length ?? 0) + (DrawableModels.Med?.Length ?? 0) + (DrawableModels.Low?.Length ?? 0) + (DrawableModels.VLow?.Length ?? 0);
|
||||||
AllModels = allModels.ToArray();
|
allModels = new DrawableModel[length];
|
||||||
|
var currIndex = 0;
|
||||||
|
if (DrawableModels.High != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DrawableModels.High.Length; i++)
|
||||||
|
{
|
||||||
|
allModels[currIndex] = DrawableModels.High[i];
|
||||||
|
currIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DrawableModels.Med != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DrawableModels.Med.Length; i++)
|
||||||
|
{
|
||||||
|
allModels[currIndex] = DrawableModels.Med[i];
|
||||||
|
currIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DrawableModels.Low != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DrawableModels.Low.Length; i++)
|
||||||
|
{
|
||||||
|
allModels[currIndex] = DrawableModels.Low[i];
|
||||||
|
currIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DrawableModels.VLow != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DrawableModels.VLow.Length; i++)
|
||||||
|
{
|
||||||
|
allModels[currIndex] = DrawableModels.VLow[i];
|
||||||
|
currIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (DrawableModels.Extra != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < DrawableModels.Extra.Length; i++)
|
||||||
|
{
|
||||||
|
allModels[currIndex] = DrawableModels.Extra[i];
|
||||||
|
currIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BuildVertexDecls()
|
public void BuildVertexDecls()
|
||||||
|
@ -1346,7 +1346,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (ItemDataByteLength != 0)//sometimes this is 0 and UnkUshort3>0, which is weird
|
if (ItemDataByteLength != 0)//sometimes this is 0 and UnkUshort3>0, which is weird
|
||||||
{
|
{
|
||||||
ShatterMapRowOffsets = reader.ReadStructs<ushort>(ItemDataCount);//byte offsets for following array
|
ShatterMapRowOffsets = reader.ReadStructs<ushort>(ItemDataCount).ToArray();//byte offsets for following array
|
||||||
ShatterMap = new WindowShatterMapRow[ItemDataCount];
|
ShatterMap = new WindowShatterMapRow[ItemDataCount];
|
||||||
for (int i = 0; i < ItemDataCount; i++)
|
for (int i = 0; i < ItemDataCount; i++)
|
||||||
{
|
{
|
||||||
@ -1942,7 +1942,13 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public void BuildOffsets()
|
public void BuildOffsets()
|
||||||
{
|
{
|
||||||
var offs = new List<WindowOffset>();
|
if (Windows == null)
|
||||||
|
{
|
||||||
|
TotalLength = 16u;
|
||||||
|
WindowOffsets = Array.Empty<WindowOffset>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var offs = new List<WindowOffset>(Windows.Length);
|
||||||
var bc = 16u;
|
var bc = 16u;
|
||||||
if (Windows != null)
|
if (Windows != null)
|
||||||
{
|
{
|
||||||
|
@ -3711,14 +3711,17 @@ namespace CodeWalker.GameFiles
|
|||||||
public ParticleKeyframePropName(uint h) { Hash = h; }
|
public ParticleKeyframePropName(uint h) { Hash = h; }
|
||||||
public ParticleKeyframePropName(string str)
|
public ParticleKeyframePropName(string str)
|
||||||
{
|
{
|
||||||
var strl = str?.ToLowerInvariant() ?? "";
|
if (string.IsNullOrEmpty(str))
|
||||||
if (strl.StartsWith("hash_"))
|
|
||||||
{
|
{
|
||||||
Hash = Convert.ToUInt32(strl.Substring(5), 16);
|
Hash = 0;
|
||||||
|
}
|
||||||
|
else if (str.StartsWith("hash_", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Hash = Convert.ToUInt32(str.Substring(5), 16);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Hash = JenkHash.GenHash(strl);
|
Hash = JenkHash.GenHashLower(str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,11 +761,15 @@ namespace CodeWalker.GameFiles
|
|||||||
//TODO: NEEDS TO BE TESTED!!!
|
//TODO: NEEDS TO BE TESTED!!!
|
||||||
data_items = new T[EntriesCount];
|
data_items = new T[EntriesCount];
|
||||||
var posbckp = reader.Position;
|
var posbckp = reader.Position;
|
||||||
|
if (EntriesCount > 0)
|
||||||
|
{
|
||||||
reader.Position = (long)EntriesPointer;
|
reader.Position = (long)EntriesPointer;
|
||||||
for (int i = 0; i < EntriesCount; i++)
|
for (int i = 0; i < EntriesCount; i++)
|
||||||
{
|
{
|
||||||
data_items[i] = reader.ReadBlock<T>();
|
data_items[i] = reader.ReadBlock<T>();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
reader.Position = posbckp;
|
reader.Position = posbckp;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using CodeWalker.Core.Utils;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
@ -470,7 +471,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
|
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
|
||||||
MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream("Decompress", data.Length);
|
MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream("Decompress", data.Length);
|
||||||
ds.CopyTo(outstr);
|
ds.CopyToFast(outstr);
|
||||||
return outstr.ToArray();
|
return outstr.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,9 @@
|
|||||||
//shamelessly stolen and mangled
|
//shamelessly stolen and mangled
|
||||||
|
|
||||||
|
|
||||||
|
using CodeWalker.Utils;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -34,7 +36,6 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a resource data reader.
|
/// Represents a resource data reader.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -53,8 +54,23 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
// this is a dictionary that contains all the resource blocks
|
// this is a dictionary that contains all the resource blocks
|
||||||
// which were read from this resource reader
|
// which were read from this resource reader
|
||||||
public Dictionary<long, IResourceBlock> blockPool = new Dictionary<long, IResourceBlock>();
|
public Dictionary<long, IResourceBlock> blockPool
|
||||||
public Dictionary<long, object> arrayPool = new Dictionary<long, object>();
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _blockPool ??= new Dictionary<long, IResourceBlock>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Dictionary<long, object> arrayPool {
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _arrayPool ??= new Dictionary<long, object>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<long, object> _arrayPool;
|
||||||
|
private Dictionary<long, IResourceBlock> _blockPool;
|
||||||
|
private long position = SYSTEM_BASE;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the length of the underlying stream.
|
/// Gets the length of the underlying stream.
|
||||||
@ -72,10 +88,22 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override long Position
|
public override long Position
|
||||||
{
|
{
|
||||||
get;
|
get => position;
|
||||||
set;
|
set {
|
||||||
} = SYSTEM_BASE;
|
if ((value & SYSTEM_BASE) == SYSTEM_BASE)
|
||||||
|
{
|
||||||
|
systemStream.Position = value & ~SYSTEM_BASE;
|
||||||
|
}
|
||||||
|
else if ((value & GRAPHICS_BASE) == GRAPHICS_BASE)
|
||||||
|
{
|
||||||
|
graphicsStream.Position = value & ~GRAPHICS_BASE;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid position {position}");
|
||||||
|
}
|
||||||
|
position = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new resource data reader for the specified system- and graphics-stream.
|
/// Initializes a new resource data reader for the specified system- and graphics-stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -108,93 +136,55 @@ namespace CodeWalker.GameFiles
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
this.systemStream = new MemoryStream(data, 0, (int)systemSize);
|
if ((int)systemSize > data.Length)
|
||||||
this.graphicsStream = new MemoryStream(data, (int)systemSize, (int)graphicsSize);
|
{
|
||||||
|
throw new ArgumentException($"systemSize {systemSize} is larger than data length ({data.Length})", nameof(systemSize));
|
||||||
|
}
|
||||||
|
if ((int)graphicsSize > data.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"graphicsSize {graphicsSize} is larger than data length ({data.Length})", nameof(graphicsSize));
|
||||||
|
}
|
||||||
|
this.systemStream = Stream.Synchronized(new MemoryStream(data, 0, (int)systemSize));
|
||||||
|
this.graphicsStream = Stream.Synchronized(new MemoryStream(data, (int)systemSize, (int)graphicsSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResourceDataReader(int systemSize, int graphicsSize, byte[] data, Endianess endianess = Endianess.LittleEndian)
|
public ResourceDataReader(int systemSize, int graphicsSize, byte[] data, Endianess endianess = Endianess.LittleEndian)
|
||||||
: base((Stream)null, endianess)
|
: base((Stream)null, endianess)
|
||||||
{
|
{
|
||||||
this.systemStream = new MemoryStream(data, 0, systemSize);
|
this.systemStream = Stream.Synchronized(new MemoryStream(data, 0, systemSize));
|
||||||
this.graphicsStream = new MemoryStream(data, systemSize, graphicsSize);
|
this.graphicsStream = Stream.Synchronized(new MemoryStream(data, systemSize, graphicsSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public override Stream GetStream()
|
||||||
/// Reads data from the underlying stream. This is the only method that directly accesses
|
|
||||||
/// the data in the underlying stream.
|
|
||||||
/// </summary>
|
|
||||||
protected override byte[] ReadFromStream(int count, bool ignoreEndianess = false, byte[] buffer = null)
|
|
||||||
{
|
{
|
||||||
if ((Position & SYSTEM_BASE) == SYSTEM_BASE)
|
if ((Position & SYSTEM_BASE) == SYSTEM_BASE)
|
||||||
{
|
{
|
||||||
// read from system stream...
|
return systemStream;
|
||||||
|
|
||||||
systemStream.Position = Position & ~SYSTEM_BASE;
|
|
||||||
|
|
||||||
buffer ??= new byte[count];
|
|
||||||
systemStream.Read(buffer, 0, count);
|
|
||||||
|
|
||||||
// handle endianess
|
|
||||||
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
|
||||||
{
|
|
||||||
Array.Reverse(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
Position = systemStream.Position | SYSTEM_BASE;
|
|
||||||
return buffer;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else if ((Position & GRAPHICS_BASE) == GRAPHICS_BASE)
|
else if ((Position & GRAPHICS_BASE) == GRAPHICS_BASE)
|
||||||
{
|
{
|
||||||
// read from graphic stream...
|
return graphicsStream;
|
||||||
|
|
||||||
graphicsStream.Position = Position & ~GRAPHICS_BASE;
|
|
||||||
|
|
||||||
buffer ??= new byte[count];
|
|
||||||
graphicsStream.Read(buffer, 0, count);
|
|
||||||
|
|
||||||
// handle endianess
|
|
||||||
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
|
||||||
{
|
|
||||||
Array.Reverse(buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Position = graphicsStream.Position | GRAPHICS_BASE;
|
throw new InvalidOperationException("illegal position!");
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
throw new Exception("illegal position!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override byte ReadByte()
|
internal override void SetPositionAfterRead(Stream stream)
|
||||||
{
|
|
||||||
if ((Position & SYSTEM_BASE) == SYSTEM_BASE)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (stream == systemStream)
|
||||||
|
|
||||||
|
|
||||||
// read from system stream...
|
|
||||||
|
|
||||||
systemStream.Position = Position & ~SYSTEM_BASE;
|
|
||||||
|
|
||||||
var readByte = (byte)systemStream.ReadByte();
|
|
||||||
|
|
||||||
Position = systemStream.Position | SYSTEM_BASE;
|
|
||||||
return readByte;
|
|
||||||
|
|
||||||
}
|
|
||||||
if ((Position & GRAPHICS_BASE) == GRAPHICS_BASE)
|
|
||||||
{
|
{
|
||||||
// read from graphic stream...
|
position = systemStream.Position | SYSTEM_BASE;
|
||||||
|
}
|
||||||
graphicsStream.Position = Position & ~GRAPHICS_BASE;
|
else if (stream == graphicsStream)
|
||||||
|
{
|
||||||
var readByte = (byte)graphicsStream.ReadByte();
|
position = graphicsStream.Position | GRAPHICS_BASE;
|
||||||
|
}
|
||||||
Position = graphicsStream.Position | GRAPHICS_BASE;
|
|
||||||
return readByte;
|
if ((position & SYSTEM_BASE) != SYSTEM_BASE && (position & GRAPHICS_BASE) != GRAPHICS_BASE)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid position {position}");
|
||||||
}
|
}
|
||||||
throw new Exception("illegal position!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -233,7 +223,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (result == null)
|
if (result == null)
|
||||||
{
|
{
|
||||||
return default(T);
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usepool)
|
if (usepool)
|
||||||
@ -279,14 +269,14 @@ namespace CodeWalker.GameFiles
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal const int StackallocThreshold = 512;
|
||||||
public byte[] ReadBytesAt(ulong position, uint count, bool cache = true)
|
public unsafe byte[] ReadBytesAt(ulong position, uint count, bool cache = true, byte[] buffer = null)
|
||||||
{
|
{
|
||||||
long pos = (long)position;
|
long pos = (long)position;
|
||||||
if ((pos <= 0) || (count == 0)) return null;
|
if ((pos <= 0) || (count == 0)) return null;
|
||||||
var posbackup = Position;
|
var posbackup = Position;
|
||||||
Position = pos;
|
Position = pos;
|
||||||
var result = ReadBytes((int)count);
|
var result = ReadBytes((int)count, buffer);
|
||||||
Position = posbackup;
|
Position = posbackup;
|
||||||
if (cache) arrayPool[(long)position] = result;
|
if (cache) arrayPool[(long)position] = result;
|
||||||
return result;
|
return result;
|
||||||
@ -296,9 +286,18 @@ namespace CodeWalker.GameFiles
|
|||||||
if ((position <= 0) || (count == 0)) return null;
|
if ((position <= 0) || (count == 0)) return null;
|
||||||
|
|
||||||
var result = new ushort[count];
|
var result = new ushort[count];
|
||||||
var length = count * 2;
|
var length = count * sizeof(ushort);
|
||||||
byte[] data = ReadBytesAt(position, length, false);
|
var data = ArrayPool<byte>.Shared.Rent((int)length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ReadBytesAt(position, length, false, data);
|
||||||
Buffer.BlockCopy(data, 0, result, 0, (int)length);
|
Buffer.BlockCopy(data, 0, result, 0, (int)length);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//var posbackup = Position;
|
//var posbackup = Position;
|
||||||
//Position = position;
|
//Position = position;
|
||||||
@ -317,9 +316,18 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
if ((position <= 0) || (count == 0)) return null;
|
if ((position <= 0) || (count == 0)) return null;
|
||||||
var result = new short[count];
|
var result = new short[count];
|
||||||
var length = count * 2;
|
var length = count * sizeof(short);
|
||||||
byte[] data = ReadBytesAt(position, length, false);
|
var buffer = ArrayPool<byte>.Shared.Rent((int)length);
|
||||||
Buffer.BlockCopy(data, 0, result, 0, (int)length);
|
try
|
||||||
|
{
|
||||||
|
ReadBytesAt(position, length, false, buffer);
|
||||||
|
Buffer.BlockCopy(buffer, 0, result, 0, (int)length);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (cache) arrayPool[(long)position] = result;
|
if (cache) arrayPool[(long)position] = result;
|
||||||
|
|
||||||
@ -330,18 +338,17 @@ namespace CodeWalker.GameFiles
|
|||||||
if ((position <= 0) || (count == 0)) return null;
|
if ((position <= 0) || (count == 0)) return null;
|
||||||
|
|
||||||
var result = new uint[count];
|
var result = new uint[count];
|
||||||
var length = count * 4;
|
var length = count * sizeof(uint);
|
||||||
byte[] data = ReadBytesAt(position, length, false);
|
var buffer = ArrayPool<byte>.Shared.Rent((int)length);
|
||||||
Buffer.BlockCopy(data, 0, result, 0, (int)length);
|
try
|
||||||
|
{
|
||||||
|
ReadBytesAt(position, length, false, buffer);
|
||||||
|
Buffer.BlockCopy(buffer, 0, result, 0, (int)length);
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
//var posbackup = Position;
|
|
||||||
//Position = position;
|
|
||||||
//var result = new uint[count];
|
|
||||||
//for (uint i = 0; i < count; i++)
|
|
||||||
//{
|
|
||||||
// result[i] = ReadUInt32();
|
|
||||||
//}
|
|
||||||
//Position = posbackup;
|
|
||||||
|
|
||||||
if (cache) arrayPool[(long)position] = result;
|
if (cache) arrayPool[(long)position] = result;
|
||||||
|
|
||||||
@ -352,18 +359,17 @@ namespace CodeWalker.GameFiles
|
|||||||
if ((position <= 0) || (count == 0)) return null;
|
if ((position <= 0) || (count == 0)) return null;
|
||||||
|
|
||||||
var result = new ulong[count];
|
var result = new ulong[count];
|
||||||
var length = count * 8;
|
var length = count * sizeof(ulong);
|
||||||
byte[] data = ReadBytesAt(position, length, false);
|
var data = ArrayPool<byte>.Shared.Rent((int)length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ReadBytesAt(position, length, false, data);
|
||||||
Buffer.BlockCopy(data, 0, result, 0, (int)length);
|
Buffer.BlockCopy(data, 0, result, 0, (int)length);
|
||||||
|
}
|
||||||
//var posbackup = Position;
|
finally
|
||||||
//Position = position;
|
{
|
||||||
//var result = new ulong[count];
|
ArrayPool<byte>.Shared.Return(data);
|
||||||
//for (uint i = 0; i < count; i++)
|
}
|
||||||
//{
|
|
||||||
// result[i] = ReadUInt64();
|
|
||||||
//}
|
|
||||||
//Position = posbackup;
|
|
||||||
|
|
||||||
if (cache) arrayPool[(long)position] = result;
|
if (cache) arrayPool[(long)position] = result;
|
||||||
|
|
||||||
@ -374,88 +380,85 @@ namespace CodeWalker.GameFiles
|
|||||||
if ((position <= 0) || (count == 0)) return null;
|
if ((position <= 0) || (count == 0)) return null;
|
||||||
|
|
||||||
var result = new float[count];
|
var result = new float[count];
|
||||||
var length = count * 4;
|
var length = count * sizeof(float);
|
||||||
byte[] data = ReadBytesAt(position, length, false);
|
var data = ArrayPool<byte>.Shared.Rent((int)length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ReadBytesAt(position, length, false, data);
|
||||||
Buffer.BlockCopy(data, 0, result, 0, (int)length);
|
Buffer.BlockCopy(data, 0, result, 0, (int)length);
|
||||||
|
}
|
||||||
//var posbackup = Position;
|
finally
|
||||||
//Position = position;
|
{
|
||||||
//var result = new float[count];
|
ArrayPool<byte>.Shared.Return(data);
|
||||||
//for (uint i = 0; i < count; i++)
|
}
|
||||||
//{
|
|
||||||
// result[i] = ReadSingle();
|
|
||||||
//}
|
|
||||||
//Position = posbackup;
|
|
||||||
|
|
||||||
if (cache) arrayPool[(long)position] = result;
|
if (cache) arrayPool[(long)position] = result;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public T[] ReadStructsAt<T>(ulong position, uint count, bool cache = true)
|
public T[] ReadStructsAt<T>(ulong position, uint count, bool cache = true) where T : struct
|
||||||
{
|
{
|
||||||
if ((position <= 0) || (count == 0)) return null;
|
if ((position <= 0) || (count == 0)) return null;
|
||||||
|
|
||||||
uint structsize = (uint)Marshal.SizeOf(typeof(T));
|
uint structsize = (uint)Marshal.SizeOf(typeof(T));
|
||||||
var length = count * structsize;
|
var length = count * structsize;
|
||||||
byte[] data = ReadBytesAt(position, length, false);
|
var data = ArrayPool<byte>.Shared.Rent((int)length);
|
||||||
|
try
|
||||||
//var result2 = new T[count];
|
{
|
||||||
//Buffer.BlockCopy(data, 0, result2, 0, (int)length); //error: "object must be an array of primitives" :(
|
ReadBytesAt(position, length, false, data);
|
||||||
|
|
||||||
//var result = new T[count];
|
|
||||||
//GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
|
||||||
//var h = handle.AddrOfPinnedObject();
|
|
||||||
//for (uint i = 0; i < count; i++)
|
|
||||||
//{
|
|
||||||
// result[i] = Marshal.PtrToStructure<T>(h + (int)(i * structsize));
|
|
||||||
//}
|
|
||||||
//handle.Free();
|
|
||||||
|
|
||||||
var result = new T[count];
|
var result = new T[count];
|
||||||
GCHandle handle = GCHandle.Alloc(result, GCHandleType.Pinned);
|
|
||||||
var h = handle.AddrOfPinnedObject();
|
|
||||||
Marshal.Copy(data, 0, h, (int)length);
|
|
||||||
handle.Free();
|
|
||||||
|
|
||||||
|
var resultSpan = MemoryMarshal.Cast<byte, T>(data.AsSpan(0, (int)length));
|
||||||
|
resultSpan.CopyTo(result);
|
||||||
|
|
||||||
if (cache) arrayPool[(long)position] = result;
|
if (cache) arrayPool[(long)position] = result;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public T[] ReadStructs<T>(uint count)
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public T[] ReadStructs<T>(uint count) where T : struct
|
||||||
{
|
{
|
||||||
uint structsize = (uint)Marshal.SizeOf(typeof(T));
|
uint structsize = (uint)Marshal.SizeOf(typeof(T));
|
||||||
var result = new T[count];
|
var result = new T[count];
|
||||||
var length = count * structsize;
|
var length = count * structsize;
|
||||||
byte[] data = ReadBytes((int)length);
|
var data = ArrayPool<byte>.Shared.Rent((int)length);
|
||||||
|
try
|
||||||
//GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
{
|
||||||
//var h = handle.AddrOfPinnedObject();
|
ReadBytes((int)length, data);
|
||||||
//for (uint i = 0; i < count; i++)
|
|
||||||
//{
|
|
||||||
// result[i] = Marshal.PtrToStructure<T>(h + (int)(i * structsize));
|
|
||||||
//}
|
|
||||||
//handle.Free();
|
|
||||||
|
|
||||||
GCHandle handle = GCHandle.Alloc(result, GCHandleType.Pinned);
|
|
||||||
var h = handle.AddrOfPinnedObject();
|
|
||||||
Marshal.Copy(data, 0, h, (int)length);
|
|
||||||
handle.Free();
|
|
||||||
|
|
||||||
|
var resultSpan = MemoryMarshal.Cast<byte, T>(data.AsSpan(0, (int)length));
|
||||||
|
resultSpan.CopyTo(result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public T ReadStruct<T>() where T : struct
|
public T ReadStruct<T>() where T : struct
|
||||||
{
|
{
|
||||||
uint structsize = (uint)Marshal.SizeOf(typeof(T));
|
uint structsize = (uint)Marshal.SizeOf(typeof(T));
|
||||||
var length = structsize;
|
var length = structsize;
|
||||||
byte[] data = ReadBytes((int)length);
|
var data = ArrayPool<byte>.Shared.Rent((int)length);
|
||||||
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
try
|
||||||
var h = handle.AddrOfPinnedObject();
|
{
|
||||||
var result = Marshal.PtrToStructure<T>(h);
|
ReadBytes((int)length, data);
|
||||||
handle.Free();
|
MemoryMarshal.TryRead<T>(data, out var value);
|
||||||
return result;
|
|
||||||
|
return value;
|
||||||
|
} finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(data);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T ReadStructAt<T>(long position) where T : struct
|
public T ReadStructAt<T>(long position) where T : struct
|
||||||
@ -513,13 +516,22 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private long position = SYSTEM_BASE;
|
||||||
/// Gets or sets the position within the underlying stream.
|
|
||||||
/// </summary>
|
|
||||||
public override long Position
|
public override long Position
|
||||||
{
|
{
|
||||||
get;
|
get => position;
|
||||||
set;
|
set
|
||||||
|
{
|
||||||
|
if ((value & SYSTEM_BASE) == SYSTEM_BASE)
|
||||||
|
{
|
||||||
|
systemStream.Position = value & ~SYSTEM_BASE;
|
||||||
|
}
|
||||||
|
else if ((value & GRAPHICS_BASE) == GRAPHICS_BASE)
|
||||||
|
{
|
||||||
|
graphicsStream.Position = value & ~GRAPHICS_BASE;
|
||||||
|
}
|
||||||
|
position = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -528,61 +540,33 @@ namespace CodeWalker.GameFiles
|
|||||||
public ResourceDataWriter(Stream systemStream, Stream graphicsStream, Endianess endianess = Endianess.LittleEndian)
|
public ResourceDataWriter(Stream systemStream, Stream graphicsStream, Endianess endianess = Endianess.LittleEndian)
|
||||||
: base((Stream)null, endianess)
|
: base((Stream)null, endianess)
|
||||||
{
|
{
|
||||||
this.systemStream = systemStream;
|
this.systemStream = Stream.Synchronized(systemStream);
|
||||||
this.graphicsStream = graphicsStream;
|
this.graphicsStream = Stream.Synchronized(graphicsStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
internal override Stream GetStream()
|
||||||
/// Writes data to the underlying stream. This is the only method that directly accesses
|
|
||||||
/// the data in the underlying stream.
|
|
||||||
/// </summary>
|
|
||||||
protected override void WriteToStream(byte[] value, bool ignoreEndianess = true)
|
|
||||||
{
|
{
|
||||||
if ((Position & SYSTEM_BASE) == SYSTEM_BASE)
|
if ((Position & SYSTEM_BASE) == SYSTEM_BASE)
|
||||||
{
|
{
|
||||||
// write to system stream...
|
return systemStream;
|
||||||
|
}
|
||||||
systemStream.Position = Position & ~SYSTEM_BASE;
|
else if ((Position & GRAPHICS_BASE) == GRAPHICS_BASE)
|
||||||
|
|
||||||
// handle endianess
|
|
||||||
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
|
||||||
{
|
{
|
||||||
var buf = (byte[])value.Clone();
|
return graphicsStream;
|
||||||
Array.Reverse(buf);
|
|
||||||
systemStream.Write(buf, 0, buf.Length);
|
|
||||||
}
|
}
|
||||||
else
|
throw new InvalidOperationException("illegal position!");
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override void SetPositionAfterWrite(Stream stream)
|
||||||
{
|
{
|
||||||
systemStream.Write(value, 0, value.Length);
|
if (stream == systemStream)
|
||||||
}
|
|
||||||
|
|
||||||
Position = systemStream.Position | 0x50000000;
|
|
||||||
return;
|
|
||||||
|
|
||||||
}
|
|
||||||
if ((Position & GRAPHICS_BASE) == GRAPHICS_BASE)
|
|
||||||
{
|
{
|
||||||
// write to graphic stream...
|
position = systemStream.Position | SYSTEM_BASE;
|
||||||
|
}
|
||||||
graphicsStream.Position = Position & ~GRAPHICS_BASE;
|
else if (stream == graphicsStream)
|
||||||
|
|
||||||
// handle endianess
|
|
||||||
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
|
||||||
{
|
{
|
||||||
var buf = (byte[])value.Clone();
|
position = graphicsStream.Position | GRAPHICS_BASE;
|
||||||
Array.Reverse(buf);
|
|
||||||
graphicsStream.Write(buf, 0, buf.Length);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
graphicsStream.Write(value, 0, value.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
Position = graphicsStream.Position | 0x60000000;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception("illegal position!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -599,20 +583,41 @@ namespace CodeWalker.GameFiles
|
|||||||
public void WriteStruct<T>(T val) where T : struct
|
public void WriteStruct<T>(T val) where T : struct
|
||||||
{
|
{
|
||||||
int size = Marshal.SizeOf(typeof(T));
|
int size = Marshal.SizeOf(typeof(T));
|
||||||
byte[] arr = new byte[size];
|
|
||||||
IntPtr ptr = Marshal.AllocHGlobal(size);
|
var arr = new byte[size];
|
||||||
Marshal.StructureToPtr(val, ptr, true);
|
|
||||||
Marshal.Copy(ptr, arr, 0, size);
|
MemoryMarshal.TryWrite(arr, ref val);
|
||||||
Marshal.FreeHGlobal(ptr);
|
|
||||||
Write(arr);
|
Write(arr);
|
||||||
|
|
||||||
|
//byte[] arr = new byte[size];
|
||||||
|
//IntPtr ptr = Marshal.AllocHGlobal(size);
|
||||||
|
//Marshal.StructureToPtr(val, ptr, true);
|
||||||
|
//Marshal.Copy(ptr, arr, 0, size);
|
||||||
|
//Marshal.FreeHGlobal(ptr);
|
||||||
|
//Write(arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteStructs<T>(Span<T> val) where T : struct
|
||||||
|
{
|
||||||
|
if (val == null) return;
|
||||||
|
|
||||||
|
var bytes = MemoryMarshal.AsBytes(val);
|
||||||
|
|
||||||
|
Write(bytes);
|
||||||
|
|
||||||
|
//foreach (var v in val)
|
||||||
|
//{
|
||||||
|
// WriteStruct(v);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
public void WriteStructs<T>(T[] val) where T : struct
|
public void WriteStructs<T>(T[] val) where T : struct
|
||||||
{
|
{
|
||||||
if (val == null) return;
|
if (val == null) return;
|
||||||
foreach (var v in val)
|
var bytes = MemoryMarshal.AsBytes<T>(val);
|
||||||
{
|
|
||||||
WriteStruct(v);
|
Write(bytes);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -636,8 +636,8 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public override void Read(ResourceDataReader reader, params object[] parameters)
|
public override void Read(ResourceDataReader reader, params object[] parameters)
|
||||||
{
|
{
|
||||||
uint format = Convert.ToUInt32(parameters[0]);
|
//uint format = Convert.ToUInt32(parameters[0]);
|
||||||
int Width = Convert.ToInt32(parameters[1]);
|
//int Width = Convert.ToInt32(parameters[1]);
|
||||||
int Height = Convert.ToInt32(parameters[2]);
|
int Height = Convert.ToInt32(parameters[2]);
|
||||||
int Levels = Convert.ToInt32(parameters[3]);
|
int Levels = Convert.ToInt32(parameters[3]);
|
||||||
int Stride = Convert.ToInt32(parameters[4]);
|
int Stride = Convert.ToInt32(parameters[4]);
|
||||||
@ -646,7 +646,7 @@ namespace CodeWalker.GameFiles
|
|||||||
int length = Stride * Height;
|
int length = Stride * Height;
|
||||||
for (int i = 0; i < Levels; i++)
|
for (int i = 0; i < Levels; i++)
|
||||||
{
|
{
|
||||||
fullLength += length;
|
fullLength += Math.Max(length, 4 * 4);
|
||||||
length /= 4;
|
length /= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Microsoft.IO;
|
using CodeWalker.Core.Utils;
|
||||||
|
using Microsoft.IO;
|
||||||
using System;
|
using System;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
@ -20,24 +21,6 @@ namespace CodeWalker.GameFiles
|
|||||||
public class RpfFile
|
public class RpfFile
|
||||||
{
|
{
|
||||||
public string Name { get; set; } //name of this RPF file/package
|
public string Name { get; set; } //name of this RPF file/package
|
||||||
|
|
||||||
|
|
||||||
private string _nameLower;
|
|
||||||
public string NameLower
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_nameLower == null)
|
|
||||||
{
|
|
||||||
_nameLower = Name.ToLowerInvariant();
|
|
||||||
}
|
|
||||||
return _nameLower;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_nameLower = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string Path { get; set; } //path within the RPF structure
|
public string Path { get; set; } //path within the RPF structure
|
||||||
public string FilePath { get; set; } //full file path of the RPF
|
public string FilePath { get; set; } //full file path of the RPF
|
||||||
public long FileSize { get; set; }
|
public long FileSize { get; set; }
|
||||||
@ -80,19 +63,48 @@ namespace CodeWalker.GameFiles
|
|||||||
public uint GrandTotalBinaryFileCount { get; set; }
|
public uint GrandTotalBinaryFileCount { get; set; }
|
||||||
public long ExtractedByteCount { get; set; }
|
public long ExtractedByteCount { get; set; }
|
||||||
|
|
||||||
|
static RpfFile()
|
||||||
|
{
|
||||||
|
recyclableMemoryStreamManager.BufferDiscarded += (sender, args) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Buffer Discarded: BufferType: {args.BufferType}; Reason: {args.Reason};");
|
||||||
|
};
|
||||||
|
|
||||||
|
recyclableMemoryStreamManager.StreamDoubleDisposed += (sender, args) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"StreamDoubleDisposed: Stack1: {args.DisposeStack1}; Stack2: {args.DisposeStack2};");
|
||||||
|
};
|
||||||
|
|
||||||
|
recyclableMemoryStreamManager.StreamOverCapacity += (sender, args) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"StreamOverCapacity: MaximumCapacity is {args.MaximumCapacity / 1024f / 1024f} MB, requisted: {args.RequestedCapacity / 1024f / 1024f:0.##} MB Stack: {args.AllocationStack}");
|
||||||
|
};
|
||||||
|
|
||||||
|
recyclableMemoryStreamManager.StreamFinalized += (sender, args) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"StreamFinalized: {args.AllocationStack}");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public RpfFile(FileInfo fileInfo)
|
||||||
|
{
|
||||||
|
Name = fileInfo.Name;
|
||||||
|
FilePath = fileInfo.FullName;
|
||||||
|
FileSize = fileInfo.Length;
|
||||||
|
}
|
||||||
|
|
||||||
public RpfFile(string fpath, string relpath) //for a ROOT filesystem RPF
|
public RpfFile(string fpath, string relpath) //for a ROOT filesystem RPF
|
||||||
{
|
{
|
||||||
FileInfo fi = new FileInfo(fpath);
|
FileInfo fi = new FileInfo(fpath);
|
||||||
Name = fi.Name;
|
Name = fi.Name;
|
||||||
Path = relpath.ToLowerInvariant();
|
Path = relpath;
|
||||||
FilePath = fpath;
|
FilePath = fpath;
|
||||||
FileSize = fi.Length;
|
FileSize = fi.Length;
|
||||||
}
|
}
|
||||||
public RpfFile(string name, string path, long filesize) //for a child RPF
|
public RpfFile(string name, string path, long filesize) //for a child RPF
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Path = path.ToLowerInvariant();
|
Path = path;
|
||||||
FilePath = path;
|
FilePath = path;
|
||||||
FileSize = filesize;
|
FileSize = filesize;
|
||||||
}
|
}
|
||||||
@ -104,7 +116,7 @@ namespace CodeWalker.GameFiles
|
|||||||
string rel_parent_path = parentFile.Path;
|
string rel_parent_path = parentFile.Path;
|
||||||
string full_parent_path = parentFile.FilePath;
|
string full_parent_path = parentFile.FilePath;
|
||||||
|
|
||||||
if(rel_parent_path.StartsWith(@"mods\"))
|
if(rel_parent_path.StartsWith(@"mods\", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
status = "already in mods folder";
|
status = "already in mods folder";
|
||||||
return null;
|
return null;
|
||||||
@ -132,7 +144,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public bool IsInModsFolder()
|
public bool IsInModsFolder()
|
||||||
{
|
{
|
||||||
return GetTopParent().Path.StartsWith(@"mods\");
|
return GetTopParent().Path.StartsWith(@"mods\", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RpfFile GetTopParent()
|
public RpfFile GetTopParent()
|
||||||
@ -169,11 +181,13 @@ namespace CodeWalker.GameFiles
|
|||||||
throw new Exception("Invalid Resource - not GTAV!");
|
throw new Exception("Invalid Resource - not GTAV!");
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] entriesdata = ArrayPool<byte>.Shared.Rent((int)EntryCount * 16);
|
var entriesLength = (int)EntryCount * 16;
|
||||||
byte[] namesdata = ArrayPool<byte>.Shared.Rent((int)NamesLength);
|
var namesLength = (int)NamesLength;
|
||||||
|
byte[] entriesdata = ArrayPool<byte>.Shared.Rent(entriesLength);
|
||||||
|
byte[] namesdata = ArrayPool<byte>.Shared.Rent(namesLength);
|
||||||
|
|
||||||
br.BaseStream.Read(entriesdata, 0, (int)EntryCount * 16);
|
br.BaseStream.Read(entriesdata, 0, entriesLength);
|
||||||
br.BaseStream.Read(namesdata, 0, (int)NamesLength);
|
br.BaseStream.Read(namesdata, 0, namesLength);
|
||||||
|
|
||||||
switch (Encryption)
|
switch (Encryption)
|
||||||
{
|
{
|
||||||
@ -181,22 +195,22 @@ namespace CodeWalker.GameFiles
|
|||||||
case RpfEncryption.OPEN: //OpenIV style RPF with unencrypted TOC
|
case RpfEncryption.OPEN: //OpenIV style RPF with unencrypted TOC
|
||||||
break;
|
break;
|
||||||
case RpfEncryption.AES:
|
case RpfEncryption.AES:
|
||||||
GTACrypto.DecryptAES(entriesdata, (int)EntryCount * 16);
|
GTACrypto.DecryptAES(entriesdata, entriesLength);
|
||||||
GTACrypto.DecryptAES(namesdata, (int)NamesLength);
|
GTACrypto.DecryptAES(namesdata, namesLength);
|
||||||
|
|
||||||
IsAESEncrypted = true;
|
IsAESEncrypted = true;
|
||||||
break;
|
break;
|
||||||
case RpfEncryption.NG:
|
case RpfEncryption.NG:
|
||||||
default:
|
default:
|
||||||
GTACrypto.DecryptNG(entriesdata, Name, (uint)FileSize, 0, (int)EntryCount * 16);
|
GTACrypto.DecryptNG(entriesdata, Name, (uint)FileSize, 0, entriesLength);
|
||||||
GTACrypto.DecryptNG(namesdata, Name, (uint)FileSize, 0, (int)NamesLength);
|
GTACrypto.DecryptNG(namesdata, Name, (uint)FileSize, 0, namesLength);
|
||||||
|
|
||||||
IsNGEncrypted = true;
|
IsNGEncrypted = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
using var entriesrdr = new DataReader(new MemoryStream(entriesdata, 0, (int)EntryCount * 16));
|
using var entriesrdr = new DataReader(new MemoryStream(entriesdata, 0, entriesLength));
|
||||||
using var namesrdr = new DataReader(new MemoryStream(namesdata, 0, (int)NamesLength));
|
using var namesrdr = new DataReader(new MemoryStream(namesdata, 0, namesLength));
|
||||||
|
|
||||||
|
|
||||||
AllEntries = new List<RpfEntry>((int)EntryCount);
|
AllEntries = new List<RpfEntry>((int)EntryCount);
|
||||||
@ -245,26 +259,19 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
namesrdr.Position = entry.NameOffset;
|
namesrdr.Position = entry.NameOffset;
|
||||||
entry.Name = namesrdr.ReadString(256);
|
entry.Name = namesrdr.ReadString(256);
|
||||||
if (entry.Name.Length > 256)
|
JenkIndex.EnsureLower(entry.Name);
|
||||||
{
|
|
||||||
// long names can freeze the RPFExplorer
|
|
||||||
entry.Name = entry.Name.Substring(0, 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entry is RpfResourceFileEntry rfe)// && string.IsNullOrEmpty(e.Name))
|
if (entry is RpfResourceFileEntry rfe)// && string.IsNullOrEmpty(e.Name))
|
||||||
{
|
{
|
||||||
rfe.IsEncrypted = rfe.Name.EndsWith(".ysc", StringComparison.OrdinalIgnoreCase);//any other way to know..?
|
rfe.IsEncrypted = rfe.IsExtension(".ysc");//any other way to know..?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Root = (RpfDirectoryEntry)AllEntries[0];
|
Root = (RpfDirectoryEntry)AllEntries[0];
|
||||||
Root.Path = Path.ToLowerInvariant();// + "\\" + Root.Name;
|
Root.Path = Path;// + "\\" + Root.Name;
|
||||||
var stack = new Stack<RpfDirectoryEntry>();
|
//var stack = new Stack<RpfDirectoryEntry>();
|
||||||
stack.Push(Root);
|
|
||||||
while (stack.Count > 0)
|
|
||||||
{
|
|
||||||
var item = stack.Pop();
|
|
||||||
|
|
||||||
|
void addSubDirectory(RpfDirectoryEntry item)
|
||||||
|
{
|
||||||
int starti = (int)item.EntriesIndex;
|
int starti = (int)item.EntriesIndex;
|
||||||
int endi = (int)(item.EntriesIndex + item.EntriesCount);
|
int endi = (int)(item.EntriesIndex + item.EntriesCount);
|
||||||
|
|
||||||
@ -274,19 +281,46 @@ namespace CodeWalker.GameFiles
|
|||||||
e.Parent = item;
|
e.Parent = item;
|
||||||
if (e is RpfDirectoryEntry rde)
|
if (e is RpfDirectoryEntry rde)
|
||||||
{
|
{
|
||||||
rde.Path = item.Path + "\\" + rde.Name;
|
rde.Path = item.Path + '\\' + rde.Name;
|
||||||
item.Directories.Add(rde);
|
item.Directories.Add(rde);
|
||||||
stack.Push(rde);
|
addSubDirectory(rde);
|
||||||
}
|
}
|
||||||
else if (e is RpfFileEntry)
|
else if (e is RpfFileEntry rfe)
|
||||||
{
|
{
|
||||||
RpfFileEntry rfe = e as RpfFileEntry;
|
rfe.Path = item.Path + '\\' + rfe.Name;
|
||||||
rfe.Path = item.Path + "\\" + rfe.Name;
|
|
||||||
item.Files.Add(rfe);
|
item.Files.Add(rfe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addSubDirectory(Root);
|
||||||
|
//stack.Push(Root);
|
||||||
|
//while (stack.Count > 0)
|
||||||
|
//{
|
||||||
|
// var item = stack.Pop();
|
||||||
|
|
||||||
|
// int starti = (int)item.EntriesIndex;
|
||||||
|
// int endi = (int)(item.EntriesIndex + item.EntriesCount);
|
||||||
|
|
||||||
|
// for (int i = starti; i < endi; i++)
|
||||||
|
// {
|
||||||
|
// RpfEntry e = AllEntries[i];
|
||||||
|
// e.Parent = item;
|
||||||
|
// if (e is RpfDirectoryEntry rde)
|
||||||
|
// {
|
||||||
|
// rde.Path = item.Path + "\\" + rde.Name;
|
||||||
|
// item.Directories.Add(rde);
|
||||||
|
// stack.Push(rde);
|
||||||
|
// }
|
||||||
|
// else if (e is RpfFileEntry)
|
||||||
|
// {
|
||||||
|
// RpfFileEntry rfe = e as RpfFileEntry;
|
||||||
|
// rfe.Path = item.Path + "\\" + rfe.Name;
|
||||||
|
// item.Files.Add(rfe);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
br.BaseStream.Position = StartPos;
|
br.BaseStream.Position = StartPos;
|
||||||
|
|
||||||
CurrentFileReader = null;
|
CurrentFileReader = null;
|
||||||
@ -294,10 +328,6 @@ namespace CodeWalker.GameFiles
|
|||||||
ArrayPool<byte>.Shared.Return(namesdata);
|
ArrayPool<byte>.Shared.Return(namesdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public bool ScanStructure(Action<string> updateStatus, Action<string> errorLog)
|
public bool ScanStructure(Action<string> updateStatus, Action<string> errorLog)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -343,7 +373,7 @@ namespace CodeWalker.GameFiles
|
|||||||
if (entry is RpfBinaryFileEntry binentry)
|
if (entry is RpfBinaryFileEntry binentry)
|
||||||
{
|
{
|
||||||
//search all the sub resources for YSC files. (recurse!)
|
//search all the sub resources for YSC files. (recurse!)
|
||||||
if (binentry.Name.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase) && binentry.Path.Length < 5000) // a long path is most likely an attempt to crash CW, so skip it
|
if (binentry.IsExtension(".rpf") && binentry.Path.Length < 5000) // a long path is most likely an attempt to crash CW, so skip it
|
||||||
{
|
{
|
||||||
br.BaseStream.Position = StartPos + ((long)binentry.FileOffset * 512);
|
br.BaseStream.Position = StartPos + ((long)binentry.FileOffset * 512);
|
||||||
|
|
||||||
@ -424,8 +454,7 @@ namespace CodeWalker.GameFiles
|
|||||||
long l = binentry.GetFileSize();
|
long l = binentry.GetFileSize();
|
||||||
|
|
||||||
//search all the sub resources for YSC files. (recurse!)
|
//search all the sub resources for YSC files. (recurse!)
|
||||||
string lname = binentry.NameLower;
|
if (binentry.IsExtension(".rpf"))
|
||||||
if (lname.EndsWith(".rpf"))
|
|
||||||
{
|
{
|
||||||
br.BaseStream.Position = StartPos + ((long)binentry.FileOffset * 512);
|
br.BaseStream.Position = StartPos + ((long)binentry.FileOffset * 512);
|
||||||
|
|
||||||
@ -442,9 +471,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
|
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
|
||||||
|
|
||||||
string lname = resentry.NameLower;
|
if (resentry.IsExtension(".ysc"))
|
||||||
|
|
||||||
if (lname.EndsWith(".ysc"))
|
|
||||||
{
|
{
|
||||||
updateStatus?.Invoke("Extracting " + resentry.Name + "...");
|
updateStatus?.Invoke("Extracting " + resentry.Name + "...");
|
||||||
|
|
||||||
@ -483,7 +510,7 @@ namespace CodeWalker.GameFiles
|
|||||||
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
|
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
|
||||||
|
|
||||||
MemoryStream outstr = recyclableMemoryStreamManager.GetStream();
|
MemoryStream outstr = recyclableMemoryStreamManager.GetStream();
|
||||||
ds.CopyTo(outstr);
|
ds.CopyToFast(outstr);
|
||||||
byte[] deflated = outstr.GetBuffer();
|
byte[] deflated = outstr.GetBuffer();
|
||||||
byte[] outbuf = new byte[outstr.Length]; //need to copy to the right size buffer for File.WriteAllBytes().
|
byte[] outbuf = new byte[outstr.Length]; //need to copy to the right size buffer for File.WriteAllBytes().
|
||||||
Array.Copy(deflated, outbuf, outbuf.Length);
|
Array.Copy(deflated, outbuf, outbuf.Length);
|
||||||
@ -556,7 +583,8 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (BinaryReader br = new BinaryReader(File.OpenRead(GetPhysicalFilePath())))
|
using var fileStream = new FileStream(GetPhysicalFilePath(), FileMode.Open, FileAccess.Read, FileShare.Read, 4096);
|
||||||
|
using (BinaryReader br = new BinaryReader(fileStream))
|
||||||
{
|
{
|
||||||
if (entry is RpfBinaryFileEntry binaryFileEntry)
|
if (entry is RpfBinaryFileEntry binaryFileEntry)
|
||||||
{
|
{
|
||||||
@ -579,18 +607,99 @@ namespace CodeWalker.GameFiles
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ValueTask<byte[]> ExtractFileAsync(RpfFileEntry entry)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var fileStream = new FileStream(GetPhysicalFilePath(), FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous);
|
||||||
|
using (BinaryReader br = new BinaryReader(fileStream))
|
||||||
|
{
|
||||||
|
if (entry is RpfBinaryFileEntry binaryFileEntry)
|
||||||
|
{
|
||||||
|
return ExtractFileBinaryAsync(binaryFileEntry, br);
|
||||||
|
}
|
||||||
|
else if (entry is RpfResourceFileEntry resourceFileEntry)
|
||||||
|
{
|
||||||
|
return ExtractFileResourceAsync(resourceFileEntry, br);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"{entry} is not a BinaryFileEntry of ResourceFileEntry");
|
||||||
|
return new ValueTask<byte[]>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LastError = ex.ToString();
|
||||||
|
LastException = ex;
|
||||||
|
return new ValueTask<byte[]>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<byte[]> ExtractFileBinaryAsync(RpfBinaryFileEntry entry, BinaryReader br)
|
||||||
|
{
|
||||||
|
br.BaseStream.Position = StartPos + ((long)entry.FileOffset * 512);
|
||||||
|
|
||||||
|
long l = entry.GetFileSize();
|
||||||
|
|
||||||
|
if (l <= 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint offset = 0;// 0x10;
|
||||||
|
uint totlen = (uint)l - offset;
|
||||||
|
|
||||||
|
byte[] tbytes = ArrayPool<byte>.Shared.Rent((int)totlen);
|
||||||
|
|
||||||
|
br.BaseStream.Position += offset;
|
||||||
|
await br.ReadAsync(tbytes, 0, (int)totlen).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (entry.IsEncrypted)
|
||||||
|
{
|
||||||
|
if (IsAESEncrypted)
|
||||||
|
{
|
||||||
|
GTACrypto.DecryptAES(tbytes, (int)totlen);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] defl;
|
||||||
|
if (entry.FileSize > 0) //apparently this means it's compressed
|
||||||
|
{
|
||||||
|
defl = await DecompressBytesAsync(tbytes).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
defl = new byte[(int)totlen];
|
||||||
|
Array.Copy(tbytes, defl, (int)totlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayPool<byte>.Shared.Return(tbytes);
|
||||||
|
|
||||||
|
return defl;
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] ExtractFileBinary(RpfBinaryFileEntry entry, BinaryReader br)
|
public byte[] ExtractFileBinary(RpfBinaryFileEntry entry, BinaryReader br)
|
||||||
{
|
{
|
||||||
br.BaseStream.Position = StartPos + ((long)entry.FileOffset * 512);
|
br.BaseStream.Position = StartPos + ((long)entry.FileOffset * 512);
|
||||||
|
|
||||||
long l = entry.GetFileSize();
|
long l = entry.GetFileSize();
|
||||||
|
|
||||||
if (l > 0)
|
if (l <= 0)
|
||||||
{
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
uint offset = 0;// 0x10;
|
uint offset = 0;// 0x10;
|
||||||
uint totlen = (uint)l - offset;
|
uint totlen = (uint)l - offset;
|
||||||
|
|
||||||
byte[] tbytes = new byte[totlen];
|
byte[] tbytes = ArrayPool<byte>.Shared.Rent((int)totlen);
|
||||||
|
|
||||||
br.BaseStream.Position += offset;
|
br.BaseStream.Position += offset;
|
||||||
br.Read(tbytes, 0, (int)totlen);
|
br.Read(tbytes, 0, (int)totlen);
|
||||||
@ -599,71 +708,63 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
if (IsAESEncrypted)
|
if (IsAESEncrypted)
|
||||||
{
|
{
|
||||||
GTACrypto.DecryptAES(tbytes);
|
GTACrypto.DecryptAES(tbytes, (int)totlen);
|
||||||
}
|
}
|
||||||
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
||||||
{
|
{
|
||||||
GTACrypto.DecryptNG(tbytes, entry.Name, entry.FileUncompressedSize);
|
GTACrypto.DecryptNG(tbytes, entry.Name, entry.FileUncompressedSize, 0, (int)totlen);
|
||||||
}
|
}
|
||||||
//else
|
|
||||||
//{ }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] defl = tbytes;
|
byte[] defl;
|
||||||
|
|
||||||
if (entry.FileSize > 0) //apparently this means it's compressed
|
if (entry.FileSize > 0) //apparently this means it's compressed
|
||||||
{
|
{
|
||||||
defl = DecompressBytes(tbytes);
|
defl = DecompressBytes(tbytes);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
defl = new byte[(int)totlen];
|
||||||
|
Buffer.BlockCopy(tbytes, 0, defl, 0, (int)totlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayPool<byte>.Shared.Return(tbytes);
|
||||||
|
|
||||||
return defl;
|
return defl;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
public async ValueTask<byte[]> ExtractFileResourceAsync(RpfResourceFileEntry entry, BinaryReader br)
|
||||||
}
|
|
||||||
public byte[] ExtractFileResource(RpfResourceFileEntry entry, BinaryReader br)
|
|
||||||
{
|
{
|
||||||
br.BaseStream.Position = StartPos + ((long)entry.FileOffset * 512);
|
br.BaseStream.Position = StartPos + ((long)entry.FileOffset * 512);
|
||||||
|
|
||||||
|
if (entry.FileSize <= 0)
|
||||||
if (entry.FileSize > 0)
|
|
||||||
{
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
uint offset = 0x10;
|
uint offset = 0x10;
|
||||||
uint totlen = entry.FileSize - offset;
|
uint totlen = entry.FileSize - offset;
|
||||||
|
|
||||||
byte[] tbytes = new byte[totlen];
|
byte[] tbytes = ArrayPool<byte>.Shared.Rent((int)totlen);
|
||||||
|
|
||||||
|
|
||||||
br.BaseStream.Position += offset;
|
br.BaseStream.Position += offset;
|
||||||
//byte[] hbytes = br.ReadBytes(16); //what are these 16 bytes actually used for?
|
|
||||||
//if (entry.FileSize > 0xFFFFFF)
|
|
||||||
//{ //(for huge files, the full file size is packed in 4 of these bytes... seriously wtf)
|
|
||||||
// var filesize = (hbytes[7] << 0) | (hbytes[14] << 8) | (hbytes[5] << 16) | (hbytes[2] << 24);
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
await br.ReadAsync(tbytes, 0, (int)totlen);
|
||||||
br.Read(tbytes, 0, (int)totlen);
|
|
||||||
if (entry.IsEncrypted)
|
if (entry.IsEncrypted)
|
||||||
{
|
{
|
||||||
if (IsAESEncrypted)
|
if (IsAESEncrypted)
|
||||||
{
|
{
|
||||||
GTACrypto.DecryptAES(tbytes);
|
GTACrypto.DecryptAES(tbytes, (int)totlen);
|
||||||
}
|
}
|
||||||
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
else //if (IsNGEncrypted) //assume the archive is set to NG encryption if not AES... (comment: fix for openIV modded files)
|
||||||
{
|
{
|
||||||
GTACrypto.DecryptNG(tbytes, entry.Name, entry.FileSize);
|
GTACrypto.DecryptNG(tbytes, entry.Name, entry.FileSize, 0, (int)totlen);
|
||||||
}
|
}
|
||||||
//else
|
|
||||||
//{ }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] deflated = DecompressBytes(tbytes);
|
byte[] deflated = await DecompressBytesAsync(tbytes);
|
||||||
|
|
||||||
byte[] data = null;
|
|
||||||
|
|
||||||
|
byte[] data;
|
||||||
if (deflated != null)
|
if (deflated != null)
|
||||||
{
|
{
|
||||||
data = deflated;
|
data = deflated;
|
||||||
@ -671,16 +772,67 @@ namespace CodeWalker.GameFiles
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
entry.FileSize -= offset;
|
entry.FileSize -= offset;
|
||||||
data = tbytes;
|
|
||||||
|
data = new byte[(int)totlen];
|
||||||
|
Buffer.BlockCopy(tbytes, 0, data, 0, (int)totlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ArrayPool<byte>.Shared.Return(tbytes);
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public byte[] ExtractFileResource(RpfResourceFileEntry entry, BinaryReader br)
|
||||||
|
{
|
||||||
|
br.BaseStream.Position = StartPos + ((long)entry.FileOffset * 512);
|
||||||
|
|
||||||
|
if (entry.FileSize <= 0)
|
||||||
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint offset = 0x10;
|
||||||
|
uint totlen = entry.FileSize - offset;
|
||||||
|
|
||||||
|
byte[] tbytes = ArrayPool<byte>.Shared.Rent((int)totlen);
|
||||||
|
|
||||||
|
|
||||||
|
br.BaseStream.Position += offset;
|
||||||
|
|
||||||
|
|
||||||
|
br.Read(tbytes, 0, (int)totlen);
|
||||||
|
if (entry.IsEncrypted)
|
||||||
|
{
|
||||||
|
if (IsAESEncrypted)
|
||||||
|
{
|
||||||
|
GTACrypto.DecryptAES(tbytes, (int)totlen);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] deflated = DecompressBytes(tbytes);
|
||||||
|
|
||||||
|
byte[] data;
|
||||||
|
if (deflated != null)
|
||||||
|
{
|
||||||
|
data = deflated;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry.FileSize -= offset;
|
||||||
|
|
||||||
|
data = new byte[(int)totlen];
|
||||||
|
Buffer.BlockCopy(tbytes, 0, data, 0, (int)totlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayPool<byte>.Shared.Return(tbytes);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
public static T GetFile<T>(RpfEntry e) where T : class, PackedFile, new()
|
public static T GetFile<T>(RpfEntry e) where T : class, PackedFile, new()
|
||||||
{
|
{
|
||||||
T file = null;
|
T file = null;
|
||||||
@ -892,7 +1044,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
LastError = string.Empty;
|
LastError = string.Empty;
|
||||||
LastException = null;
|
LastException = null;
|
||||||
if (!entry.NameLower.EndsWith(".rpf")) //don't try to extract rpf's, they will be done separately..
|
if (!entry.IsExtension(".rpf")) //don't try to extract rpf's, they will be done separately..
|
||||||
{
|
{
|
||||||
if (entry is RpfBinaryFileEntry)
|
if (entry is RpfBinaryFileEntry)
|
||||||
{
|
{
|
||||||
@ -1025,19 +1177,17 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static RecyclableMemoryStreamManager recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
|
public static RecyclableMemoryStreamManager recyclableMemoryStreamManager = new RecyclableMemoryStreamManager(256 * 1024, 1024 * 1024, 128 * 1024 * 1024, false, 256 * 1024 * 100, 1024 * 1024 * 128 * 4);
|
||||||
|
|
||||||
public byte[] DecompressBytes(byte[] bytes)
|
public byte[] DecompressBytes(byte[] bytes)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (DeflateStream ds = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress))
|
using DeflateStream ds = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress);
|
||||||
{
|
using var outstr = recyclableMemoryStreamManager.GetStream("DecompressBytes", bytes.Length);
|
||||||
using (var outstr = recyclableMemoryStreamManager.GetStream("DecompressBytes", bytes.Length))
|
|
||||||
{
|
ds.CopyToFast(outstr);
|
||||||
ds.CopyTo(outstr);
|
byte[] outbuf = outstr.ToArray(); //need to copy to the right size buffer for output.
|
||||||
byte[] deflated = outstr.GetBuffer();
|
|
||||||
byte[] outbuf = new byte[outstr.Length]; //need to copy to the right size buffer for output.
|
|
||||||
Buffer.BlockCopy(deflated, 0, outbuf, 0, outbuf.Length);
|
|
||||||
|
|
||||||
if (outbuf.Length <= bytes.Length)
|
if (outbuf.Length <= bytes.Length)
|
||||||
{
|
{
|
||||||
@ -1047,8 +1197,38 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
return outbuf;
|
return outbuf;
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LastError = "Could not decompress.";// ex.ToString();
|
||||||
|
LastException = ex;
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<byte[]> DecompressBytesAsync(byte[] bytes)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using DeflateStream ds = new DeflateStream(new MemoryStream(bytes), CompressionMode.Decompress);
|
||||||
|
using var outstr = recyclableMemoryStreamManager.GetStream("DecompressBytes", bytes.Length);
|
||||||
|
|
||||||
|
await ds.CopyToFastAsync(outstr).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)
|
||||||
|
{
|
||||||
|
LastError = "Warning: Decompressed data was smaller than compressed data...";
|
||||||
|
//return null; //could still be OK for tiny things!
|
||||||
|
}
|
||||||
|
|
||||||
|
return outbuf;
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
LastError = "Could not decompress.";// ex.ToString();
|
LastError = "Could not decompress.";// ex.ToString();
|
||||||
@ -1056,6 +1236,7 @@ namespace CodeWalker.GameFiles
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] CompressBytes(byte[] data) //TODO: refactor this with ResourceBuilder.Compress/Decompress
|
public static byte[] CompressBytes(byte[] data) //TODO: refactor this with ResourceBuilder.Compress/Decompress
|
||||||
{
|
{
|
||||||
using (MemoryStream ms = recyclableMemoryStreamManager.GetStream("CompressBytes", data.Length))
|
using (MemoryStream ms = recyclableMemoryStreamManager.GetStream("CompressBytes", data.Length))
|
||||||
@ -1152,7 +1333,7 @@ namespace CodeWalker.GameFiles
|
|||||||
Root = new RpfDirectoryEntry();
|
Root = new RpfDirectoryEntry();
|
||||||
Root.File = this;
|
Root.File = this;
|
||||||
Root.Name = string.Empty;
|
Root.Name = string.Empty;
|
||||||
Root.Path = Path.ToLowerInvariant();
|
Root.Path = Path;
|
||||||
}
|
}
|
||||||
if (Children == null)
|
if (Children == null)
|
||||||
{
|
{
|
||||||
@ -1517,15 +1698,15 @@ namespace CodeWalker.GameFiles
|
|||||||
//recursively update paths, including in child RPFs.
|
//recursively update paths, including in child RPFs.
|
||||||
if (dir == null)
|
if (dir == null)
|
||||||
{
|
{
|
||||||
Root.Path = Path.ToLowerInvariant();
|
Root.Path = Path;
|
||||||
dir = Root;
|
dir = Root;
|
||||||
}
|
}
|
||||||
foreach (var file in dir.Files)
|
foreach (var file in dir.Files)
|
||||||
{
|
{
|
||||||
file.Path = dir.Path + "\\" + file.NameLower;
|
file.Path = dir.Path + "\\" + file.Name;
|
||||||
|
|
||||||
RpfBinaryFileEntry binf = file as RpfBinaryFileEntry;
|
RpfBinaryFileEntry binf = file as RpfBinaryFileEntry;
|
||||||
if ((binf != null) && file.Name.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase))
|
if ((binf != null) && file.IsExtension(".rpf"))
|
||||||
{
|
{
|
||||||
RpfFile childrpf = FindChildArchive(binf);
|
RpfFile childrpf = FindChildArchive(binf);
|
||||||
if (childrpf != null)
|
if (childrpf != null)
|
||||||
@ -1685,9 +1866,8 @@ namespace CodeWalker.GameFiles
|
|||||||
//create a new directory inside the given parent dir
|
//create a new directory inside the given parent dir
|
||||||
|
|
||||||
RpfFile parent = dir.File;
|
RpfFile parent = dir.File;
|
||||||
string namel = name.ToLowerInvariant();
|
|
||||||
string fpath = parent.GetPhysicalFilePath();
|
string fpath = parent.GetPhysicalFilePath();
|
||||||
string rpath = dir.Path + "\\" + namel;
|
string rpath = dir.Path + "\\" + name;
|
||||||
|
|
||||||
if (!File.Exists(fpath))
|
if (!File.Exists(fpath))
|
||||||
{
|
{
|
||||||
@ -1862,7 +2042,6 @@ namespace CodeWalker.GameFiles
|
|||||||
entry.File = parent;
|
entry.File = parent;
|
||||||
entry.Path = rpath;
|
entry.Path = rpath;
|
||||||
entry.Name = name;
|
entry.Name = name;
|
||||||
entry.NameLower = namel;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2194,6 +2373,9 @@ namespace CodeWalker.GameFiles
|
|||||||
public RpfFile File { get; set; }
|
public RpfFile File { get; set; }
|
||||||
public RpfDirectoryEntry Parent { get; set; }
|
public RpfDirectoryEntry Parent { get; set; }
|
||||||
|
|
||||||
|
public static int ExtensionHits = 0;
|
||||||
|
public static int ExtensionMisses = 0;
|
||||||
|
|
||||||
public uint NameHash { get
|
public uint NameHash { get
|
||||||
{
|
{
|
||||||
if (nameHash == 0 && !string.IsNullOrEmpty(Name))
|
if (nameHash == 0 && !string.IsNullOrEmpty(Name))
|
||||||
@ -2229,19 +2411,38 @@ namespace CodeWalker.GameFiles
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
name = value;
|
name = value;
|
||||||
nameLower = null;
|
|
||||||
nameHash = 0;
|
nameHash = 0;
|
||||||
shortNameHash = 0;
|
shortNameHash = 0;
|
||||||
shortName = null;
|
shortName = null;
|
||||||
|
extension = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public string NameLower
|
|
||||||
|
public string Extension
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return nameLower ??= Name?.ToLowerInvariant();
|
if (extension == null)
|
||||||
|
{
|
||||||
|
int length = Name.Length;
|
||||||
|
for (int i = length; --i >= 0;)
|
||||||
|
{
|
||||||
|
char ch = Name[i];
|
||||||
|
if (ch == '.')
|
||||||
|
{
|
||||||
|
extension = Name.Substring(i, length - i).ToLowerInvariant();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (ch == System.IO.Path.DirectorySeparatorChar || ch == System.IO.Path.AltDirectorySeparatorChar)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
extension ??= string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return extension;
|
||||||
}
|
}
|
||||||
set { nameLower = value; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ShortName {
|
public string ShortName {
|
||||||
@ -2249,14 +2450,22 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(shortName) && !string.IsNullOrEmpty(Name))
|
if (string.IsNullOrEmpty(shortName) && !string.IsNullOrEmpty(Name))
|
||||||
{
|
{
|
||||||
int ind = Name.LastIndexOf('.');
|
int length = Name.Length;
|
||||||
if (ind > 0)
|
for (int i = length; --i >= 0;)
|
||||||
{
|
{
|
||||||
shortName = Name.Substring(0, ind);
|
char ch = Name[i];
|
||||||
|
if (ch == '.')
|
||||||
|
{
|
||||||
|
Interlocked.Increment(ref ExtensionHits);
|
||||||
|
shortName = Name.Substring(0, i);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
if (ch == System.IO.Path.DirectorySeparatorChar || ch == System.IO.Path.AltDirectorySeparatorChar)
|
||||||
{
|
{
|
||||||
|
Interlocked.Increment(ref ExtensionMisses);
|
||||||
shortName = Name;
|
shortName = Name;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2273,10 +2482,10 @@ namespace CodeWalker.GameFiles
|
|||||||
public uint H1; //first 2 header values from RPF table...
|
public uint H1; //first 2 header values from RPF table...
|
||||||
public uint H2;
|
public uint H2;
|
||||||
private string name;
|
private string name;
|
||||||
private string nameLower;
|
|
||||||
private uint shortNameHash;
|
private uint shortNameHash;
|
||||||
private uint nameHash;
|
private uint nameHash;
|
||||||
private string shortName;
|
private string shortName;
|
||||||
|
private string extension;
|
||||||
|
|
||||||
public abstract void Read(DataReader reader);
|
public abstract void Read(DataReader reader);
|
||||||
public abstract void Write(DataWriter writer);
|
public abstract void Write(DataWriter writer);
|
||||||
@ -2286,9 +2495,9 @@ namespace CodeWalker.GameFiles
|
|||||||
return Path;
|
return Path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetShortName()
|
public bool IsExtension(string ext)
|
||||||
{
|
{
|
||||||
return ShortName;
|
return Extension.Equals(ext, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using CodeWalker.Core.Utils;
|
|
||||||
|
|
||||||
|
using CodeWalker.Core.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -56,10 +58,10 @@ namespace CodeWalker.GameFiles
|
|||||||
AllRpfs = new List<RpfFile>();
|
AllRpfs = new List<RpfFile>();
|
||||||
DlcNoModRpfs = new List<RpfFile>();
|
DlcNoModRpfs = new List<RpfFile>();
|
||||||
AllNoModRpfs = new List<RpfFile>();
|
AllNoModRpfs = new List<RpfFile>();
|
||||||
RpfDict = new Dictionary<string, RpfFile>();
|
RpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
||||||
EntryDict = new Dictionary<string, RpfEntry>();
|
EntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
||||||
ModRpfDict = new Dictionary<string, RpfFile>();
|
ModRpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
||||||
ModEntryDict = new Dictionary<string, RpfEntry>();
|
ModEntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var rpfs = new ConcurrentBag<RpfFile>();
|
var rpfs = new ConcurrentBag<RpfFile>();
|
||||||
Parallel.ForEach(allfiles, (rpfpath) =>
|
Parallel.ForEach(allfiles, (rpfpath) =>
|
||||||
@ -73,7 +75,7 @@ namespace CodeWalker.GameFiles
|
|||||||
bool excl = false;
|
bool excl = false;
|
||||||
for (int i = 0; i < ExcludePaths.Length; i++)
|
for (int i = 0; i < ExcludePaths.Length; i++)
|
||||||
{
|
{
|
||||||
if (rf.Path.StartsWith(ExcludePaths[i]))
|
if (rf.Path.StartsWith(ExcludePaths[i], StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
excl = true;
|
excl = true;
|
||||||
break;
|
break;
|
||||||
@ -147,10 +149,10 @@ namespace CodeWalker.GameFiles
|
|||||||
DlcRpfs = new List<RpfFile>();
|
DlcRpfs = new List<RpfFile>();
|
||||||
DlcNoModRpfs = new List<RpfFile>();
|
DlcNoModRpfs = new List<RpfFile>();
|
||||||
AllNoModRpfs = new List<RpfFile>();
|
AllNoModRpfs = new List<RpfFile>();
|
||||||
RpfDict = new Dictionary<string, RpfFile>();
|
RpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
||||||
EntryDict = new Dictionary<string, RpfEntry>();
|
EntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
||||||
ModRpfDict = new Dictionary<string, RpfFile>();
|
ModRpfDict = new Dictionary<string, RpfFile>(StringComparer.OrdinalIgnoreCase);
|
||||||
ModEntryDict = new Dictionary<string, RpfEntry>();
|
ModEntryDict = new Dictionary<string, RpfEntry>(StringComparer.OrdinalIgnoreCase);
|
||||||
foreach (var rpf in allRpfs)
|
foreach (var rpf in allRpfs)
|
||||||
{
|
{
|
||||||
RpfDict[rpf.Path] = rpf;
|
RpfDict[rpf.Path] = rpf;
|
||||||
@ -171,8 +173,8 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
private void AddRpfFile(RpfFile file, bool isdlc, bool ismod)
|
private void AddRpfFile(RpfFile file, bool isdlc, bool ismod)
|
||||||
{
|
{
|
||||||
isdlc = isdlc || (file.NameLower == "update.rpf") || (file.NameLower.StartsWith("dlc") && file.NameLower.EndsWith(".rpf"));
|
isdlc = isdlc || file.Name.Equals("update.rpf", StringComparison.OrdinalIgnoreCase) || (file.Name.StartsWith("dlc", StringComparison.OrdinalIgnoreCase) && file.Name.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase));
|
||||||
ismod = ismod || (file.Path.StartsWith("mods\\"));
|
ismod = ismod || (file.Path.StartsWith("mods\\", StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
if (file.AllEntries != null)
|
if (file.AllEntries != null)
|
||||||
{
|
{
|
||||||
@ -249,8 +251,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public RpfFile FindRpfFile(string path, bool exactPathOnly)
|
public RpfFile FindRpfFile(string path, bool exactPathOnly)
|
||||||
{
|
{
|
||||||
RpfFile file = null; //check the dictionary
|
RpfFile file;
|
||||||
|
|
||||||
if (EnableMods && ModRpfDict.TryGetValue(path, out file))
|
if (EnableMods && ModRpfDict.TryGetValue(path, out file))
|
||||||
{
|
{
|
||||||
return file;
|
return file;
|
||||||
@ -261,14 +262,13 @@ namespace CodeWalker.GameFiles
|
|||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
string lpath = path.ToLowerInvariant(); //try look at names etc
|
|
||||||
foreach (RpfFile tfile in AllRpfs)
|
foreach (RpfFile tfile in AllRpfs)
|
||||||
{
|
{
|
||||||
if (!exactPathOnly && tfile.NameLower == lpath)
|
if (!exactPathOnly && tfile.Name.Equals(path, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return tfile;
|
return tfile;
|
||||||
}
|
}
|
||||||
if (tfile.Path == lpath)
|
if (tfile.Path.Equals(path, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return tfile;
|
return tfile;
|
||||||
}
|
}
|
||||||
@ -281,21 +281,20 @@ namespace CodeWalker.GameFiles
|
|||||||
public RpfEntry GetEntry(string path)
|
public RpfEntry GetEntry(string path)
|
||||||
{
|
{
|
||||||
RpfEntry entry;
|
RpfEntry entry;
|
||||||
string pathl = path.ToLowerInvariant();
|
if (EnableMods && ModEntryDict.TryGetValue(path, out entry))
|
||||||
if (EnableMods && ModEntryDict.TryGetValue(pathl, out entry))
|
|
||||||
{
|
{
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
EntryDict.TryGetValue(pathl, out entry);
|
EntryDict.TryGetValue(path, out entry);
|
||||||
if (entry == null)
|
if (entry == null)
|
||||||
{
|
{
|
||||||
pathl = pathl.Replace("/", "\\");
|
path = path.Replace("/", "\\");
|
||||||
pathl = pathl.Replace("common:", "common.rpf");
|
path = path.Replace("common:", "common.rpf");
|
||||||
if (EnableMods && ModEntryDict.TryGetValue(pathl, out entry))
|
if (EnableMods && ModEntryDict.TryGetValue(path, out entry))
|
||||||
{
|
{
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
EntryDict.TryGetValue(pathl, out entry);
|
EntryDict.TryGetValue(path, out entry);
|
||||||
}
|
}
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
@ -357,6 +356,30 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
public async Task<T> GetFileAsync<T>(RpfEntry e) where T : class, PackedFile, new()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
T file = null;
|
||||||
|
byte[] data = null;
|
||||||
|
RpfFileEntry entry = e as RpfFileEntry;
|
||||||
|
if (entry != null)
|
||||||
|
{
|
||||||
|
data = await entry.File.ExtractFileAsync(entry).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
file = new T();
|
||||||
|
file.Load(data, entry);
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
} catch(Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
public bool LoadFile<T>(T file, RpfEntry e) where T : class, PackedFile
|
public bool LoadFile<T>(T file, RpfEntry e) where T : class, PackedFile
|
||||||
{
|
{
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
@ -366,10 +389,42 @@ namespace CodeWalker.GameFiles
|
|||||||
data = entry.File.ExtractFile(entry);
|
data = entry.File.ExtractFile(entry);
|
||||||
}
|
}
|
||||||
if (data != null)
|
if (data != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
file.Load(data, entry);
|
file.Load(data, entry);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error occured while loading {entry.Name} at {entry.Path}:\n{ex}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async ValueTask<bool> LoadFileAsync<T>(T file, RpfEntry e) where T : class, PackedFile
|
||||||
|
{
|
||||||
|
byte[] data = null;
|
||||||
|
RpfFileEntry entry = e as RpfFileEntry;
|
||||||
|
if (entry != null)
|
||||||
|
{
|
||||||
|
data = await entry.File.ExtractFileAsync(entry).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
if (data != null && data.Length > 0)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
file.Load(data, entry);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error occured while loading {entry.Name} at {entry.Path}:\n{ex}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,71 +441,64 @@ namespace CodeWalker.GameFiles
|
|||||||
JenkIndex.Ensure(file.Name);
|
JenkIndex.Ensure(file.Name);
|
||||||
foreach (RpfEntry entry in file.AllEntries)
|
foreach (RpfEntry entry in file.AllEntries)
|
||||||
{
|
{
|
||||||
var nlow = entry.NameLower;
|
var name = entry.Name;
|
||||||
if (string.IsNullOrEmpty(nlow)) continue;
|
if (string.IsNullOrEmpty(name))
|
||||||
|
continue;
|
||||||
//JenkIndex.Ensure(entry.Name);
|
//JenkIndex.Ensure(entry.Name);
|
||||||
//JenkIndex.Ensure(nlow);
|
//JenkIndex.Ensure(nlow);
|
||||||
int ind = nlow.LastIndexOf('.');
|
var nameWithoutExtension = entry.ShortName;
|
||||||
if (ind > 0)
|
JenkIndex.EnsureBoth(nameWithoutExtension);
|
||||||
{
|
|
||||||
|
|
||||||
JenkIndex.Ensure(entry.Name.Substring(0, ind));
|
|
||||||
JenkIndex.Ensure(nlow.Substring(0, ind));
|
|
||||||
|
|
||||||
//if (ind < entry.Name.Length - 2)
|
//if (ind < entry.Name.Length - 2)
|
||||||
//{
|
//{
|
||||||
// JenkIndex.Ensure(entry.Name.Substring(0, ind) + ".#" + entry.Name.Substring(ind + 2));
|
// JenkIndex.Ensure(entry.Name.Substring(0, ind) + ".#" + entry.Name.Substring(ind + 2));
|
||||||
// JenkIndex.Ensure(entry.NameLower.Substring(0, ind) + ".#" + entry.NameLower.Substring(ind + 2));
|
// JenkIndex.Ensure(entry.NameLower.Substring(0, ind) + ".#" + entry.NameLower.Substring(ind + 2));
|
||||||
//}
|
//}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
JenkIndex.Ensure(entry.Name);
|
|
||||||
JenkIndex.Ensure(nlow);
|
|
||||||
}
|
|
||||||
if (BuildExtendedJenkIndex)
|
if (BuildExtendedJenkIndex)
|
||||||
{
|
{
|
||||||
if (nlow.EndsWith(".ydr"))// || nlow.EndsWith(".yft")) //do yft's get lods?
|
if (name.EndsWith(".ydr", StringComparison.OrdinalIgnoreCase))// || nlow.EndsWith(".yft")) //do yft's get lods?
|
||||||
{
|
{
|
||||||
var sname = nlow.Substring(0, nlow.Length - 4);
|
var sname = entry.ShortName;
|
||||||
JenkIndex.Ensure(sname + "_lod");
|
var nameLod = sname + "_lod";
|
||||||
JenkIndex.Ensure(sname + "_loda");
|
JenkIndex.EnsureLower(nameLod);
|
||||||
JenkIndex.Ensure(sname + "_lodb");
|
JenkIndex.EnsureLower(nameLod + 'a');
|
||||||
|
JenkIndex.EnsureLower(nameLod + 'b');
|
||||||
}
|
}
|
||||||
if (nlow.EndsWith(".ydd"))
|
else if (name.EndsWith(".ydd", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (nlow.EndsWith("_children.ydd"))
|
if (name.EndsWith("_children.ydd", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var strn = nlow.Substring(0, nlow.Length - 13);
|
var strn = entry.Name.Substring(0, name.Length - 13);
|
||||||
JenkIndex.Ensure(strn);
|
JenkIndex.EnsureLower(strn);
|
||||||
JenkIndex.Ensure(strn + "_lod");
|
var nameChildrenLod = strn + "_lod";
|
||||||
JenkIndex.Ensure(strn + "_loda");
|
JenkIndex.EnsureLower(nameChildrenLod);
|
||||||
JenkIndex.Ensure(strn + "_lodb");
|
JenkIndex.EnsureLower(nameChildrenLod + 'a');
|
||||||
|
JenkIndex.EnsureLower(nameChildrenLod + 'b');
|
||||||
}
|
}
|
||||||
var idx = nlow.LastIndexOf('_');
|
var idx = name.LastIndexOf('_');
|
||||||
if (idx > 0)
|
if (idx > 0)
|
||||||
{
|
{
|
||||||
var str1 = nlow.Substring(0, idx);
|
var str1 = name.Substring(0, idx);
|
||||||
var idx2 = str1.LastIndexOf('_');
|
var idx2 = str1.LastIndexOf('_');
|
||||||
if (idx2 > 0)
|
if (idx2 > 0)
|
||||||
{
|
{
|
||||||
var str2 = str1.Substring(0, idx2);
|
var str2 = str1.Substring(0, idx2);
|
||||||
JenkIndex.Ensure(str2 + "_lod");
|
JenkIndex.EnsureLower(str2 + "_lod");
|
||||||
var maxi = 100;
|
var maxi = 100;
|
||||||
for (int i = 1; i <= maxi; i++)
|
for (int i = 1; i <= maxi; i++)
|
||||||
{
|
{
|
||||||
var str3 = str2 + "_" + i.ToString().PadLeft(2, '0');
|
var str3 = str2 + '_' + i.ToString().PadLeft(2, '0') + "_lod";
|
||||||
//JenkIndex.Ensure(str3);
|
//JenkIndex.Ensure(str3);
|
||||||
JenkIndex.Ensure(str3 + "_lod");
|
JenkIndex.EnsureLower(str3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nlow.EndsWith(".sps"))
|
else if(name.EndsWith(".sps", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
JenkIndex.Ensure(nlow);//for shader preset filename hashes!
|
JenkIndex.EnsureLower(entry.Name);//for shader preset filename hashes!
|
||||||
}
|
}
|
||||||
if (nlow.EndsWith(".awc")) //create audio container path hashes...
|
else if(name.EndsWith(".awc", StringComparison.OrdinalIgnoreCase)) //create audio container path hashes...
|
||||||
{
|
{
|
||||||
string[] parts = entry.Path.Split('\\');
|
string[] parts = entry.Path.Split('\\');
|
||||||
int pl = parts.Length;
|
int pl = parts.Length;
|
||||||
@ -459,21 +507,18 @@ namespace CodeWalker.GameFiles
|
|||||||
string fn = parts[pl - 1];
|
string fn = parts[pl - 1];
|
||||||
string fd = parts[pl - 2];
|
string fd = parts[pl - 2];
|
||||||
string hpath = fn.Substring(0, fn.Length - 4);
|
string hpath = fn.Substring(0, fn.Length - 4);
|
||||||
if (fd.EndsWith(".rpf"))
|
if (fd.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
fd = fd.Substring(0, fd.Length - 4);
|
fd = fd.Substring(0, fd.Length - 4);
|
||||||
}
|
}
|
||||||
hpath = fd + "/" + hpath;
|
hpath = fd + '/' + hpath;
|
||||||
if (parts[pl - 3] != "sfx")
|
|
||||||
{ }//no hit
|
|
||||||
|
|
||||||
JenkIndex.Ensure(hpath);
|
JenkIndex.EnsureLower(hpath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nlow.EndsWith(".nametable"))
|
else if(name.EndsWith(".nametable", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
RpfBinaryFileEntry binfe = entry as RpfBinaryFileEntry;
|
if (entry is RpfBinaryFileEntry binfe)
|
||||||
if (binfe != null)
|
|
||||||
{
|
{
|
||||||
byte[] data = file.ExtractFile(binfe);
|
byte[] data = file.ExtractFile(binfe);
|
||||||
if (data != null)
|
if (data != null)
|
||||||
@ -487,9 +532,8 @@ namespace CodeWalker.GameFiles
|
|||||||
string str = sb.ToString();
|
string str = sb.ToString();
|
||||||
if (!string.IsNullOrEmpty(str))
|
if (!string.IsNullOrEmpty(str))
|
||||||
{
|
{
|
||||||
string strl = str.ToLowerInvariant();
|
|
||||||
//JenkIndex.Ensure(str);
|
//JenkIndex.Ensure(str);
|
||||||
JenkIndex.Ensure(strl);
|
JenkIndex.EnsureLower(str);
|
||||||
|
|
||||||
////DirMod_Sounds_ entries apparently can be used to infer SP audio strings
|
////DirMod_Sounds_ entries apparently can be used to infer SP audio strings
|
||||||
////no luck here yet though
|
////no luck here yet though
|
||||||
@ -508,8 +552,6 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,10 +96,12 @@
|
|||||||
|
|
||||||
|
|
||||||
using CodeWalker.GameFiles;
|
using CodeWalker.GameFiles;
|
||||||
|
using DirectXTexNet;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -122,8 +124,6 @@ namespace CodeWalker.Utils
|
|||||||
|
|
||||||
public static class DDSIO
|
public static class DDSIO
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
public static byte[] GetPixels(Texture texture, int mip)
|
public static byte[] GetPixels(Texture texture, int mip)
|
||||||
{
|
{
|
||||||
//dexyfex version
|
//dexyfex version
|
||||||
@ -159,29 +159,13 @@ namespace CodeWalker.Utils
|
|||||||
|
|
||||||
bool swaprb = true;
|
bool swaprb = true;
|
||||||
|
|
||||||
|
if (DirectXTexNet.TexHelper.Instance.IsCompressed((DirectXTexNet.DXGI_FORMAT)format))
|
||||||
|
{
|
||||||
|
px = Decompress(imgdata, w, h, format);
|
||||||
|
} else
|
||||||
|
{
|
||||||
switch (format)
|
switch (format)
|
||||||
{
|
{
|
||||||
// compressed
|
|
||||||
case DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM: // TextureFormat.D3DFMT_DXT1
|
|
||||||
px = DecompressDxt1(imgdata, w, h);
|
|
||||||
break;
|
|
||||||
case DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM: // TextureFormat.D3DFMT_DXT3
|
|
||||||
px = DecompressDxt3(imgdata, w, h);
|
|
||||||
break;
|
|
||||||
case DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM: // TextureFormat.D3DFMT_DXT5
|
|
||||||
px = DecompressDxt5(imgdata, w, h);
|
|
||||||
break;
|
|
||||||
case DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM: // TextureFormat.D3DFMT_ATI1
|
|
||||||
px = DecompressBC4(imgdata, w, h);
|
|
||||||
break;
|
|
||||||
case DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM: // TextureFormat.D3DFMT_ATI2
|
|
||||||
px = DecompressBC5(imgdata, w, h);
|
|
||||||
break;
|
|
||||||
case DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM: // TextureFormat.D3DFMT_BC7
|
|
||||||
//BC7 TODO!!
|
|
||||||
break;
|
|
||||||
|
|
||||||
// uncompressed
|
|
||||||
case DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM: // TextureFormat.D3DFMT_A1R5G5B5
|
case DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM: // TextureFormat.D3DFMT_A1R5G5B5
|
||||||
px = ConvertBGR5A1ToRGBA8(imgdata, w, h); //needs testing
|
px = ConvertBGR5A1ToRGBA8(imgdata, w, h); //needs testing
|
||||||
break;
|
break;
|
||||||
@ -205,8 +189,63 @@ namespace CodeWalker.Utils
|
|||||||
swaprb = false;
|
swaprb = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break; //shouldn't get here...
|
px = imgdata;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//switch (format)
|
||||||
|
//{
|
||||||
|
// // compressed
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_BC1_UNORM: // TextureFormat.D3DFMT_DXT1
|
||||||
|
// px = DecompressDxt1(imgdata, w, h);
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_BC2_UNORM: // TextureFormat.D3DFMT_DXT3
|
||||||
|
// px = DecompressDxt3(imgdata, w, h);
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_BC3_UNORM: // TextureFormat.D3DFMT_DXT5
|
||||||
|
// px = DecompressDxt5(imgdata, w, h);
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM: // TextureFormat.D3DFMT_ATI1
|
||||||
|
// px = Decompress(imgdata, w, h, DXGI_FORMAT.DXGI_FORMAT_BC4_UNORM);
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM: // TextureFormat.D3DFMT_ATI2
|
||||||
|
// px = Decompress(imgdata, w, h, DXGI_FORMAT.DXGI_FORMAT_BC5_UNORM);
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM: // TextureFormat.D3DFMT_BC7
|
||||||
|
// px = Decompress(imgdata, w, h, DXGI_FORMAT.DXGI_FORMAT_BC7_UNORM);
|
||||||
|
// //BC7 TODO!!
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// // uncompressed
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_B5G5R5A1_UNORM: // TextureFormat.D3DFMT_A1R5G5B5
|
||||||
|
// px = ConvertBGR5A1ToRGBA8(imgdata, w, h); //needs testing
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_A8_UNORM: // TextureFormat.D3DFMT_A8
|
||||||
|
// px = ConvertA8ToRGBA8(imgdata, w, h);
|
||||||
|
// swaprb = false;
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_UNORM: // TextureFormat.D3DFMT_A8B8G8R8
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_R8G8B8A8_TYPELESS:
|
||||||
|
// px = imgdata;
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_R8_UNORM: // TextureFormat.D3DFMT_L8
|
||||||
|
// px = ConvertR8ToRGBA8(imgdata, w, h);
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_B8G8R8A8_UNORM: // TextureFormat.D3DFMT_A8R8G8B8
|
||||||
|
// px = imgdata;
|
||||||
|
// swaprb = false;
|
||||||
|
// break;
|
||||||
|
// case DXGI_FORMAT.DXGI_FORMAT_B8G8R8X8_UNORM: // TextureFormat.D3DFMT_X8R8G8B8
|
||||||
|
// px = imgdata;
|
||||||
|
// swaprb = false;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// break; //shouldn't get here...
|
||||||
|
//}
|
||||||
|
|
||||||
if (swaprb && (px != null))
|
if (swaprb && (px != null))
|
||||||
{
|
{
|
||||||
@ -564,7 +603,10 @@ namespace CodeWalker.Utils
|
|||||||
images[i].format = format; //(DXGI_FORMAT)img.Format;
|
images[i].format = format; //(DXGI_FORMAT)img.Format;
|
||||||
images[i].pixels = buf + add;
|
images[i].pixels = buf + add;
|
||||||
|
|
||||||
DXTex.ComputePitch(images[i].format, images[i].width, images[i].height, out images[i].rowPitch, out images[i].slicePitch, 0);
|
DXTex.ComputePitch(images[i].format, images[i].width, images[i].height, out var rowPitch, out var slicePitch, 0);
|
||||||
|
images[i].rowPitch = (int)rowPitch;
|
||||||
|
images[i].slicePitch = (int)slicePitch;
|
||||||
|
//DXTex.ComputePitch(images[i].format, images[i].width, images[i].height, out images[i].rowPitch, out images[i].slicePitch, 0);
|
||||||
|
|
||||||
add += images[i].slicePitch;
|
add += images[i].slicePitch;
|
||||||
div *= 2;
|
div *= 2;
|
||||||
@ -2641,6 +2683,48 @@ namespace CodeWalker.Utils
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static unsafe byte[] Decompress(Byte[] data, int width, int height, DXGI_FORMAT format)
|
||||||
|
{
|
||||||
|
Console.WriteLine(format);
|
||||||
|
Console.WriteLine(width);
|
||||||
|
Console.WriteLine(height);
|
||||||
|
|
||||||
|
long inputRowPitch;
|
||||||
|
long inputSlicePitch;
|
||||||
|
TexHelper.Instance.ComputePitch((DirectXTexNet.DXGI_FORMAT)format, width, height, out inputRowPitch, out inputSlicePitch, DirectXTexNet.CP_FLAGS.NONE);
|
||||||
|
|
||||||
|
DirectXTexNet.DXGI_FORMAT FormatDecompressed;
|
||||||
|
|
||||||
|
if (format.ToString().Contains("SRGB"))
|
||||||
|
FormatDecompressed = DirectXTexNet.DXGI_FORMAT.R8G8B8A8_UNORM_SRGB;
|
||||||
|
else
|
||||||
|
FormatDecompressed = DirectXTexNet.DXGI_FORMAT.R8G8B8A8_UNORM;
|
||||||
|
|
||||||
|
byte* buf;
|
||||||
|
buf = (byte*)Marshal.AllocHGlobal((int)inputSlicePitch);
|
||||||
|
Marshal.Copy(data, 0, (IntPtr)buf, (int)inputSlicePitch);
|
||||||
|
|
||||||
|
DirectXTexNet.Image inputImage = new DirectXTexNet.Image(
|
||||||
|
width, height, (DirectXTexNet.DXGI_FORMAT)format, inputRowPitch,
|
||||||
|
inputSlicePitch, (IntPtr)buf, null);
|
||||||
|
|
||||||
|
DirectXTexNet.TexMetadata texMetadata = new DirectXTexNet.TexMetadata(width, height, 1, 1, 1, 0, 0,
|
||||||
|
(DirectXTexNet.DXGI_FORMAT)format, DirectXTexNet.TEX_DIMENSION.TEXTURE2D);
|
||||||
|
|
||||||
|
ScratchImage scratchImage = TexHelper.Instance.InitializeTemporary(
|
||||||
|
new DirectXTexNet.Image[] { inputImage }, texMetadata, null);
|
||||||
|
|
||||||
|
using (var decomp = scratchImage.Decompress(0, FormatDecompressed))
|
||||||
|
{
|
||||||
|
byte[] result = new byte[4 * width * height];
|
||||||
|
Marshal.Copy(decomp.GetImage(0).Pixels, result, 0, result.Length);
|
||||||
|
|
||||||
|
inputImage = null;
|
||||||
|
scratchImage.Dispose();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal static byte[] DecompressBC5(byte[] imageData, int width, int height)
|
internal static byte[] DecompressBC5(byte[] imageData, int width, int height)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
/*
|
|
||||||
|
|
||||||
|
/*
|
||||||
Copyright(c) 2015 Neodymium
|
Copyright(c) 2015 Neodymium
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
@ -29,6 +31,12 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using CodeWalker.Core.Utils;
|
||||||
|
using System.Buffers.Binary;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace CodeWalker.GameFiles
|
namespace CodeWalker.GameFiles
|
||||||
{
|
{
|
||||||
@ -98,18 +106,40 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public DataReader(Stream stream, Endianess endianess = Endianess.LittleEndian)
|
public DataReader(Stream stream, Endianess endianess = Endianess.LittleEndian)
|
||||||
{
|
{
|
||||||
this.baseStream = stream;
|
if (stream is not null)
|
||||||
|
{
|
||||||
|
this.baseStream = Stream.Synchronized(stream);
|
||||||
|
}
|
||||||
this.Endianess = endianess;
|
this.Endianess = endianess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual Stream GetStream()
|
||||||
|
{
|
||||||
|
return baseStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal virtual void SetPositionAfterRead(Stream stream)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads data from the underlying stream. This is the only method that directly accesses
|
/// Reads data from the underlying stream. This is the only method that directly accesses
|
||||||
/// the data in the underlying stream.
|
/// the data in the underlying stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual byte[] ReadFromStream(int count, bool ignoreEndianess = false, byte[] buffer = null)
|
protected virtual byte[] ReadFromStream(int count, bool ignoreEndianess = false, byte[] buffer = null)
|
||||||
{
|
{
|
||||||
|
var stream = GetStream();
|
||||||
buffer ??= new byte[count];
|
buffer ??= new byte[count];
|
||||||
baseStream.Read(buffer, 0, count);
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
stream.Read(buffer, 0, count);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SetPositionAfterRead(stream);
|
||||||
|
}
|
||||||
|
|
||||||
// handle endianess
|
// handle endianess
|
||||||
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
||||||
@ -125,11 +155,22 @@ namespace CodeWalker.GameFiles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual byte ReadByte()
|
public virtual byte ReadByte()
|
||||||
{
|
{
|
||||||
var result = baseStream.ReadByte();
|
var stream = GetStream();
|
||||||
|
int result;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = stream.ReadByte();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SetPositionAfterRead(stream);
|
||||||
|
}
|
||||||
|
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Tried to read from stream beyond end!");
|
throw new InvalidOperationException("Tried to read from stream beyond end!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return (byte) result;
|
return (byte) result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,21 +246,37 @@ namespace CodeWalker.GameFiles
|
|||||||
return BitConverter.ToDouble(ReadFromStream(8, buffer: _buffer), 0);
|
return BitConverter.ToDouble(ReadFromStream(8, buffer: _buffer), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a string.
|
||||||
|
/// </summary>
|
||||||
|
unsafe public string ReadStringLength(int length)
|
||||||
|
{
|
||||||
|
if (length == 0)
|
||||||
|
{
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
var bytes = stackalloc byte[length];
|
||||||
|
for (int i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
bytes[i] = ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string((sbyte*)bytes, 0, length, Encoding.ASCII);
|
||||||
|
//return Encoding.UTF8.GetString(bytes, Math.Min(charsRead, maxLength));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a string.
|
/// Reads a string.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
unsafe public string ReadString(int maxLength = 1024)
|
unsafe public string ReadString(int maxLength = 1024)
|
||||||
{
|
{
|
||||||
var bytes = stackalloc byte[Math.Min(maxLength, 1024)];
|
var bytes = stackalloc byte[Math.Min(maxLength, 1024)];
|
||||||
|
var chars = stackalloc char[Math.Min(maxLength, 1024)];
|
||||||
var temp = ReadByte();
|
var temp = ReadByte();
|
||||||
var charsRead = 0;
|
var charsRead = 0;
|
||||||
while (temp != 0 && (Length == -1 || Position <= Length))
|
while (temp != 0 && (Length == -1 || Position <= Length))
|
||||||
{
|
{
|
||||||
if (charsRead > 1023)
|
if (charsRead < maxLength && charsRead < 1024)
|
||||||
{
|
|
||||||
throw new Exception("String too long!");
|
|
||||||
}
|
|
||||||
if (charsRead < maxLength)
|
|
||||||
{
|
{
|
||||||
bytes[charsRead] = temp;
|
bytes[charsRead] = temp;
|
||||||
}
|
}
|
||||||
@ -227,7 +284,10 @@ namespace CodeWalker.GameFiles
|
|||||||
charsRead++;
|
charsRead++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Encoding.UTF8.GetString(bytes, Math.Min(charsRead, maxLength));
|
var charsCount = Encoding.UTF8.GetChars(bytes, charsRead, chars, Math.Min(maxLength, 1024));
|
||||||
|
|
||||||
|
return new string(chars, 0, charsCount);
|
||||||
|
//return Encoding.UTF8.GetString(bytes, Math.Min(charsRead, maxLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe public string ReadStringLower()
|
unsafe public string ReadStringLower()
|
||||||
@ -357,12 +417,23 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal virtual Stream GetStream()
|
||||||
|
{
|
||||||
|
return baseStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal virtual void SetPositionAfterWrite(Stream stream)
|
||||||
|
{ }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new data writer for the specified stream.
|
/// Initializes a new data writer for the specified stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DataWriter(Stream stream, Endianess endianess = Endianess.LittleEndian)
|
public DataWriter(Stream stream, Endianess endianess = Endianess.LittleEndian)
|
||||||
{
|
{
|
||||||
this.baseStream = stream;
|
if (stream is not null)
|
||||||
|
{
|
||||||
|
this.baseStream = Stream.Synchronized(stream);
|
||||||
|
}
|
||||||
this.Endianess = endianess;
|
this.Endianess = endianess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,17 +441,65 @@ namespace CodeWalker.GameFiles
|
|||||||
/// Writes data to the underlying stream. This is the only method that directly accesses
|
/// Writes data to the underlying stream. This is the only method that directly accesses
|
||||||
/// the data in the underlying stream.
|
/// the data in the underlying stream.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void WriteToStream(byte[] value, bool ignoreEndianess = false)
|
protected virtual void WriteToStream(byte[] value, bool ignoreEndianess = false, int count = -1, int offset = 0)
|
||||||
{
|
{
|
||||||
|
var stream = GetStream();
|
||||||
|
if (count == -1)
|
||||||
|
{
|
||||||
|
count = value.Length;
|
||||||
|
}
|
||||||
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
|
||||||
{
|
{
|
||||||
var buffer = (byte[])value.Clone();
|
var buffer = ArrayPool<byte>.Shared.Rent(count);
|
||||||
Array.Reverse(buffer);
|
try
|
||||||
baseStream.Write(buffer, 0, buffer.Length);
|
{
|
||||||
|
Array.Copy(value, offset, buffer, 0, count);
|
||||||
|
Array.Reverse(buffer, 0, count);
|
||||||
|
stream.Write(buffer, 0, count);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
baseStream.Write(value, 0, value.Length);
|
stream.Write(value, offset, count);
|
||||||
|
}
|
||||||
|
SetPositionAfterWrite(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void WriteToStream(Span<byte> value, bool ignoreEndianess = false)
|
||||||
|
{
|
||||||
|
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(value.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
value.CopyTo(sharedBuffer);
|
||||||
|
WriteToStream(sharedBuffer, count: value.Length);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(sharedBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void WriteToStream(Memory<byte> buffer, bool ignoreEndianess = false)
|
||||||
|
{
|
||||||
|
if (MemoryMarshal.TryGetArray(buffer, out ArraySegment<byte> array))
|
||||||
|
{
|
||||||
|
WriteToStream(array.Array!, offset: array.Offset, count: array.Count);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
buffer.Span.CopyTo(sharedBuffer);
|
||||||
|
WriteToStream(sharedBuffer, count: buffer.Length);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(sharedBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,6 +519,16 @@ namespace CodeWalker.GameFiles
|
|||||||
WriteToStream(value, true);
|
WriteToStream(value, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Write(Span<byte> value)
|
||||||
|
{
|
||||||
|
WriteToStream(value, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(Memory<byte> value)
|
||||||
|
{
|
||||||
|
WriteToStream(value, true);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes a signed 16-bit value.
|
/// Writes a signed 16-bit value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -512,12 +641,12 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
baseStream.Dispose();
|
baseStream?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Close()
|
public virtual void Close()
|
||||||
{
|
{
|
||||||
baseStream.Close();
|
baseStream?.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/*
|
|
||||||
|
/*
|
||||||
Copyright(c) 2015 Neodymium
|
Copyright(c) 2015 Neodymium
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
//shamelessly stolen
|
//shamelessly stolen
|
||||||
|
|
||||||
using CodeWalker.Core.Properties;
|
using CodeWalker.Core.Properties;
|
||||||
|
using CodeWalker.Core.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@ -297,7 +298,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
using (MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream())
|
using (MemoryStream outstr = RpfFile.recyclableMemoryStreamManager.GetStream())
|
||||||
{
|
{
|
||||||
ds.CopyTo(outstr);
|
ds.CopyToFast(outstr);
|
||||||
b = outstr.GetBuffer();
|
b = outstr.GetBuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1220,7 +1221,7 @@ namespace CodeWalker.GameFiles
|
|||||||
using (var fs = new FileStream(fileName, FileMode.Create))
|
using (var fs = new FileStream(fileName, FileMode.Create))
|
||||||
{
|
{
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
ms.CopyTo(fs);
|
ms.CopyToFast(fs);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1307,7 +1308,7 @@ namespace CodeWalker.GameFiles
|
|||||||
using (var fs = new FileStream(fileName, FileMode.Create))
|
using (var fs = new FileStream(fileName, FileMode.Create))
|
||||||
{
|
{
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
ms.CopyTo(fs);
|
ms.CopyToFast(fs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1445,7 +1446,7 @@ namespace CodeWalker.GameFiles
|
|||||||
using (var fs = new FileStream(fileName, FileMode.Create))
|
using (var fs = new FileStream(fileName, FileMode.Create))
|
||||||
{
|
{
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
ms.CopyTo(fs);
|
ms.CopyToFast(fs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -28,6 +29,11 @@ namespace CodeWalker.GameFiles
|
|||||||
HashHex = "0x" + HashUint.ToString("X");
|
HashHex = "0x" + HashUint.ToString("X");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static char ToLower(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'A' && c <= 'Z') ? (char)(c - 'A' + 'a') : c;
|
||||||
|
}
|
||||||
|
|
||||||
public static uint GenHash(string text, JenkHashInputEncoding encoding)
|
public static uint GenHash(string text, JenkHashInputEncoding encoding)
|
||||||
{
|
{
|
||||||
@ -64,8 +70,47 @@ namespace CodeWalker.GameFiles
|
|||||||
uint h = 0;
|
uint h = 0;
|
||||||
for (int i = 0; i < text.Length; i++)
|
for (int i = 0; i < text.Length; i++)
|
||||||
{
|
{
|
||||||
|
h += (byte)ToLower(text[i]);
|
||||||
|
h += (h << 10);
|
||||||
|
h ^= (h >> 6);
|
||||||
|
}
|
||||||
|
h += (h << 3);
|
||||||
|
h ^= (h >> 11);
|
||||||
|
h += (h << 15);
|
||||||
|
|
||||||
h += (byte)char.ToLowerInvariant(text[i]);
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint GenHashLower(ReadOnlySpan<char> text, ReadOnlySpan<char> str2 = default)
|
||||||
|
{
|
||||||
|
if (text == null) return 0;
|
||||||
|
uint h = 0;
|
||||||
|
for (int i = 0; i < text.Length; i++)
|
||||||
|
{
|
||||||
|
h += (byte)ToLower(text[i]);
|
||||||
|
h += (h << 10);
|
||||||
|
h ^= (h >> 6);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < str2.Length; i++)
|
||||||
|
{
|
||||||
|
h += (byte)ToLower(str2[i]);
|
||||||
|
h += (h << 10);
|
||||||
|
h ^= (h >> 6);
|
||||||
|
}
|
||||||
|
h += (h << 3);
|
||||||
|
h ^= (h >> 11);
|
||||||
|
h += (h << 15);
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static uint GenHash(ReadOnlySpan<char> text)
|
||||||
|
{
|
||||||
|
if (text == null) return 0;
|
||||||
|
uint h = 0;
|
||||||
|
for (int i = 0; i < text.Length; i++)
|
||||||
|
{
|
||||||
|
h += (byte)text[i];
|
||||||
h += (h << 10);
|
h += (h << 10);
|
||||||
h ^= (h >> 6);
|
h ^= (h >> 6);
|
||||||
}
|
}
|
||||||
@ -231,41 +276,42 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
public static class JenkIndex
|
public static class JenkIndex
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<uint, string> Index = new ConcurrentDictionary<uint, string>(Environment.ProcessorCount, 1500000);
|
public static ConcurrentDictionary<uint, string> Index = new ConcurrentDictionary<uint, string>(32, 1500000);
|
||||||
|
|
||||||
public static void Clear()
|
public static void Ensure(string str)
|
||||||
{
|
|
||||||
Index.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Ensure(string str)
|
|
||||||
{
|
{
|
||||||
uint hash = JenkHash.GenHash(str);
|
uint hash = JenkHash.GenHash(str);
|
||||||
if (hash == 0) return true;
|
Ensure(str, hash);
|
||||||
if (Index.ContainsKey(hash))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
lock (Index)
|
|
||||||
{
|
|
||||||
Index[hash] = str;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool EnsureLower(string str)
|
public static void Ensure(string str, uint hash)
|
||||||
{
|
{
|
||||||
uint hash = JenkHash.GenHashLower(str);
|
if (hash == 0) return;
|
||||||
if (hash == 0) return true;
|
|
||||||
if (Index.ContainsKey(hash))
|
if (Index.ContainsKey(hash))
|
||||||
{
|
{
|
||||||
return true;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Index.TryAdd(hash, str);
|
Index.TryAdd(hash, str);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void EnsureLower(string str)
|
||||||
|
{
|
||||||
|
uint hash = JenkHash.GenHashLower(str);
|
||||||
|
Ensure(str, hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void EnsureBoth(string str)
|
||||||
|
{
|
||||||
|
uint hash = JenkHash.GenHash(str);
|
||||||
|
uint hashLower = JenkHash.GenHashLower(str);
|
||||||
|
Ensure(str, hash);
|
||||||
|
if (hash != hashLower)
|
||||||
|
{
|
||||||
|
Ensure(str, hashLower);
|
||||||
|
}
|
||||||
|
}
|
||||||
public static void AddRange(params string[] strings)
|
public static void AddRange(params string[] strings)
|
||||||
{
|
{
|
||||||
foreach(var s in strings)
|
foreach(var s in strings)
|
||||||
@ -307,10 +353,9 @@ namespace CodeWalker.GameFiles
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string[] GetAllStrings()
|
public static ICollection<string> GetAllStrings()
|
||||||
{
|
{
|
||||||
string[] res = null;
|
var res = Index.Values;
|
||||||
res = Index.Values.ToArray();
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith("cache_y.dat"))// || entry.NameLower.EndsWith("cache_y_bank.dat"))
|
if (entry.Name.EndsWith("cache_y.dat", StringComparison.OrdinalIgnoreCase))// || entry.NameLower.EndsWith("cache_y_bank.dat"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
var cdfile = RpfMan.GetFile<CacheDatFile>(entry);
|
var cdfile = RpfMan.GetFile<CacheDatFile>(entry);
|
||||||
@ -63,7 +63,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
foreach (RpfEntry entry in file.AllEntries)
|
foreach (RpfEntry entry in file.AllEntries)
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".dat") && entry.NameLower.StartsWith("heightmap"))
|
if (entry.IsExtension(".dat") && entry.Name.StartsWith("heightmap", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
HeightmapFile hmf = null;
|
HeightmapFile hmf = null;
|
||||||
@ -100,7 +100,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
foreach (RpfEntry entry in file.AllEntries)
|
foreach (RpfEntry entry in file.AllEntries)
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".dat") && entry.NameLower.StartsWith("waterheight"))
|
if (entry.IsExtension(".dat") && entry.Name.StartsWith("waterheight", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
WatermapFile wmf = null;
|
WatermapFile wmf = null;
|
||||||
@ -147,7 +147,7 @@ namespace CodeWalker.GameFiles
|
|||||||
var rbfe = rfe as RpfBinaryFileEntry;
|
var rbfe = rfe as RpfBinaryFileEntry;
|
||||||
if ((rfe == null) || (rbfe == null)) continue;
|
if ((rfe == null) || (rbfe == null)) continue;
|
||||||
|
|
||||||
if (rfe.Name.EndsWith(".rel", StringComparison.OrdinalIgnoreCase))
|
if (rfe.IsExtension(".rel"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
|
|
||||||
@ -315,8 +315,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var n = entry.NameLower;
|
if (entry.IsExtension(".ymt"))
|
||||||
if (n.EndsWith(".ymt"))
|
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
//YmtFile ymtfile = RpfMan.GetFile<YmtFile>(entry);
|
//YmtFile ymtfile = RpfMan.GetFile<YmtFile>(entry);
|
||||||
@ -324,7 +323,7 @@ namespace CodeWalker.GameFiles
|
|||||||
//{
|
//{
|
||||||
//}
|
//}
|
||||||
|
|
||||||
var sn = entry.GetShortName();
|
var sn = entry.ShortName;
|
||||||
uint un;
|
uint un;
|
||||||
if (uint.TryParse(sn, out un))
|
if (uint.TryParse(sn, out un))
|
||||||
{
|
{
|
||||||
@ -388,8 +387,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
//{
|
//{
|
||||||
var n = entry.NameLower;
|
if (entry.IsExtension(".awc"))
|
||||||
if (n.EndsWith(".awc"))
|
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
var awcfile = RpfMan.GetFile<AwcFile>(entry);
|
var awcfile = RpfMan.GetFile<AwcFile>(entry);
|
||||||
@ -417,8 +415,8 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
{
|
{
|
||||||
var n = entry.NameLower;
|
var n = entry.Name;
|
||||||
//if (n.EndsWith(".ymap"))
|
//if (n.EndsWith(".ymap", StringComparison.OrdinalIgnoreCase))
|
||||||
//{
|
//{
|
||||||
// UpdateStatus?.Invoke(string.Format(entry.Path));
|
// UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
// YmapFile ymapfile = RpfMan.GetFile<YmapFile>(entry);
|
// YmapFile ymapfile = RpfMan.GetFile<YmapFile>(entry);
|
||||||
@ -427,7 +425,7 @@ namespace CodeWalker.GameFiles
|
|||||||
// MetaTypes.EnsureMetaTypes(ymapfile.Meta);
|
// MetaTypes.EnsureMetaTypes(ymapfile.Meta);
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
//else if (n.EndsWith(".ytyp"))
|
//else if (n.EndsWith(".ytyp", StringComparison.OrdinalIgnoreCase))
|
||||||
//{
|
//{
|
||||||
// UpdateStatus?.Invoke(string.Format(entry.Path));
|
// UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
// YtypFile ytypfile = RpfMan.GetFile<YtypFile>(entry);
|
// YtypFile ytypfile = RpfMan.GetFile<YtypFile>(entry);
|
||||||
@ -436,7 +434,7 @@ namespace CodeWalker.GameFiles
|
|||||||
// MetaTypes.EnsureMetaTypes(ytypfile.Meta);
|
// MetaTypes.EnsureMetaTypes(ytypfile.Meta);
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
//else if (n.EndsWith(".ymt"))
|
//else if (n.EndsWith(".ymt", StringComparison.OrdinalIgnoreCase))
|
||||||
//{
|
//{
|
||||||
// UpdateStatus?.Invoke(string.Format(entry.Path));
|
// UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
// YmtFile ymtfile = RpfMan.GetFile<YmtFile>(entry);
|
// YmtFile ymtfile = RpfMan.GetFile<YmtFile>(entry);
|
||||||
@ -447,7 +445,7 @@ namespace CodeWalker.GameFiles
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
||||||
if (n.EndsWith(".ymap") || n.EndsWith(".ytyp") || n.EndsWith(".ymt"))
|
if (n.EndsWith(".ymap", StringComparison.OrdinalIgnoreCase) || n.EndsWith(".ytyp", StringComparison.OrdinalIgnoreCase) || n.EndsWith(".ymt", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var rfe = entry as RpfResourceFileEntry;
|
var rfe = entry as RpfResourceFileEntry;
|
||||||
if (rfe == null) continue;
|
if (rfe == null) continue;
|
||||||
@ -465,7 +463,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
if (xml.Length != xml2.Length)
|
if (xml.Length != xml2.Length)
|
||||||
{ }
|
{ }
|
||||||
if ((xml != xml2) && (!n.EndsWith("srl.ymt") && !n.StartsWith("des_")))
|
if ((xml != xml2) && (!n.EndsWith("srl.ymt", StringComparison.OrdinalIgnoreCase) && !n.StartsWith("des_", StringComparison.OrdinalIgnoreCase)))
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -501,13 +499,13 @@ namespace CodeWalker.GameFiles
|
|||||||
try
|
try
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
var n = entry.NameLower;
|
var n = entry.Name;
|
||||||
if (!(n.EndsWith(".pso") ||
|
if (!(n.EndsWith(".pso", StringComparison.OrdinalIgnoreCase) ||
|
||||||
n.EndsWith(".ymt") ||
|
n.EndsWith(".ymt", StringComparison.OrdinalIgnoreCase) ||
|
||||||
n.EndsWith(".ymf") ||
|
n.EndsWith(".ymf", StringComparison.OrdinalIgnoreCase) ||
|
||||||
n.EndsWith(".ymap") ||
|
n.EndsWith(".ymap", StringComparison.OrdinalIgnoreCase) ||
|
||||||
n.EndsWith(".ytyp") ||
|
n.EndsWith(".ytyp", StringComparison.OrdinalIgnoreCase) ||
|
||||||
n.EndsWith(".cut")))
|
n.EndsWith(".cut", StringComparison.OrdinalIgnoreCase)))
|
||||||
continue; //PSO files seem to only have these extensions
|
continue; //PSO files seem to only have these extensions
|
||||||
|
|
||||||
var fentry = entry as RpfFileEntry;
|
var fentry = entry as RpfFileEntry;
|
||||||
@ -597,12 +595,12 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
foreach (RpfEntry entry in file.AllEntries)
|
foreach (RpfEntry entry in file.AllEntries)
|
||||||
{
|
{
|
||||||
var n = entry.NameLower;
|
var n = entry.Name;
|
||||||
if (!(n.EndsWith(".ymt") ||
|
if (!(n.EndsWith(".ymt", StringComparison.OrdinalIgnoreCase) ||
|
||||||
n.EndsWith(".ymf") ||
|
n.EndsWith(".ymf", StringComparison.OrdinalIgnoreCase) ||
|
||||||
n.EndsWith(".ymap") ||
|
n.EndsWith(".ymap", StringComparison.OrdinalIgnoreCase) ||
|
||||||
n.EndsWith(".ytyp") ||
|
n.EndsWith(".ytyp", StringComparison.OrdinalIgnoreCase) ||
|
||||||
n.EndsWith(".cut")))
|
n.EndsWith(".cut", StringComparison.OrdinalIgnoreCase)))
|
||||||
continue; //PSO files seem to only have these extensions
|
continue; //PSO files seem to only have these extensions
|
||||||
|
|
||||||
var fentry = entry as RpfFileEntry;
|
var fentry = entry as RpfFileEntry;
|
||||||
@ -686,7 +684,7 @@ namespace CodeWalker.GameFiles
|
|||||||
var rfe = entry as RpfFileEntry;
|
var rfe = entry as RpfFileEntry;
|
||||||
if (rfe == null) continue;
|
if (rfe == null) continue;
|
||||||
|
|
||||||
if (rfe.NameLower.EndsWith(".cut"))
|
if (rfe.IsExtension(".cut"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
|
|
||||||
@ -729,7 +727,7 @@ namespace CodeWalker.GameFiles
|
|||||||
var rfe = entry as RpfFileEntry;
|
var rfe = entry as RpfFileEntry;
|
||||||
if (rfe == null) continue;
|
if (rfe == null) continue;
|
||||||
|
|
||||||
if (rfe.NameLower.EndsWith(".yld"))
|
if (rfe.IsExtension(".yld"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
|
|
||||||
@ -769,7 +767,7 @@ namespace CodeWalker.GameFiles
|
|||||||
var rfe = entry as RpfFileEntry;
|
var rfe = entry as RpfFileEntry;
|
||||||
if (rfe == null) continue;
|
if (rfe == null) continue;
|
||||||
|
|
||||||
if (rfe.NameLower.EndsWith(".yed"))
|
if (rfe.IsExtension(".yed"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
|
|
||||||
@ -813,7 +811,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
//{
|
//{
|
||||||
if (entry.NameLower.EndsWith(".ycd"))
|
if (entry.IsExtension(".ycd"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YcdFile ycd1 = RpfMan.GetFile<YcdFile>(entry);
|
YcdFile ycd1 = RpfMan.GetFile<YcdFile>(entry);
|
||||||
@ -1084,7 +1082,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".ytd"))
|
if (entry.IsExtension(".ytd"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YtdFile ytdfile = null;
|
YtdFile ytdfile = null;
|
||||||
@ -1103,7 +1101,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
var dds = Utils.DDSIO.GetDDSFile(tex);
|
var dds = Utils.DDSIO.GetDDSFile(tex);
|
||||||
var tex2 = Utils.DDSIO.GetTexture(dds);
|
var tex2 = Utils.DDSIO.GetTexture(dds);
|
||||||
if (!tex.Name.StartsWith("script_rt"))
|
if (!tex.Name.StartsWith("script_rt", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (tex.Data?.FullData?.Length != tex2.Data?.FullData?.Length)
|
if (tex.Data?.FullData?.Length != tex2.Data?.FullData?.Length)
|
||||||
{ }
|
{ }
|
||||||
@ -1181,7 +1179,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".ybn"))
|
if (entry.IsExtension(".ybn"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YbnFile ybn = null;
|
YbnFile ybn = null;
|
||||||
@ -1353,7 +1351,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".ydr"))
|
if (entry.IsExtension(".ydr"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YdrFile ydr = null;
|
YdrFile ydr = null;
|
||||||
@ -1412,7 +1410,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".ydd"))
|
if (entry.IsExtension(".ydd"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YddFile ydd = null;
|
YddFile ydd = null;
|
||||||
@ -1481,7 +1479,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".yft"))
|
if (entry.IsExtension(".yft"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YftFile yft = null;
|
YftFile yft = null;
|
||||||
@ -1558,7 +1556,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".ypt"))
|
if (entry.IsExtension(".ypt"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YptFile ypt = null;
|
YptFile ypt = null;
|
||||||
@ -1616,7 +1614,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
//try
|
//try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".ynv"))
|
if (entry.IsExtension(".ynv"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YnvFile ynv = null;
|
YnvFile ynv = null;
|
||||||
@ -1697,9 +1695,9 @@ namespace CodeWalker.GameFiles
|
|||||||
var rfe = entry as RpfFileEntry;
|
var rfe = entry as RpfFileEntry;
|
||||||
if (rfe == null) continue;
|
if (rfe == null) continue;
|
||||||
|
|
||||||
if (rfe.NameLower.EndsWith(".yvr"))
|
if (rfe.IsExtension(".yvr"))
|
||||||
{
|
{
|
||||||
if (rfe.NameLower == "agencyprep001.yvr") continue; //this file seems corrupted
|
if (rfe.Name.Equals("agencyprep001.yvr", StringComparison.OrdinalIgnoreCase)) continue; //this file seems corrupted
|
||||||
|
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
|
|
||||||
@ -1745,10 +1743,9 @@ namespace CodeWalker.GameFiles
|
|||||||
try
|
try
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
var rfe = entry as RpfFileEntry;
|
if (entry is not RpfFileEntry rfe || rfe == null) continue;
|
||||||
if (rfe == null) continue;
|
|
||||||
|
|
||||||
if (rfe.NameLower.EndsWith(".ywr"))
|
if (rfe.IsExtension(".ywr"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
|
|
||||||
@ -1789,7 +1786,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".ymap"))
|
if (entry.IsExtension(".ymap"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YmapFile ymapfile = RpfMan.GetFile<YmapFile>(entry);
|
YmapFile ymapfile = RpfMan.GetFile<YmapFile>(entry);
|
||||||
@ -1817,7 +1814,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (rfe.NameLower.EndsWith(".ypdb"))
|
if (rfe.IsExtension(".ypdb"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YpdbFile ypdb = RpfMan.GetFile<YpdbFile>(entry);
|
YpdbFile ypdb = RpfMan.GetFile<YpdbFile>(entry);
|
||||||
@ -1866,7 +1863,7 @@ namespace CodeWalker.GameFiles
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (rfe.NameLower.EndsWith(".yfd"))
|
if (rfe.IsExtension(".yfd"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
YfdFile yfd = RpfMan.GetFile<YfdFile>(entry);
|
YfdFile yfd = RpfMan.GetFile<YfdFile>(entry);
|
||||||
@ -1913,7 +1910,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".mrf"))
|
if (entry.IsExtension(".mrf"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
MrfFile mrffile = RpfMan.GetFile<MrfFile>(entry);
|
MrfFile mrffile = RpfMan.GetFile<MrfFile>(entry);
|
||||||
@ -2083,7 +2080,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".fxc"))
|
if (entry.IsExtension(".fxc"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(string.Format(entry.Path));
|
UpdateStatus?.Invoke(string.Format(entry.Path));
|
||||||
var fxcfile = RpfMan.GetFile<FxcFile>(entry);
|
var fxcfile = RpfMan.GetFile<FxcFile>(entry);
|
||||||
@ -2298,7 +2295,7 @@ namespace CodeWalker.GameFiles
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (doydr && entry.NameLower.EndsWith(".ydr"))
|
if (doydr && entry.IsExtension(".ydr"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(entry.Path);
|
UpdateStatus?.Invoke(entry.Path);
|
||||||
YdrFile ydr = RpfMan.GetFile<YdrFile>(entry);
|
YdrFile ydr = RpfMan.GetFile<YdrFile>(entry);
|
||||||
@ -2327,7 +2324,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (doydd & entry.NameLower.EndsWith(".ydd"))
|
else if (doydd & entry.IsExtension(".ydd"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(entry.Path);
|
UpdateStatus?.Invoke(entry.Path);
|
||||||
YddFile ydd = RpfMan.GetFile<YddFile>(entry);
|
YddFile ydd = RpfMan.GetFile<YddFile>(entry);
|
||||||
@ -2359,7 +2356,7 @@ namespace CodeWalker.GameFiles
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (doyft && entry.NameLower.EndsWith(".yft"))
|
else if (doyft && entry.IsExtension(".yft"))
|
||||||
{
|
{
|
||||||
UpdateStatus?.Invoke(entry.Path);
|
UpdateStatus?.Invoke(entry.Path);
|
||||||
YftFile yft = RpfMan.GetFile<YftFile>(entry);
|
YftFile yft = RpfMan.GetFile<YftFile>(entry);
|
||||||
|
@ -14,11 +14,12 @@ namespace CodeWalker
|
|||||||
public long MaxMemoryUsage = 536870912; //512mb
|
public long MaxMemoryUsage = 536870912; //512mb
|
||||||
public long CurrentMemoryUsage = 0;
|
public long CurrentMemoryUsage = 0;
|
||||||
public double CacheTime = 10.0; //seconds to keep something that's not used
|
public double CacheTime = 10.0; //seconds to keep something that's not used
|
||||||
|
public double LoadingCacheTime = 1.0;
|
||||||
public DateTime CurrentTime = DateTime.Now;
|
public DateTime CurrentTime = DateTime.Now;
|
||||||
|
|
||||||
private LinkedList<TVal> loadedList = new LinkedList<TVal>();
|
private LinkedList<TVal> loadedList = new LinkedList<TVal>();
|
||||||
private object loadedListLock = new object();
|
private object loadedListLock = new object();
|
||||||
private Dictionary<TKey, LinkedListNode<TVal>> loadedListDict = new Dictionary<TKey, LinkedListNode<TVal>>();
|
private ConcurrentDictionary<TKey, LinkedListNode<TVal>> loadedListDict = new ConcurrentDictionary<TKey, LinkedListNode<TVal>>();
|
||||||
|
|
||||||
public int Count
|
public int Count
|
||||||
{
|
{
|
||||||
@ -45,50 +46,52 @@ namespace CodeWalker
|
|||||||
|
|
||||||
public TVal TryGet(TKey key)
|
public TVal TryGet(TKey key)
|
||||||
{
|
{
|
||||||
LinkedListNode<TVal> lln = null;
|
|
||||||
lock (loadedListLock)
|
lock (loadedListLock)
|
||||||
{
|
{
|
||||||
if (loadedListDict.TryGetValue(key, out lln))
|
if (loadedListDict.TryGetValue(key, out var lln))
|
||||||
{
|
{
|
||||||
|
|
||||||
loadedList.Remove(lln);
|
loadedList.Remove(lln);
|
||||||
loadedList.AddLast(lln);
|
loadedList.AddLast(lln);
|
||||||
|
|
||||||
lln.Value.LastUseTime = CurrentTime;
|
lln.Value.LastUseTime = CurrentTime;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return (lln != null) ? lln.Value : null;
|
return (lln != null) ? lln.Value : null;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
public bool TryAdd(TKey key, TVal item)
|
public bool TryAdd(TKey key, TVal item)
|
||||||
{
|
{
|
||||||
item.Key = key;
|
item.Key = key;
|
||||||
if (CanAdd())
|
if (CanAdd())
|
||||||
{
|
{
|
||||||
|
LinkedListNode<TVal> lln;
|
||||||
lock(loadedListLock)
|
lock(loadedListLock)
|
||||||
{
|
{
|
||||||
var lln = loadedList.AddLast(item);
|
lln = loadedList.AddLast(item);
|
||||||
loadedListDict.Add(key, lln);
|
|
||||||
Interlocked.Add(ref CurrentMemoryUsage, item.MemoryUsage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lln.Value.LastUseTime = CurrentTime;
|
||||||
|
loadedListDict.TryAdd(key, lln);
|
||||||
|
Interlocked.Add(ref CurrentMemoryUsage, item.MemoryUsage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//cache full, check the front of the list for oldest..
|
//cache full, check the front of the list for oldest..
|
||||||
var oldlln = loadedList.First;
|
var oldlln = loadedList.First;
|
||||||
var cachetime = CacheTime;
|
var cachetime = LoadingCacheTime;
|
||||||
int iter = 0, maxiter = 2;
|
int iter = 0, maxiter = 2;
|
||||||
while (!CanAdd() && (iter<maxiter))
|
while (!CanAdd() && (iter<maxiter))
|
||||||
{
|
{
|
||||||
while ((!CanAdd()) && (oldlln != null) && ((CurrentTime - oldlln.Value.LastUseTime).TotalSeconds > cachetime))
|
while ((!CanAdd()) && (oldlln != null) && ((CurrentTime - oldlln.Value.LastUseTime).TotalSeconds > cachetime))
|
||||||
{
|
|
||||||
lock(loadedListLock)
|
|
||||||
{
|
{
|
||||||
Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage);
|
Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage);
|
||||||
loadedListDict.Remove(oldlln.Value.Key);
|
lock (loadedListLock)
|
||||||
|
{
|
||||||
loadedList.Remove(oldlln); //gc should free up memory later..
|
loadedList.Remove(oldlln); //gc should free up memory later..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadedListDict.TryRemove(oldlln.Value.Key, out _);
|
||||||
|
|
||||||
oldlln.Value = null;
|
oldlln.Value = null;
|
||||||
oldlln = null;
|
oldlln = null;
|
||||||
//GC.Collect();
|
//GC.Collect();
|
||||||
@ -99,12 +102,13 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
if (CanAdd()) //see if there's enough memory now...
|
if (CanAdd()) //see if there's enough memory now...
|
||||||
{
|
{
|
||||||
|
LinkedListNode<TVal> newlln;
|
||||||
lock(loadedListLock)
|
lock(loadedListLock)
|
||||||
{
|
{
|
||||||
var newlln = loadedList.AddLast(item);
|
newlln = loadedList.AddLast(item);
|
||||||
loadedListDict.Add(key, newlln);
|
|
||||||
Interlocked.Add(ref CurrentMemoryUsage, item.MemoryUsage);
|
|
||||||
}
|
}
|
||||||
|
loadedListDict.TryAdd(key, newlln);
|
||||||
|
Interlocked.Add(ref CurrentMemoryUsage, item.MemoryUsage);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -127,8 +131,8 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
loadedList.Clear();
|
loadedList.Clear();
|
||||||
loadedListDict.Clear();
|
loadedListDict.Clear();
|
||||||
CurrentMemoryUsage = 0;
|
|
||||||
}
|
}
|
||||||
|
Interlocked.Exchange(ref CurrentMemoryUsage, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(TKey key)
|
public void Remove(TKey key)
|
||||||
@ -137,22 +141,21 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lock(loadedListLock)
|
|
||||||
|
if (loadedListDict.TryRemove(key, out var n))
|
||||||
{
|
{
|
||||||
LinkedListNode<TVal> n;
|
lock (loadedListLock)
|
||||||
if (loadedListDict.TryGetValue(key, out n))
|
|
||||||
{
|
{
|
||||||
loadedListDict.Remove(key);
|
|
||||||
loadedList.Remove(n);
|
loadedList.Remove(n);
|
||||||
Interlocked.Add(ref CurrentMemoryUsage, -n.Value.MemoryUsage);
|
|
||||||
}
|
}
|
||||||
|
Interlocked.Add(ref CurrentMemoryUsage, -n.Value.MemoryUsage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Compact()
|
public void Compact()
|
||||||
{
|
{
|
||||||
lock(loadedList)
|
lock(loadedListLock)
|
||||||
{
|
{
|
||||||
var oldlln = loadedList.First;
|
var oldlln = loadedList.First;
|
||||||
while (oldlln != null)
|
while (oldlln != null)
|
||||||
@ -160,7 +163,7 @@ namespace CodeWalker
|
|||||||
if ((CurrentTime - oldlln.Value.LastUseTime).TotalSeconds < CacheTime) break;
|
if ((CurrentTime - oldlln.Value.LastUseTime).TotalSeconds < CacheTime) break;
|
||||||
var nextln = oldlln.Next;
|
var nextln = oldlln.Next;
|
||||||
Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage);
|
Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage);
|
||||||
loadedListDict.Remove(oldlln.Value.Key);
|
loadedListDict.TryRemove(oldlln.Value.Key, out _);
|
||||||
loadedList.Remove(oldlln); //gc should free up memory later..
|
loadedList.Remove(oldlln); //gc should free up memory later..
|
||||||
|
|
||||||
oldlln.Value = null;
|
oldlln.Value = null;
|
||||||
|
167
CodeWalker.Core/Utils/StreamingExtensions.cs
Normal file
167
CodeWalker.Core/Utils/StreamingExtensions.cs
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CodeWalker.Core.Utils
|
||||||
|
{
|
||||||
|
public static class StreamingExtensions
|
||||||
|
{
|
||||||
|
public static Task<int> ReadAsync(this BinaryReader br, byte[] buffer, int index, int count)
|
||||||
|
{
|
||||||
|
return br.BaseStream.ReadAsync(buffer, index, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void CopyToFast(this Stream stream, Stream destination)
|
||||||
|
{
|
||||||
|
var buffer = ArrayPool<byte>.Shared.Rent(81920);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int read;
|
||||||
|
while ((read = stream.Read(buffer, 0, buffer.Length)) != 0)
|
||||||
|
destination.Write(buffer, 0, read);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task CopyToFastAsync(this Stream stream, Stream destination, int bufferSize = 131072, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task FinishWriteAsync(Task writeTask, byte[] localBuffer)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await writeTask.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
ArrayPool<byte>.Shared.Return(localBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -90,22 +90,33 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
if (bytes == null)
|
if (bytes == null)
|
||||||
{ return string.Empty; } //file not found..
|
{ return string.Empty; } //file not found..
|
||||||
|
var start = 0;
|
||||||
|
var length = bytes.Length;
|
||||||
if ((bytes.Length > 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF))
|
if ((bytes.Length > 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF))
|
||||||
{
|
{
|
||||||
byte[] newb = new byte[bytes.Length - 3];
|
start = 3;
|
||||||
for (int i = 3; i < bytes.Length; i++)
|
length = bytes.Length - 3;
|
||||||
{
|
|
||||||
newb[i - 3] = bytes[i];
|
|
||||||
}
|
}
|
||||||
bytes = newb; //trim starting byte order mark
|
return Encoding.UTF8.GetString(bytes, start, length);
|
||||||
}
|
|
||||||
return Encoding.UTF8.GetString(bytes);
|
|
||||||
}
|
}
|
||||||
public static bool Contains(this string source, string toCheck, StringComparison comp)
|
public static bool Contains(this string source, string toCheck, StringComparison comp)
|
||||||
{
|
{
|
||||||
return source?.IndexOf(toCheck, comp) >= 0;
|
return source?.IndexOf(toCheck, comp) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool EndsWithAny(this string str, params string[] strings)
|
||||||
|
{
|
||||||
|
foreach(var searchString in strings)
|
||||||
|
{
|
||||||
|
if (str.EndsWith(searchString, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -264,6 +275,12 @@ namespace CodeWalker
|
|||||||
public static uint UpdateBit(uint value, int bit, bool flag)
|
public static uint UpdateBit(uint value, int bit, bool flag)
|
||||||
{
|
{
|
||||||
if (flag) return SetBit(value, bit);
|
if (flag) return SetBit(value, bit);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
else return ClearBit(value, bit);
|
else return ClearBit(value, bit);
|
||||||
}
|
}
|
||||||
public static uint RotateLeft(uint value, int count)
|
public static uint RotateLeft(uint value, int count)
|
||||||
@ -275,24 +292,4 @@ namespace CodeWalker
|
|||||||
return (value >> count) | (value << (32 - count));
|
return (value >> count) | (value << (32 - count));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SpanExtensions
|
|
||||||
{
|
|
||||||
public static int Read(this Stream stream, Span<byte> buffer)
|
|
||||||
{
|
|
||||||
var n = Math.Min(stream.Length - stream.Position, buffer.Length);
|
|
||||||
if (n <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < buffer.Length; i++)
|
|
||||||
{
|
|
||||||
var result = stream.ReadByte();
|
|
||||||
buffer[i] = (byte)result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer.Length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -117,6 +117,24 @@ namespace CodeWalker
|
|||||||
return new Vector2I(a.X - b.X, a.Y - b.Y);
|
return new Vector2I(a.X - b.X, a.Y - b.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Vector2I a, Vector2I b)
|
||||||
|
{
|
||||||
|
return a.Equals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Vector2I a, Vector2I b)
|
||||||
|
{
|
||||||
|
return !a.Equals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is null) return false;
|
||||||
|
if (obj is not Vector2I vectorB) return false;
|
||||||
|
|
||||||
|
return vectorB.X == this.X && vectorB.Y == this.Y;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using SharpDX;
|
using CodeWalker.GameFiles;
|
||||||
|
using SharpDX;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -6,11 +7,27 @@ using System.Text;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace CodeWalker
|
namespace CodeWalker
|
||||||
{
|
{
|
||||||
public static class Xml
|
public static class Xml
|
||||||
{
|
{
|
||||||
|
public static void ValidateReaderState(XmlReader reader, string element)
|
||||||
|
{
|
||||||
|
if (reader == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(reader));
|
||||||
|
}
|
||||||
|
if (!reader.IsStartElement())
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Expected reader to be at a start element but was at \"{reader.NodeType}\" with name \"{reader.Name}\"");
|
||||||
|
}
|
||||||
|
if (reader.Name != element)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Expected reader to be at start element of \"{element}\" but was at \"{reader.NodeType}\" with name \"{reader.Name}\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetStringAttribute(XmlNode node, string attribute)
|
public static string GetStringAttribute(XmlNode node, string attribute)
|
||||||
{
|
{
|
||||||
@ -63,6 +80,55 @@ namespace CodeWalker
|
|||||||
if (node == null) return null;
|
if (node == null) return null;
|
||||||
return node.SelectSingleNode(name)?.InnerText;
|
return node.SelectSingleNode(name)?.InnerText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetChildInnerText(XElement node, string name) {
|
||||||
|
if (node == null) return null;
|
||||||
|
return node.Element(name).Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetChildInnerText(XmlReader reader, string name)
|
||||||
|
{
|
||||||
|
ValidateReaderState(reader, name);
|
||||||
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
if (reader.IsEmptyElement)
|
||||||
|
{
|
||||||
|
reader.ReadStartElement();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return reader.ReadElementContentAsString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return reader.ReadContentAsString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetChildBoolInnerText(XElement node, string name)
|
||||||
|
{
|
||||||
|
if (node == null) return false;
|
||||||
|
string val = node.Element(name).Value;
|
||||||
|
|
||||||
|
bool b;
|
||||||
|
bool.TryParse(val, out b);
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool GetChildBoolInnerText(XmlReader reader, string name)
|
||||||
|
{
|
||||||
|
ValidateReaderState(reader, name);
|
||||||
|
if (reader.NodeType == XmlNodeType.Element)
|
||||||
|
{
|
||||||
|
return reader.ReadElementContentAsBoolean();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return reader.ReadContentAsBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public static bool GetChildBoolInnerText(XmlNode node, string name)
|
public static bool GetChildBoolInnerText(XmlNode node, string name)
|
||||||
{
|
{
|
||||||
if (node == null) return false;
|
if (node == null) return false;
|
||||||
@ -87,6 +153,14 @@ namespace CodeWalker
|
|||||||
FloatUtil.TryParse(val, out f);
|
FloatUtil.TryParse(val, out f);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float GetChildFloatInnerText(XmlReader reader, string name)
|
||||||
|
{
|
||||||
|
ValidateReaderState(reader, name);
|
||||||
|
|
||||||
|
return reader.ReadElementContentAsFloat();
|
||||||
|
}
|
||||||
|
|
||||||
public static T GetChildEnumInnerText<T>(XmlNode node, string name) where T : struct
|
public static T GetChildEnumInnerText<T>(XmlNode node, string name) where T : struct
|
||||||
{
|
{
|
||||||
if (node == null) return new T();
|
if (node == null) return new T();
|
||||||
@ -99,7 +173,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
return default(T);
|
return default(T);
|
||||||
}
|
}
|
||||||
if (val.StartsWith("hash_"))
|
if (val.StartsWith("hash_", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
//convert hash_12ABC to Unk_12345
|
//convert hash_12ABC to Unk_12345
|
||||||
var substr = val.Substring(5);
|
var substr = val.Substring(5);
|
||||||
@ -111,7 +185,18 @@ namespace CodeWalker
|
|||||||
return enumval;
|
return enumval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool GetChildBoolAttribute(XmlReader reader, string name, string attribute = "value")
|
||||||
|
{
|
||||||
|
ValidateReaderState(reader, name);
|
||||||
|
|
||||||
|
string val = reader.GetAttribute(attribute);
|
||||||
|
|
||||||
|
bool.TryParse(val, out bool boolval);
|
||||||
|
|
||||||
|
reader.ReadStartElement();
|
||||||
|
|
||||||
|
return boolval;
|
||||||
|
}
|
||||||
public static bool GetChildBoolAttribute(XmlNode node, string name, string attribute = "value")
|
public static bool GetChildBoolAttribute(XmlNode node, string name, string attribute = "value")
|
||||||
{
|
{
|
||||||
if (node == null) return false;
|
if (node == null) return false;
|
||||||
@ -120,6 +205,20 @@ namespace CodeWalker
|
|||||||
bool.TryParse(val, out b);
|
bool.TryParse(val, out b);
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int GetChildIntAttribute(XmlReader reader, string name, string attribute = "value")
|
||||||
|
{
|
||||||
|
ValidateReaderState(reader, name);
|
||||||
|
|
||||||
|
string val = reader.GetAttribute(attribute);
|
||||||
|
|
||||||
|
int.TryParse(val, out var i);
|
||||||
|
|
||||||
|
reader.ReadStartElement();
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
public static int GetChildIntAttribute(XmlNode node, string name, string attribute = "value")
|
public static int GetChildIntAttribute(XmlNode node, string name, string attribute = "value")
|
||||||
{
|
{
|
||||||
if (node == null) return 0;
|
if (node == null) return 0;
|
||||||
@ -128,12 +227,31 @@ namespace CodeWalker
|
|||||||
int.TryParse(val, out i);
|
int.TryParse(val, out i);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static uint GetChildUIntAttribute(XmlReader reader, string name, string attribute = "value")
|
||||||
|
{
|
||||||
|
if (reader == null) return 0;
|
||||||
|
|
||||||
|
uint i;
|
||||||
|
string val = reader.GetAttribute(attribute);
|
||||||
|
if (val?.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ?? false)
|
||||||
|
{
|
||||||
|
var subs = val.Substring(2);
|
||||||
|
i = Convert.ToUInt32(subs, 16);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint.TryParse(val, out i);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
public static uint GetChildUIntAttribute(XmlNode node, string name, string attribute = "value")
|
public static uint GetChildUIntAttribute(XmlNode node, string name, string attribute = "value")
|
||||||
{
|
{
|
||||||
if (node == null) return 0;
|
if (node == null) return 0;
|
||||||
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
|
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
|
||||||
uint i;
|
uint i;
|
||||||
if (val?.StartsWith("0x") ?? false)
|
if (val?.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ?? false)
|
||||||
{
|
{
|
||||||
var subs = val.Substring(2);
|
var subs = val.Substring(2);
|
||||||
i = Convert.ToUInt32(subs, 16);
|
i = Convert.ToUInt32(subs, 16);
|
||||||
@ -149,7 +267,7 @@ namespace CodeWalker
|
|||||||
if (node == null) return 0;
|
if (node == null) return 0;
|
||||||
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
|
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
|
||||||
ulong i;
|
ulong i;
|
||||||
if (val?.StartsWith("0x") ?? false)
|
if (val?.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ?? false)
|
||||||
{
|
{
|
||||||
var subs = val.Substring(2);
|
var subs = val.Substring(2);
|
||||||
i = Convert.ToUInt64(subs, 16);
|
i = Convert.ToUInt64(subs, 16);
|
||||||
@ -160,6 +278,26 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float GetChildFloatAttribute(XmlReader reader, string name, string attribute = "value")
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
ValidateReaderState(reader, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
string val = reader.GetAttribute(attribute);
|
||||||
|
|
||||||
|
FloatUtil.TryParse(val, out float f);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
reader.ReadStartElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
public static float GetChildFloatAttribute(XmlNode node, string name, string attribute = "value")
|
public static float GetChildFloatAttribute(XmlNode node, string name, string attribute = "value")
|
||||||
{
|
{
|
||||||
if (node == null) return 0;
|
if (node == null) return 0;
|
||||||
@ -174,12 +312,37 @@ namespace CodeWalker
|
|||||||
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
|
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetChildStringAttribute(XmlReader reader, string name, string attribute = "value")
|
||||||
|
{
|
||||||
|
ValidateReaderState(reader, name);
|
||||||
|
|
||||||
|
var val = reader.GetAttribute(attribute);
|
||||||
|
|
||||||
|
reader.ReadStartElement();
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
public static Vector2 GetChildVector2Attributes(XmlNode node, string name, string x = "x", string y = "y")
|
public static Vector2 GetChildVector2Attributes(XmlNode node, string name, string x = "x", string y = "y")
|
||||||
{
|
{
|
||||||
float fx = GetChildFloatAttribute(node, name, x);
|
float fx = GetChildFloatAttribute(node, name, x);
|
||||||
float fy = GetChildFloatAttribute(node, name, y);
|
float fy = GetChildFloatAttribute(node, name, y);
|
||||||
return new Vector2(fx, fy);
|
return new Vector2(fx, fy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vector3 GetChildVector3Attributes(XmlReader reader, string name, string x = "x", string y = "y", string z = "z")
|
||||||
|
{
|
||||||
|
ValidateReaderState(reader, name);
|
||||||
|
float fx = GetChildFloatAttribute(reader, null, x);
|
||||||
|
float fy = GetChildFloatAttribute(reader, null, y);
|
||||||
|
float fz = GetChildFloatAttribute(reader, null, z);
|
||||||
|
|
||||||
|
reader.ReadStartElement();
|
||||||
|
|
||||||
|
return new Vector3(fx, fy, fz);
|
||||||
|
}
|
||||||
|
|
||||||
public static Vector3 GetChildVector3Attributes(XmlNode node, string name, string x = "x", string y = "y", string z = "z")
|
public static Vector3 GetChildVector3Attributes(XmlNode node, string name, string x = "x", string y = "y", string z = "z")
|
||||||
{
|
{
|
||||||
float fx = GetChildFloatAttribute(node, name, x);
|
float fx = GetChildFloatAttribute(node, name, x);
|
||||||
@ -207,6 +370,37 @@ namespace CodeWalker
|
|||||||
node.AppendChild(child);
|
node.AppendChild(child);
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool IsItemElement(this XmlReader reader)
|
||||||
|
{
|
||||||
|
if (reader.MoveToContent() == XmlNodeType.Element && reader.Name == "Item")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<XElement> IterateItems(XmlReader reader, string parentElementName)
|
||||||
|
{
|
||||||
|
ValidateReaderState(reader, parentElementName);
|
||||||
|
reader.MoveToContent();
|
||||||
|
if (reader.IsEmptyElement)
|
||||||
|
{
|
||||||
|
// Move past empty element
|
||||||
|
reader.ReadStartElement(parentElementName);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
reader.ReadStartElement(parentElementName);
|
||||||
|
while(reader.IsItemElement())
|
||||||
|
{
|
||||||
|
if (XNode.ReadFrom(reader) is XElement el)
|
||||||
|
{
|
||||||
|
yield return el;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reader.ReadEndElement();
|
||||||
|
}
|
||||||
public static XmlElement AddChildWithInnerText(XmlDocument doc, XmlNode node, string name, string innerText)
|
public static XmlElement AddChildWithInnerText(XmlDocument doc, XmlNode node, string name, string innerText)
|
||||||
{
|
{
|
||||||
XmlElement child = AddChild(doc, node, name);
|
XmlElement child = AddChild(doc, node, name);
|
||||||
|
@ -33,6 +33,9 @@ namespace CodeWalker.World
|
|||||||
|
|
||||||
List<AudioPlacement> placements = new List<AudioPlacement>();
|
List<AudioPlacement> placements = new List<AudioPlacement>();
|
||||||
|
|
||||||
|
GameFileCache.AudioDatRelFilesLock.EnterReadLock();
|
||||||
|
try
|
||||||
|
{
|
||||||
foreach (var relfile in GameFileCache.AudioDatRelFiles)
|
foreach (var relfile in GameFileCache.AudioDatRelFiles)
|
||||||
{
|
{
|
||||||
if (relfile == null) continue;
|
if (relfile == null) continue;
|
||||||
@ -43,6 +46,11 @@ namespace CodeWalker.World
|
|||||||
|
|
||||||
PlacementsDict[relfile] = placements.ToArray();
|
PlacementsDict[relfile] = placements.ToArray();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
GameFileCache.AudioDatRelFilesLock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
AllItems.AddRange(Zones);
|
AllItems.AddRange(Zones);
|
||||||
AllItems.AddRange(Emitters);
|
AllItems.AddRange(Emitters);
|
||||||
|
@ -1799,7 +1799,6 @@ namespace CodeWalker.World
|
|||||||
|
|
||||||
var noneset = new AmbientModelSet();
|
var noneset = new AmbientModelSet();
|
||||||
noneset.Name = "NONE";
|
noneset.Name = "NONE";
|
||||||
noneset.NameLower = "none";
|
|
||||||
noneset.NameHash = JenkHash.GenHash("none");
|
noneset.NameHash = JenkHash.GenHash("none");
|
||||||
sets[noneset.NameHash] = noneset;
|
sets[noneset.NameHash] = noneset;
|
||||||
|
|
||||||
@ -1808,10 +1807,10 @@ namespace CodeWalker.World
|
|||||||
{
|
{
|
||||||
AmbientModelSet set = new AmbientModelSet();
|
AmbientModelSet set = new AmbientModelSet();
|
||||||
set.Load(item);
|
set.Load(item);
|
||||||
if (!string.IsNullOrEmpty(set.NameLower))
|
if (!string.IsNullOrEmpty(set.Name))
|
||||||
{
|
{
|
||||||
JenkIndex.Ensure(set.NameLower);
|
uint hash = JenkHash.GenHashLower(set.Name);
|
||||||
uint hash = JenkHash.GenHash(set.NameLower);
|
JenkIndex.Ensure(set.Name, hash);
|
||||||
sets[hash] = set;
|
sets[hash] = set;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1837,11 +1836,12 @@ namespace CodeWalker.World
|
|||||||
{
|
{
|
||||||
ConditionalAnimsGroup group = new ConditionalAnimsGroup();
|
ConditionalAnimsGroup group = new ConditionalAnimsGroup();
|
||||||
group.Load(item);
|
group.Load(item);
|
||||||
if (!string.IsNullOrEmpty(group.NameLower))
|
if (!string.IsNullOrEmpty(group.Name))
|
||||||
{
|
{
|
||||||
|
uint hash = JenkHash.GenHashLower(group.Name);
|
||||||
JenkIndex.Ensure(group.Name);
|
JenkIndex.Ensure(group.Name);
|
||||||
JenkIndex.Ensure(group.NameLower);
|
JenkIndex.Ensure(group.Name, hash);
|
||||||
uint hash = JenkHash.GenHash(group.NameLower);
|
|
||||||
groups[hash] = group;
|
groups[hash] = group;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1903,7 +1903,6 @@ namespace CodeWalker.World
|
|||||||
string s_hash = hash.ToString("X");
|
string s_hash = hash.ToString("X");
|
||||||
ms = new AmbientModelSet();
|
ms = new AmbientModelSet();
|
||||||
ms.Name = $"UNKNOWN PED MODELSET ({s_hash})";
|
ms.Name = $"UNKNOWN PED MODELSET ({s_hash})";
|
||||||
ms.NameLower = ms.Name.ToLowerInvariant();
|
|
||||||
ms.NameHash = new MetaHash(hash);
|
ms.NameHash = new MetaHash(hash);
|
||||||
ms.Models = new AmbientModel[] { };
|
ms.Models = new AmbientModel[] { };
|
||||||
PedModelSets.Add(hash, ms);
|
PedModelSets.Add(hash, ms);
|
||||||
@ -1922,7 +1921,6 @@ namespace CodeWalker.World
|
|||||||
string s_hash = hash.ToString("X");
|
string s_hash = hash.ToString("X");
|
||||||
ms = new AmbientModelSet();
|
ms = new AmbientModelSet();
|
||||||
ms.Name = $"UNKNOWN VEHICLE MODELSET ({s_hash})";
|
ms.Name = $"UNKNOWN VEHICLE MODELSET ({s_hash})";
|
||||||
ms.NameLower = ms.Name.ToLowerInvariant();
|
|
||||||
ms.NameHash = new MetaHash(hash);
|
ms.NameHash = new MetaHash(hash);
|
||||||
ms.Models = new AmbientModel[] {};
|
ms.Models = new AmbientModel[] {};
|
||||||
VehicleModelSets.Add(hash, ms);
|
VehicleModelSets.Add(hash, ms);
|
||||||
@ -2110,7 +2108,6 @@ namespace CodeWalker.World
|
|||||||
[TypeConverter(typeof(ExpandableObjectConverter))] public class AmbientModelSet
|
[TypeConverter(typeof(ExpandableObjectConverter))] public class AmbientModelSet
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string NameLower { get; set; }
|
|
||||||
public MetaHash NameHash { get; set; }
|
public MetaHash NameHash { get; set; }
|
||||||
public AmbientModel[] Models { get; set; }
|
public AmbientModel[] Models { get; set; }
|
||||||
|
|
||||||
@ -2118,8 +2115,7 @@ namespace CodeWalker.World
|
|||||||
public void Load(XmlNode node)
|
public void Load(XmlNode node)
|
||||||
{
|
{
|
||||||
Name = Xml.GetChildInnerText(node, "Name");
|
Name = Xml.GetChildInnerText(node, "Name");
|
||||||
NameLower = Name.ToLowerInvariant();
|
NameHash = JenkHash.GenHashLower(Name);
|
||||||
NameHash = JenkHash.GenHash(NameLower);
|
|
||||||
|
|
||||||
var models = node.SelectNodes("Models/Item");
|
var models = node.SelectNodes("Models/Item");
|
||||||
var modellist = new List<AmbientModel>();
|
var modellist = new List<AmbientModel>();
|
||||||
@ -2190,14 +2186,12 @@ namespace CodeWalker.World
|
|||||||
{
|
{
|
||||||
public string OuterXml { get; set; }
|
public string OuterXml { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string NameLower { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
public void Load(XmlNode node)
|
public void Load(XmlNode node)
|
||||||
{
|
{
|
||||||
OuterXml = node.OuterXml;
|
OuterXml = node.OuterXml;
|
||||||
Name = Xml.GetChildInnerText(node, "Name");
|
Name = Xml.GetChildInnerText(node, "Name");
|
||||||
NameLower = Name.ToLowerInvariant();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
|
@ -277,7 +277,7 @@ namespace CodeWalker.World
|
|||||||
{
|
{
|
||||||
foreach (var entry in maprpf.AllEntries)
|
foreach (var entry in maprpf.AllEntries)
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".ymap"))
|
if (entry.IsExtension(".ymap"))
|
||||||
{
|
{
|
||||||
if (!nodedict.ContainsKey(new MetaHash(entry.ShortNameHash)))
|
if (!nodedict.ContainsKey(new MetaHash(entry.ShortNameHash)))
|
||||||
{
|
{
|
||||||
@ -297,7 +297,7 @@ namespace CodeWalker.World
|
|||||||
{ }
|
{ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entry.NameLower.EndsWith(".ybn"))
|
if (entry.IsExtension(".ybn"))
|
||||||
{
|
{
|
||||||
MetaHash ehash = new MetaHash(entry.ShortNameHash);
|
MetaHash ehash = new MetaHash(entry.ShortNameHash);
|
||||||
if (!usedboundsdict.ContainsKey(ehash))
|
if (!usedboundsdict.ContainsKey(ehash))
|
||||||
@ -367,7 +367,7 @@ namespace CodeWalker.World
|
|||||||
}
|
}
|
||||||
foreach (var dlcrpf in GameFileCache.DlcActiveRpfs) //load nodes from current dlc rpfs
|
foreach (var dlcrpf in GameFileCache.DlcActiveRpfs) //load nodes from current dlc rpfs
|
||||||
{
|
{
|
||||||
if (dlcrpf.Path.StartsWith("x64")) continue; //don't override update.rpf YNDs with x64 ones! *hack
|
if (dlcrpf.Path.StartsWith("x64", StringComparison.OrdinalIgnoreCase)) continue; //don't override update.rpf YNDs with x64 ones! *hack
|
||||||
foreach (var rpffile in dlcrpf.Children)
|
foreach (var rpffile in dlcrpf.Children)
|
||||||
{
|
{
|
||||||
AddRpfYnds(rpffile, yndentries);
|
AddRpfYnds(rpffile, yndentries);
|
||||||
@ -509,7 +509,7 @@ namespace CodeWalker.World
|
|||||||
if (entry is RpfFileEntry)
|
if (entry is RpfFileEntry)
|
||||||
{
|
{
|
||||||
RpfFileEntry fentry = entry as RpfFileEntry;
|
RpfFileEntry fentry = entry as RpfFileEntry;
|
||||||
if (entry.NameLower.EndsWith(".ynd"))
|
if (entry.IsExtension(".ynd"))
|
||||||
{
|
{
|
||||||
if (yndentries.ContainsKey(entry.NameHash))
|
if (yndentries.ContainsKey(entry.NameHash))
|
||||||
{ }
|
{ }
|
||||||
@ -809,7 +809,7 @@ namespace CodeWalker.World
|
|||||||
if (entry is RpfFileEntry)
|
if (entry is RpfFileEntry)
|
||||||
{
|
{
|
||||||
RpfFileEntry fentry = entry as RpfFileEntry;
|
RpfFileEntry fentry = entry as RpfFileEntry;
|
||||||
if (entry.NameLower.EndsWith(".ynv"))
|
if (entry.IsExtension(".ynv"))
|
||||||
{
|
{
|
||||||
if (ynventries.ContainsKey(entry.NameHash))
|
if (ynventries.ContainsKey(entry.NameHash))
|
||||||
{ }
|
{ }
|
||||||
|
@ -38,7 +38,7 @@ namespace CodeWalker.World
|
|||||||
{
|
{
|
||||||
foreach (var file in dlcrpf.AllEntries)
|
foreach (var file in dlcrpf.AllEntries)
|
||||||
{
|
{
|
||||||
if (file.NameLower.EndsWith(".xml") && file.NameLower.StartsWith("timecycle_mods_"))
|
if (file.IsExtension(".xml") && file.Name.StartsWith("timecycle_mods_", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
LoadXml(rpfman.GetFileXml(file.Path));
|
LoadXml(rpfman.GetFileXml(file.Path));
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using CodeWalker.Utils;
|
using CodeWalker.Utils;
|
||||||
|
using CodeWalker.Core.Utils;
|
||||||
|
|
||||||
namespace CodeWalker.RPFExplorer
|
namespace CodeWalker.RPFExplorer
|
||||||
{
|
{
|
||||||
@ -18,13 +19,31 @@ namespace CodeWalker.RPFExplorer
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
static void Main()
|
static void Main()
|
||||||
{
|
{
|
||||||
//Process.Start("CodeWalker.exe", "explorer");
|
try
|
||||||
|
{
|
||||||
|
if (!NamedPipe.TrySendMessageToOtherProcess("explorer"))
|
||||||
|
{
|
||||||
ConsoleWindow.Hide();
|
ConsoleWindow.Hide();
|
||||||
|
//Process.Start("CodeWalker.exe", "explorer");
|
||||||
Application.EnableVisualStyles();
|
Application.EnableVisualStyles();
|
||||||
Application.SetCompatibleTextRenderingDefault(false);
|
Application.SetCompatibleTextRenderingDefault(false);
|
||||||
Application.Run(new ExploreForm());
|
|
||||||
|
var form = new ExploreForm();
|
||||||
|
var namedPipe = new NamedPipe(form);
|
||||||
|
namedPipe.Init();
|
||||||
|
|
||||||
|
Application.Run(form);
|
||||||
|
|
||||||
GTAFolder.UpdateSettings();
|
GTAFolder.UpdateSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.ToString());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
12
CodeWalker.Test/BinaryPrimitesFloats.cs
Normal file
12
CodeWalker.Test/BinaryPrimitesFloats.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace CodeWalker.Test
|
||||||
|
{
|
||||||
|
internal class BinaryPrimitesFloats
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
30
CodeWalker.Test/CodeWalker.Test.csproj
Normal file
30
CodeWalker.Test/CodeWalker.Test.csproj
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net48</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<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>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.1.0">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\CodeWalker.Core\CodeWalker.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
96
CodeWalker.Test/JenkGenTests.cs
Normal file
96
CodeWalker.Test/JenkGenTests.cs
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
using CodeWalker.GameFiles;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace CodeWalker.Test
|
||||||
|
{
|
||||||
|
public class JenkGenTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void GenHashMustReturnHash()
|
||||||
|
{
|
||||||
|
Assert.Equal((uint)1044535224, JenkHash.GenHash("ASDF"));
|
||||||
|
|
||||||
|
Assert.Equal((uint)1485398060, JenkHash.GenHashLower("asdf"));
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
public void EnsureMustAddStringToDictionary()
|
||||||
|
{
|
||||||
|
JenkIndex.Index.Clear();
|
||||||
|
Assert.Empty(JenkIndex.Index);
|
||||||
|
JenkIndex.Ensure("asdf");
|
||||||
|
|
||||||
|
Assert.Single(JenkIndex.Index);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetStringWithMissingHashMustReturnEmptyString()
|
||||||
|
{
|
||||||
|
JenkIndex.Index.Clear();
|
||||||
|
Assert.Empty(JenkIndex.Index);
|
||||||
|
|
||||||
|
var str = JenkIndex.TryGetString((uint)1485398060);
|
||||||
|
|
||||||
|
Assert.Equal(string.Empty, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetStringWithMissingHashMustReturnHashAsString()
|
||||||
|
{
|
||||||
|
JenkIndex.Index.Clear();
|
||||||
|
Assert.Empty(JenkIndex.Index);
|
||||||
|
|
||||||
|
var str = JenkIndex.GetString((uint)1485398060);
|
||||||
|
|
||||||
|
Assert.Equal(1485398060.ToString(), str);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TryGetStringMustReturnAddedString()
|
||||||
|
{
|
||||||
|
JenkIndex.Ensure("asdf");
|
||||||
|
|
||||||
|
var str = JenkIndex.TryGetString((uint)1485398060);
|
||||||
|
|
||||||
|
Assert.Equal("asdf", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void EnsureLowerMustAddLoweredStringToDictionary()
|
||||||
|
{
|
||||||
|
JenkIndex.Index.Clear();
|
||||||
|
Assert.Empty(JenkIndex.Index);
|
||||||
|
JenkIndex.EnsureLower("ASDF");
|
||||||
|
|
||||||
|
Assert.Single(JenkIndex.Index);
|
||||||
|
|
||||||
|
var str = JenkIndex.TryGetString((uint)1485398060);
|
||||||
|
|
||||||
|
Assert.Equal("ASDF", str);
|
||||||
|
|
||||||
|
var missingStr = JenkIndex.TryGetString((uint)1044535224);
|
||||||
|
Assert.Equal(string.Empty, missingStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetStringMustReturnAddedString()
|
||||||
|
{
|
||||||
|
JenkIndex.Index.Clear();
|
||||||
|
Assert.Empty(JenkIndex.Index);
|
||||||
|
JenkIndex.EnsureLower("ASDF");
|
||||||
|
|
||||||
|
Assert.Single(JenkIndex.Index);
|
||||||
|
|
||||||
|
var str = JenkIndex.TryGetString((uint)1485398060);
|
||||||
|
|
||||||
|
Assert.Equal("ASDF", str);
|
||||||
|
|
||||||
|
var missingStr = JenkIndex.TryGetString((uint)1044535224);
|
||||||
|
Assert.Equal(string.Empty, missingStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
445
CodeWalker.Test/TestBinaryConversions.cs
Normal file
445
CodeWalker.Test/TestBinaryConversions.cs
Normal file
File diff suppressed because one or more lines are too long
1081
CodeWalker.Test/XmlTests.cs
Normal file
1081
CodeWalker.Test/XmlTests.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,16 +1,20 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>net48</TargetFramework>
|
<TargetFramework>net48</TargetFramework>
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DockPanelSuite.ThemeVS2015" Version="3.0.6" />
|
<PackageReference Include="DockPanelSuite.ThemeVS2015" Version="3.0.6" />
|
||||||
<PackageReference Include="SharpDX" Version="4.2.0" />
|
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 16.0.29806.167
|
VisualStudioVersion = 17.7.34031.279
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CodeWalker.Shaders", "CodeWalker.Shaders\CodeWalker.Shaders.vcxproj", "{0D14B076-0ABF-434E-AB9F-36E7800D8887}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CodeWalker.Shaders", "CodeWalker.Shaders\CodeWalker.Shaders.vcxproj", "{0D14B076-0ABF-434E-AB9F-36E7800D8887}"
|
||||||
EndProject
|
EndProject
|
||||||
@ -23,6 +23,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeWalker.RPFExplorer", "C
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeWalker.Vehicles", "CodeWalker.Vehicles\CodeWalker.Vehicles.csproj", "{F5A776B0-2F1A-4C36-87B3-86206AC4B439}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeWalker.Vehicles", "CodeWalker.Vehicles\CodeWalker.Vehicles.csproj", "{F5A776B0-2F1A-4C36-87B3-86206AC4B439}"
|
||||||
EndProject
|
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}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -128,6 +132,30 @@ Global
|
|||||||
{F5A776B0-2F1A-4C36-87B3-86206AC4B439}.Release|x64.Build.0 = Release|Any CPU
|
{F5A776B0-2F1A-4C36-87B3-86206AC4B439}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{F5A776B0-2F1A-4C36-87B3-86206AC4B439}.Release|x86.ActiveCfg = Release|Any CPU
|
{F5A776B0-2F1A-4C36-87B3-86206AC4B439}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{F5A776B0-2F1A-4C36-87B3-86206AC4B439}.Release|x86.Build.0 = Release|Any CPU
|
{F5A776B0-2F1A-4C36-87B3-86206AC4B439}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{067FF87E-CA79-4B29-BCF6-11622999EDC6}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{EDDA8A8E-5333-4E28-8221-A31E3B70EB7A}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -15,11 +15,17 @@
|
|||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||||
<PlatformTarget>x64</PlatformTarget>
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<PlatformTarget>x64</PlatformTarget>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DockPanelSuite.ThemeVS2015" Version="3.0.6" />
|
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
|
||||||
|
<PackageReference Include="DirectXTexNet" Version="1.0.1" />
|
||||||
|
<PackageReference Include="DockPanelSuite.ThemeVS2015" Version="3.1.0" />
|
||||||
<PackageReference Include="FCTB" Version="2.16.24" />
|
<PackageReference Include="FCTB" Version="2.16.24" />
|
||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="SharpDX" Version="4.2.0" />
|
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||||
<PackageReference Include="SharpDX.D3DCompiler" Version="4.2.0" />
|
<PackageReference Include="SharpDX.D3DCompiler" Version="4.2.0" />
|
||||||
<PackageReference Include="SharpDX.Direct2D1" Version="4.2.0" />
|
<PackageReference Include="SharpDX.Direct2D1" Version="4.2.0" />
|
||||||
|
16
CodeWalker/ExploreForm.Designer.cs
generated
16
CodeWalker/ExploreForm.Designer.cs
generated
@ -1,4 +1,7 @@
|
|||||||
using CodeWalker.Core.Utils;
|
using CodeWalker.Core.Utils;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
using CodeWalker.WinForms;
|
||||||
|
|
||||||
namespace CodeWalker
|
namespace CodeWalker
|
||||||
{
|
{
|
||||||
@ -15,11 +18,13 @@ namespace CodeWalker
|
|||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
using var _ = new DisposableTimer("ExploreForm Dipose");
|
||||||
|
base.Dispose(disposing);
|
||||||
|
MainListView.Dispose();
|
||||||
if (disposing && (components != null))
|
if (disposing && (components != null))
|
||||||
{
|
{
|
||||||
components.Dispose();
|
components.Dispose();
|
||||||
}
|
}
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Windows Form Designer generated code
|
#region Windows Form Designer generated code
|
||||||
@ -121,6 +126,7 @@ namespace CodeWalker
|
|||||||
this.ListContextViewHexMenu = new System.Windows.Forms.ToolStripMenuItem();
|
this.ListContextViewHexMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||||
this.ListContextExportXmlMenu = new System.Windows.Forms.ToolStripMenuItem();
|
this.ListContextExportXmlMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
|
this.ListContextExtractShadersMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.ListContextExtractRawMenu = new System.Windows.Forms.ToolStripMenuItem();
|
this.ListContextExtractRawMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.ListContextExtractUncompressedMenu = new System.Windows.Forms.ToolStripMenuItem();
|
this.ListContextExtractUncompressedMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
this.ListContextExtractAllMenu = new System.Windows.Forms.ToolStripMenuItem();
|
this.ListContextExtractAllMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||||
@ -990,6 +996,7 @@ namespace CodeWalker
|
|||||||
this.ListContextViewMenu,
|
this.ListContextViewMenu,
|
||||||
this.ListContextViewHexMenu,
|
this.ListContextViewHexMenu,
|
||||||
this.toolStripSeparator2,
|
this.toolStripSeparator2,
|
||||||
|
this.ListContextExtractShadersMenu,
|
||||||
this.ListContextExportXmlMenu,
|
this.ListContextExportXmlMenu,
|
||||||
this.ListContextExtractRawMenu,
|
this.ListContextExtractRawMenu,
|
||||||
this.ListContextExtractUncompressedMenu,
|
this.ListContextExtractUncompressedMenu,
|
||||||
@ -1047,6 +1054,12 @@ namespace CodeWalker
|
|||||||
this.ListContextExportXmlMenu.Size = new System.Drawing.Size(208, 22);
|
this.ListContextExportXmlMenu.Size = new System.Drawing.Size(208, 22);
|
||||||
this.ListContextExportXmlMenu.Text = "Export XML...";
|
this.ListContextExportXmlMenu.Text = "Export XML...";
|
||||||
this.ListContextExportXmlMenu.Click += new System.EventHandler(this.ListContextExportXmlMenu_Click);
|
this.ListContextExportXmlMenu.Click += new System.EventHandler(this.ListContextExportXmlMenu_Click);
|
||||||
|
this.ListContextExtractShadersMenu.Image = ((System.Drawing.Image)(resources.GetObject("ListContextExportXmlMenu.Image")));
|
||||||
|
this.ListContextExtractShadersMenu.Name = "ListContextExportShadersMenu";
|
||||||
|
this.ListContextExtractShadersMenu.ShortcutKeyDisplayString = "Ctrl+S";
|
||||||
|
this.ListContextExtractShadersMenu.Size = new System.Drawing.Size(208, 22);
|
||||||
|
this.ListContextExtractShadersMenu.Text = "Export Shaders...";
|
||||||
|
this.ListContextExtractShadersMenu.Click += new System.EventHandler(this.ListContextExportShaders_Click);
|
||||||
//
|
//
|
||||||
// ListContextExtractRawMenu
|
// ListContextExtractRawMenu
|
||||||
//
|
//
|
||||||
@ -1394,6 +1407,7 @@ namespace CodeWalker
|
|||||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
||||||
private System.Windows.Forms.ToolStripMenuItem ListContextExportXmlMenu;
|
private System.Windows.Forms.ToolStripMenuItem ListContextExportXmlMenu;
|
||||||
private System.Windows.Forms.ToolStripMenuItem ListContextExtractAllMenu;
|
private System.Windows.Forms.ToolStripMenuItem ListContextExtractAllMenu;
|
||||||
|
private System.Windows.Forms.ToolStripMenuItem ListContextExtractShadersMenu;
|
||||||
private System.Windows.Forms.ToolStripSeparator ListContextImportSeparator;
|
private System.Windows.Forms.ToolStripSeparator ListContextImportSeparator;
|
||||||
private System.Windows.Forms.ToolStripMenuItem ListContextCopyPathMenu;
|
private System.Windows.Forms.ToolStripMenuItem ListContextCopyPathMenu;
|
||||||
private System.Windows.Forms.ToolStripSeparator ListContextEditSeparator;
|
private System.Windows.Forms.ToolStripSeparator ListContextEditSeparator;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,7 @@ using System.Windows.Forms;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Range = FastColoredTextBoxNS.Range;
|
using Range = FastColoredTextBoxNS.Range;
|
||||||
|
using CodeWalker.Core.Utils;
|
||||||
|
|
||||||
namespace CodeWalker.Forms
|
namespace CodeWalker.Forms
|
||||||
{
|
{
|
||||||
@ -400,7 +401,7 @@ namespace CodeWalker.Forms
|
|||||||
{
|
{
|
||||||
Stream wavStream = audio.GetWavStream();
|
Stream wavStream = audio.GetWavStream();
|
||||||
FileStream stream = File.Create(saveFileDialog.FileName);
|
FileStream stream = File.Create(saveFileDialog.FileName);
|
||||||
wavStream.CopyTo(stream);
|
wavStream.CopyToFast(stream);
|
||||||
stream.Close();
|
stream.Close();
|
||||||
wavStream.Close();
|
wavStream.Close();
|
||||||
}
|
}
|
||||||
|
@ -25,14 +25,11 @@ namespace CodeWalker.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
public string FilePath { get; set; }
|
public string FilePath { get; set; }
|
||||||
|
|
||||||
ExploreForm ExploreForm;
|
|
||||||
object CurrentFile;
|
object CurrentFile;
|
||||||
|
|
||||||
|
|
||||||
public GenericForm(ExploreForm exploreForm)
|
public GenericForm()
|
||||||
{
|
{
|
||||||
ExploreForm = exploreForm;
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,16 +45,12 @@ namespace CodeWalker.Forms
|
|||||||
private bool LoadingXml = false;
|
private bool LoadingXml = false;
|
||||||
private bool DelayHighlight = false;
|
private bool DelayHighlight = false;
|
||||||
|
|
||||||
|
|
||||||
private ExploreForm exploreForm = null;
|
|
||||||
public RpfFileEntry rpfFileEntry { get; private set; } = null;
|
public RpfFileEntry rpfFileEntry { get; private set; } = null;
|
||||||
private MetaFormat metaFormat = MetaFormat.XML;
|
private MetaFormat metaFormat = MetaFormat.XML;
|
||||||
|
|
||||||
|
|
||||||
public MetaForm(ExploreForm owner)
|
public MetaForm()
|
||||||
{
|
{
|
||||||
exploreForm = owner;
|
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,6 +413,68 @@ namespace CodeWalker.Forms
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void LoadMeta(PackedFile gameFile)
|
||||||
|
{
|
||||||
|
gameFile = gameFile ?? throw new ArgumentNullException(nameof(gameFile));
|
||||||
|
|
||||||
|
if (gameFile is YmfFile ymfFile)
|
||||||
|
{
|
||||||
|
LoadMeta(ymfFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is MrfFile mrfFile)
|
||||||
|
{
|
||||||
|
LoadMeta(mrfFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is YfdFile yfdFile)
|
||||||
|
{
|
||||||
|
LoadMeta(yfdFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is YpdbFile ypdbFile)
|
||||||
|
{
|
||||||
|
LoadMeta(ypdbFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is HeightmapFile heightmap)
|
||||||
|
{
|
||||||
|
LoadMeta(heightmap);
|
||||||
|
}
|
||||||
|
else if (gameFile is CacheDatFile cacheDatFile)
|
||||||
|
{
|
||||||
|
LoadMeta(cacheDatFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is YedFile yedFile)
|
||||||
|
{
|
||||||
|
LoadMeta(yedFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is YldFile yldFile)
|
||||||
|
{
|
||||||
|
LoadMeta(yldFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is YndFile yndFile)
|
||||||
|
{
|
||||||
|
LoadMeta(yndFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is CutFile cutFile)
|
||||||
|
{
|
||||||
|
LoadMeta(cutFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is JPsoFile jpsoFile)
|
||||||
|
{
|
||||||
|
LoadMeta(jpsoFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is YtypFile ytypFile)
|
||||||
|
{
|
||||||
|
LoadMeta(ytypFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is YmapFile ymapFile)
|
||||||
|
{
|
||||||
|
LoadMeta(ymapFile);
|
||||||
|
}
|
||||||
|
else if (gameFile is YmtFile ymtFile)
|
||||||
|
{
|
||||||
|
LoadMeta(ymtFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public bool SaveMeta(XmlDocument doc)
|
public bool SaveMeta(XmlDocument doc)
|
||||||
@ -426,7 +484,7 @@ namespace CodeWalker.Forms
|
|||||||
//otherwise, save the generated file to disk?
|
//otherwise, save the generated file to disk?
|
||||||
//(currently just return false and revert to XML file save)
|
//(currently just return false and revert to XML file save)
|
||||||
|
|
||||||
if (!(exploreForm?.EditMode ?? false)) return false;
|
if (!(ExploreForm.Instance?.EditMode ?? false)) return false;
|
||||||
|
|
||||||
if(metaFormat == MetaFormat.XML) return false;//what are we even doing here?
|
if(metaFormat == MetaFormat.XML) return false;//what are we even doing here?
|
||||||
|
|
||||||
@ -466,14 +524,14 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!(exploreForm?.EnsureRpfValidEncryption(rpfFileEntry.File) ?? false)) return false;
|
if (!(ExploreForm.EnsureRpfValidEncryption(rpfFileEntry.File))) return false;
|
||||||
|
|
||||||
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
||||||
if (newentry != rpfFileEntry)
|
if (newentry != rpfFileEntry)
|
||||||
{ }
|
{ }
|
||||||
rpfFileEntry = newentry;
|
rpfFileEntry = newentry;
|
||||||
|
|
||||||
exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
|
|
||||||
modified = false;
|
modified = false;
|
||||||
|
|
||||||
@ -492,7 +550,7 @@ namespace CodeWalker.Forms
|
|||||||
{
|
{
|
||||||
File.WriteAllBytes(rpfFileEntry.Path, data);
|
File.WriteAllBytes(rpfFileEntry.Path, data);
|
||||||
|
|
||||||
exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
|
|
||||||
modified = false;
|
modified = false;
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ namespace CodeWalker.Forms
|
|||||||
{
|
{
|
||||||
public Form Form { get { return this; } } //for DXForm/DXManager use
|
public Form Form { get { return this; } } //for DXForm/DXManager use
|
||||||
|
|
||||||
private Renderer Renderer = null;
|
public Renderer Renderer { get; set; }
|
||||||
|
|
||||||
|
|
||||||
volatile bool formopen = false;
|
volatile bool formopen = false;
|
||||||
@ -37,6 +37,8 @@ namespace CodeWalker.Forms
|
|||||||
Weather weather;
|
Weather weather;
|
||||||
Clouds clouds;
|
Clouds clouds;
|
||||||
|
|
||||||
|
public CancellationTokenSource CancellationTokenSource { get; } = new CancellationTokenSource();
|
||||||
|
|
||||||
bool MouseLButtonDown = false;
|
bool MouseLButtonDown = false;
|
||||||
bool MouseRButtonDown = false;
|
bool MouseRButtonDown = false;
|
||||||
int MouseX;
|
int MouseX;
|
||||||
@ -114,7 +116,6 @@ namespace CodeWalker.Forms
|
|||||||
public bool showLightGizmos = true;
|
public bool showLightGizmos = true;
|
||||||
public Skeleton Skeleton = null;
|
public Skeleton Skeleton = null;
|
||||||
|
|
||||||
ExploreForm exploreForm = null;
|
|
||||||
RpfFileEntry rpfFileEntry = null;
|
RpfFileEntry rpfFileEntry = null;
|
||||||
|
|
||||||
|
|
||||||
@ -128,16 +129,14 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public ModelForm(ExploreForm ExpForm = null)
|
public ModelForm()
|
||||||
{
|
{
|
||||||
if (this.DesignMode) return;
|
if (this.DesignMode) return;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
exploreForm = ExpForm;
|
gameFileCache = GameFileCacheFactory.GetInstance();
|
||||||
|
|
||||||
gameFileCache = ExpForm?.GetFileCache() ?? GameFileCacheFactory.Create();
|
if (ExploreForm.Instance == null)
|
||||||
|
|
||||||
if (ExpForm == null)
|
|
||||||
{
|
{
|
||||||
gameFileCache.EnableDlc = false;
|
gameFileCache.EnableDlc = false;
|
||||||
gameFileCache.EnableMods = false;
|
gameFileCache.EnableMods = false;
|
||||||
@ -163,12 +162,14 @@ namespace CodeWalker.Forms
|
|||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine(ex);
|
Console.WriteLine(ex);
|
||||||
throw ex;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
while (!IsDisposed) //run the file cache content thread until the form exits.
|
while (!IsDisposed) //run the file cache content thread until the form exits.
|
||||||
{
|
{
|
||||||
@ -180,14 +181,21 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
if (!fcItemsPending)
|
if (!fcItemsPending)
|
||||||
{
|
{
|
||||||
Thread.Sleep(10);
|
await Task.Delay(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Thread.Sleep(20);
|
await Task.Delay(20);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Exception occurred in gameFileCache ContentThread.\n{ex}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +307,8 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
|
|
||||||
formopen = true;
|
formopen = true;
|
||||||
new Thread(new ThreadStart(ContentThread)).Start();
|
|
||||||
|
Task.Run(ContentThread);
|
||||||
|
|
||||||
frametimer.Start();
|
frametimer.Start();
|
||||||
}
|
}
|
||||||
@ -324,19 +333,26 @@ namespace CodeWalker.Forms
|
|||||||
Console.WriteLine("Clearing cache");
|
Console.WriteLine("Clearing cache");
|
||||||
gameFileCache.Clear();
|
gameFileCache.Clear();
|
||||||
gameFileCache.IsInited = true;
|
gameFileCache.IsInited = true;
|
||||||
GC.Collect();
|
//GC.Collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
public void RenderScene(DeviceContext context)
|
public async ValueTask RenderScene(DeviceContext context)
|
||||||
{
|
{
|
||||||
float elapsed = (float)frametimer.Elapsed.TotalSeconds;
|
float elapsed = (float)frametimer.Elapsed.TotalSeconds;
|
||||||
frametimer.Restart();
|
frametimer.Restart();
|
||||||
|
|
||||||
|
if (elapsed < 0.016666)
|
||||||
|
{
|
||||||
|
await Task.Delay((int)(0.016666 * elapsed) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
if (Pauserendering) return;
|
if (Pauserendering) return;
|
||||||
|
|
||||||
if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50))
|
if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50))
|
||||||
{ return; } //couldn't get a lock, try again next time
|
{
|
||||||
|
return;
|
||||||
|
} //couldn't get a lock, try again next time
|
||||||
|
|
||||||
UpdateControlInputs(elapsed);
|
UpdateControlInputs(elapsed);
|
||||||
|
|
||||||
@ -376,7 +392,7 @@ namespace CodeWalker.Forms
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void ContentThread()
|
private async void ContentThread()
|
||||||
{
|
{
|
||||||
//main content loading thread.
|
//main content loading thread.
|
||||||
//running = true;
|
//running = true;
|
||||||
@ -453,7 +469,7 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
if (!(rcItemsPending)) //gameFileCache.ItemsStillPending ||
|
if (!(rcItemsPending)) //gameFileCache.ItemsStillPending ||
|
||||||
{
|
{
|
||||||
Thread.Sleep(1); //sleep if there's nothing to do
|
await Task.Delay(ActiveForm == null ? 50 : 1).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -482,7 +498,7 @@ namespace CodeWalker.Forms
|
|||||||
List<string> ycdlist = new List<string>();
|
List<string> ycdlist = new List<string>();
|
||||||
foreach (var ycde in ycds)
|
foreach (var ycde in ycds)
|
||||||
{
|
{
|
||||||
ycdlist.Add(ycde.GetShortName());
|
ycdlist.Add(ycde.ShortName);
|
||||||
}
|
}
|
||||||
ClipDictComboBox.AutoCompleteCustomSource.AddRange(ycdlist.ToArray());
|
ClipDictComboBox.AutoCompleteCustomSource.AddRange(ycdlist.ToArray());
|
||||||
ClipDictComboBox.Text = "";
|
ClipDictComboBox.Text = "";
|
||||||
@ -703,10 +719,10 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
public void ViewModel(byte[] data, RpfFileEntry e)
|
public void ViewModel(byte[] data, RpfFileEntry e)
|
||||||
{
|
{
|
||||||
var nl = e?.NameLower ?? "";
|
var nl = e?.Name ?? "";
|
||||||
var fe = Path.GetExtension(nl);
|
var fe = Path.GetExtension(nl);
|
||||||
Show();
|
Show();
|
||||||
switch (fe)
|
switch (fe.ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case ".ydr":
|
case ".ydr":
|
||||||
var ydr = RpfFile.GetFile<YdrFile>(e, data);
|
var ydr = RpfFile.GetFile<YdrFile>(e, data);
|
||||||
@ -902,10 +918,10 @@ namespace CodeWalker.Forms
|
|||||||
Yft = yft;
|
Yft = yft;
|
||||||
rpfFileEntry = Yft.RpfFileEntry;
|
rpfFileEntry = Yft.RpfFileEntry;
|
||||||
ModelHash = Yft.RpfFileEntry?.ShortNameHash ?? 0;
|
ModelHash = Yft.RpfFileEntry?.ShortNameHash ?? 0;
|
||||||
var namelower = Yft.RpfFileEntry?.ShortName;
|
var name = Yft.RpfFileEntry?.ShortName;
|
||||||
if (namelower?.EndsWith("_hi", StringComparison.OrdinalIgnoreCase) ?? false)
|
if (name?.EndsWith("_hi", StringComparison.OrdinalIgnoreCase) ?? false)
|
||||||
{
|
{
|
||||||
ModelHash = JenkHash.GenHashLower(namelower.Substring(0, namelower.Length - 3));
|
ModelHash = JenkHash.GenHashLower(name.AsSpan(0, name.Length - 3));
|
||||||
}
|
}
|
||||||
if (ModelHash != 0)
|
if (ModelHash != 0)
|
||||||
{
|
{
|
||||||
@ -1295,7 +1311,7 @@ namespace CodeWalker.Forms
|
|||||||
{
|
{
|
||||||
items.Add(kvp);
|
items.Add(kvp);
|
||||||
}
|
}
|
||||||
items.Sort((a, b) => { return a.Value?.Name?.CompareTo(b.Value?.Name ?? "") ?? 0; });
|
items.Sort((a, b) => StringComparer.OrdinalIgnoreCase.Compare(a.Value?.Name, b.Value?.Name));
|
||||||
foreach (var kvp in items)
|
foreach (var kvp in items)
|
||||||
{
|
{
|
||||||
AddDrawableTreeNode(kvp.Value, kvp.Key, check);
|
AddDrawableTreeNode(kvp.Value, kvp.Key, check);
|
||||||
@ -1668,7 +1684,7 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
if (td != null)
|
if (td != null)
|
||||||
{
|
{
|
||||||
YtdForm f = new YtdForm(null, this);
|
YtdForm f = new YtdForm(this);
|
||||||
f.Show(this);
|
f.Show(this);
|
||||||
f.LoadTexDict(td, fileName);
|
f.LoadTexDict(td, fileName);
|
||||||
}
|
}
|
||||||
@ -1760,7 +1776,7 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
private void Save(bool saveAs = false)
|
private void Save(bool saveAs = false)
|
||||||
{
|
{
|
||||||
var editMode = exploreForm?.EditMode ?? false;
|
var editMode = ExploreForm.Instance?.EditMode ?? false;
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(FilePath))
|
if (string.IsNullOrEmpty(FilePath))
|
||||||
{
|
{
|
||||||
@ -1857,14 +1873,14 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!(exploreForm?.EnsureRpfValidEncryption(rpfFileEntry.File) ?? false)) return;
|
if (!(ExploreForm.EnsureRpfValidEncryption(rpfFileEntry.File))) return;
|
||||||
|
|
||||||
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, fileBytes);
|
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, fileBytes);
|
||||||
if (newentry != rpfFileEntry)
|
if (newentry != rpfFileEntry)
|
||||||
{ }
|
{ }
|
||||||
rpfFileEntry = newentry;
|
rpfFileEntry = newentry;
|
||||||
|
|
||||||
exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
|
|
||||||
StatusLabel.Text = rpfFileEntry.Name + " saved successfully at " + DateTime.Now.ToString();
|
StatusLabel.Text = rpfFileEntry.Name + " saved successfully at " + DateTime.Now.ToString();
|
||||||
|
|
||||||
@ -1889,7 +1905,7 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
fileName = Path.GetFileName(fn);
|
fileName = Path.GetFileName(fn);
|
||||||
|
|
||||||
exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
|
|
||||||
StatusLabel.Text = fileName + " saved successfully at " + DateTime.Now.ToString();
|
StatusLabel.Text = fileName + " saved successfully at " + DateTime.Now.ToString();
|
||||||
}
|
}
|
||||||
|
@ -51,8 +51,6 @@ namespace CodeWalker.Forms
|
|||||||
private bool modified = false;
|
private bool modified = false;
|
||||||
private bool LoadingXml = false;
|
private bool LoadingXml = false;
|
||||||
private bool DelayHighlight = false;
|
private bool DelayHighlight = false;
|
||||||
|
|
||||||
private ExploreForm exploreForm = null;
|
|
||||||
public RpfFileEntry rpfFileEntry { get; private set; } = null;
|
public RpfFileEntry rpfFileEntry { get; private set; } = null;
|
||||||
private MetaFormat metaFormat = MetaFormat.XML;
|
private MetaFormat metaFormat = MetaFormat.XML;
|
||||||
|
|
||||||
@ -60,10 +58,8 @@ namespace CodeWalker.Forms
|
|||||||
private Dat10Synth currentSynth = null;
|
private Dat10Synth currentSynth = null;
|
||||||
|
|
||||||
|
|
||||||
public RelForm(ExploreForm owner)
|
public RelForm()
|
||||||
{
|
{
|
||||||
exploreForm = owner;
|
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +203,7 @@ namespace CodeWalker.Forms
|
|||||||
private bool SaveRel(XmlDocument doc)
|
private bool SaveRel(XmlDocument doc)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!(exploreForm?.EditMode ?? false)) return false;
|
if (!(ExploreForm.Instance?.EditMode ?? false)) return false;
|
||||||
|
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
|
|
||||||
@ -256,14 +252,14 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!(exploreForm?.EnsureRpfValidEncryption(rpfFileEntry.File) ?? false)) return false;
|
if (!(ExploreForm.EnsureRpfValidEncryption(rpfFileEntry.File))) return false;
|
||||||
|
|
||||||
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
||||||
if (newentry != rpfFileEntry)
|
if (newentry != rpfFileEntry)
|
||||||
{ }
|
{ }
|
||||||
rpfFileEntry = newentry;
|
rpfFileEntry = newentry;
|
||||||
|
|
||||||
exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
|
|
||||||
modified = false;
|
modified = false;
|
||||||
|
|
||||||
@ -282,7 +278,7 @@ namespace CodeWalker.Forms
|
|||||||
{
|
{
|
||||||
File.WriteAllBytes(rpfFileEntry.Path, data);
|
File.WriteAllBytes(rpfFileEntry.Path, data);
|
||||||
|
|
||||||
exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
|
|
||||||
modified = false;
|
modified = false;
|
||||||
|
|
||||||
@ -513,7 +509,6 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
bool textsearch = SearchTextRadio.Checked;
|
bool textsearch = SearchTextRadio.Checked;
|
||||||
var text = SearchTextBox.Text;
|
var text = SearchTextBox.Text;
|
||||||
var textl = text.ToLowerInvariant();
|
|
||||||
|
|
||||||
uint hash = 0;
|
uint hash = 0;
|
||||||
uint hashl = 0;
|
uint hashl = 0;
|
||||||
@ -521,8 +516,8 @@ namespace CodeWalker.Forms
|
|||||||
{
|
{
|
||||||
hash = JenkHash.GenHash(text);
|
hash = JenkHash.GenHash(text);
|
||||||
JenkIndex.Ensure(text);
|
JenkIndex.Ensure(text);
|
||||||
hashl = JenkHash.GenHash(textl);
|
hashl = JenkHash.GenHashLower(text);
|
||||||
JenkIndex.Ensure(textl);
|
JenkIndex.EnsureLower(text);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -536,8 +531,8 @@ namespace CodeWalker.Forms
|
|||||||
{
|
{
|
||||||
if (textsearch)
|
if (textsearch)
|
||||||
{
|
{
|
||||||
if (((rd.Name?.Contains(textl, StringComparison.OrdinalIgnoreCase)) ?? false) || (rd.NameHash == hash) || (rd.NameHash == hashl) ||
|
if (((rd.Name?.Contains(text, StringComparison.OrdinalIgnoreCase)) ?? false) || (rd.NameHash == hash) || (rd.NameHash == hashl) ||
|
||||||
rd.NameHash.ToString().Contains(textl, StringComparison.OrdinalIgnoreCase))
|
rd.NameHash.ToString().Contains(text, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
results.Add(rd);
|
results.Add(rd);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
private bool modified = false;
|
private bool modified = false;
|
||||||
|
|
||||||
private ExploreForm exploreForm = null;
|
|
||||||
public RpfFileEntry rpfFileEntry { get; private set; } = null;
|
public RpfFileEntry rpfFileEntry { get; private set; } = null;
|
||||||
|
|
||||||
|
|
||||||
@ -55,10 +54,8 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
public TextForm(ExploreForm owner)
|
public TextForm()
|
||||||
{
|
{
|
||||||
exploreForm = owner;
|
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,15 +157,14 @@ namespace CodeWalker.Forms
|
|||||||
if (!File.Exists(fn)) return; //couldn't find file?
|
if (!File.Exists(fn)) return; //couldn't find file?
|
||||||
|
|
||||||
|
|
||||||
var fnl = fn.ToLowerInvariant();
|
if (fn.EndsWith(".gxt2", StringComparison.OrdinalIgnoreCase))
|
||||||
if (fnl.EndsWith(".gxt2"))
|
|
||||||
{
|
{
|
||||||
var gxt = new Gxt2File();
|
var gxt = new Gxt2File();
|
||||||
gxt.Load(File.ReadAllBytes(fn), null);
|
gxt.Load(File.ReadAllBytes(fn), null);
|
||||||
fileType = TextFileType.GXT2;
|
fileType = TextFileType.GXT2;
|
||||||
TextValue = gxt.ToText();
|
TextValue = gxt.ToText();
|
||||||
}
|
}
|
||||||
else if (fnl.EndsWith(".nametable"))
|
else if (fn.EndsWith(".nametable", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
fileType = TextFileType.Nametable;
|
fileType = TextFileType.Nametable;
|
||||||
TextValue = File.ReadAllText(fn).Replace('\0', '\n');
|
TextValue = File.ReadAllText(fn).Replace('\0', '\n');
|
||||||
@ -242,7 +238,7 @@ namespace CodeWalker.Forms
|
|||||||
private bool SaveToRPF(string txt)
|
private bool SaveToRPF(string txt)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!(exploreForm?.EditMode ?? false)) return false;
|
if (!(ExploreForm.Instance?.EditMode ?? false)) return false;
|
||||||
if (rpfFileEntry?.Parent == null) return false;
|
if (rpfFileEntry?.Parent == null) return false;
|
||||||
|
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
@ -287,14 +283,14 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!(exploreForm?.EnsureRpfValidEncryption(rpfFileEntry.File) ?? false)) return false;
|
if (!(ExploreForm.EnsureRpfValidEncryption(rpfFileEntry.File))) return false;
|
||||||
|
|
||||||
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
||||||
if (newentry != rpfFileEntry)
|
if (newentry != rpfFileEntry)
|
||||||
{ }
|
{ }
|
||||||
rpfFileEntry = newentry;
|
rpfFileEntry = newentry;
|
||||||
|
|
||||||
exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
|
|
||||||
modified = false;
|
modified = false;
|
||||||
|
|
||||||
|
@ -44,15 +44,11 @@ namespace CodeWalker.Forms
|
|||||||
private bool modified = false;
|
private bool modified = false;
|
||||||
private bool LoadingXml = false;
|
private bool LoadingXml = false;
|
||||||
private bool DelayHighlight = false;
|
private bool DelayHighlight = false;
|
||||||
|
|
||||||
private ExploreForm exploreForm = null;
|
|
||||||
public RpfFileEntry rpfFileEntry { get; private set; } = null;
|
public RpfFileEntry rpfFileEntry { get; private set; } = null;
|
||||||
|
|
||||||
|
|
||||||
public XmlForm(ExploreForm owner)
|
public XmlForm()
|
||||||
{
|
{
|
||||||
exploreForm = owner;
|
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +211,7 @@ namespace CodeWalker.Forms
|
|||||||
private bool SaveToRPF(string txt)
|
private bool SaveToRPF(string txt)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!(exploreForm?.EditMode ?? false)) return false;
|
if (!(ExploreForm.Instance?.EditMode ?? false)) return false;
|
||||||
if (rpfFileEntry?.Parent == null) return false;
|
if (rpfFileEntry?.Parent == null) return false;
|
||||||
|
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
@ -238,14 +234,14 @@ namespace CodeWalker.Forms
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!(exploreForm?.EnsureRpfValidEncryption(rpfFileEntry.File) ?? false)) return false;
|
if (!(ExploreForm.EnsureRpfValidEncryption(rpfFileEntry.File))) return false;
|
||||||
|
|
||||||
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
var newentry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
||||||
if (newentry != rpfFileEntry)
|
if (newentry != rpfFileEntry)
|
||||||
{ }
|
{ }
|
||||||
rpfFileEntry = newentry;
|
rpfFileEntry = newentry;
|
||||||
|
|
||||||
exploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
|
|
||||||
modified = false;
|
modified = false;
|
||||||
|
|
||||||
|
5
CodeWalker/Forms/YtdForm.Designer.cs
generated
5
CodeWalker/Forms/YtdForm.Designer.cs
generated
@ -61,7 +61,7 @@
|
|||||||
this.label1 = new System.Windows.Forms.Label();
|
this.label1 = new System.Windows.Forms.Label();
|
||||||
this.SelTextureZoomCombo = new System.Windows.Forms.ComboBox();
|
this.SelTextureZoomCombo = new System.Windows.Forms.ComboBox();
|
||||||
this.SelTexturePanel = new System.Windows.Forms.Panel();
|
this.SelTexturePanel = new System.Windows.Forms.Panel();
|
||||||
this.SelTexturePictureBox = new System.Windows.Forms.PictureBox();
|
this.SelTexturePictureBox = new PixelBox();
|
||||||
this.SelTextureMipLabel = new System.Windows.Forms.Label();
|
this.SelTextureMipLabel = new System.Windows.Forms.Label();
|
||||||
this.SelTextureDimensionsLabel = new System.Windows.Forms.Label();
|
this.SelTextureDimensionsLabel = new System.Windows.Forms.Label();
|
||||||
this.SelTextureMipTrackBar = new System.Windows.Forms.TrackBar();
|
this.SelTextureMipTrackBar = new System.Windows.Forms.TrackBar();
|
||||||
@ -436,6 +436,7 @@
|
|||||||
this.SelTexturePictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
|
this.SelTexturePictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
|
||||||
this.SelTexturePictureBox.TabIndex = 45;
|
this.SelTexturePictureBox.TabIndex = 45;
|
||||||
this.SelTexturePictureBox.TabStop = false;
|
this.SelTexturePictureBox.TabStop = false;
|
||||||
|
|
||||||
//
|
//
|
||||||
// SelTextureMipLabel
|
// SelTextureMipLabel
|
||||||
//
|
//
|
||||||
@ -573,7 +574,7 @@
|
|||||||
private System.Windows.Forms.Label SelTextureDimensionsLabel;
|
private System.Windows.Forms.Label SelTextureDimensionsLabel;
|
||||||
private System.Windows.Forms.TrackBar SelTextureMipTrackBar;
|
private System.Windows.Forms.TrackBar SelTextureMipTrackBar;
|
||||||
private System.Windows.Forms.Label label4;
|
private System.Windows.Forms.Label label4;
|
||||||
private System.Windows.Forms.PictureBox SelTexturePictureBox;
|
private PixelBox SelTexturePictureBox;
|
||||||
private System.Windows.Forms.TabPage DetailsTabPage;
|
private System.Windows.Forms.TabPage DetailsTabPage;
|
||||||
private WinForms.PropertyGridFix DetailsPropertyGrid;
|
private WinForms.PropertyGridFix DetailsPropertyGrid;
|
||||||
private System.Windows.Forms.ListView TexturesListView;
|
private System.Windows.Forms.ListView TexturesListView;
|
||||||
|
@ -5,10 +5,12 @@ using System.Collections.Generic;
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
|
using System.Drawing.Drawing2D;
|
||||||
using System.Drawing.Imaging;
|
using System.Drawing.Imaging;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Remoting.Channels;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
@ -23,13 +25,11 @@ namespace CodeWalker.Forms
|
|||||||
private Texture CurrentTexture = null;
|
private Texture CurrentTexture = null;
|
||||||
private float CurrentZoom = 0.0f; //1.0 = 100%, 0.0 = stretch
|
private float CurrentZoom = 0.0f; //1.0 = 100%, 0.0 = stretch
|
||||||
private bool Modified = false;
|
private bool Modified = false;
|
||||||
private ExploreForm ExploreForm = null;
|
|
||||||
private ModelForm ModelForm = null;
|
private ModelForm ModelForm = null;
|
||||||
|
|
||||||
|
|
||||||
public YtdForm(ExploreForm exploreForm = null, ModelForm modelForm = null)
|
public YtdForm(ModelForm modelForm = null)
|
||||||
{
|
{
|
||||||
ExploreForm = exploreForm;
|
|
||||||
ModelForm = modelForm;
|
ModelForm = modelForm;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
@ -155,8 +155,10 @@ namespace CodeWalker.Forms
|
|||||||
byte[] pixels = DDSIO.GetPixels(tex, cmip);
|
byte[] pixels = DDSIO.GetPixels(tex, cmip);
|
||||||
int w = tex.Width >> cmip;
|
int w = tex.Width >> cmip;
|
||||||
int h = tex.Height >> cmip;
|
int h = tex.Height >> cmip;
|
||||||
Bitmap bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb);
|
|
||||||
|
|
||||||
|
//Image bmp = Image.FromStream(new MemoryStream(pixels));
|
||||||
|
|
||||||
|
Bitmap bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb);
|
||||||
if (pixels != null)
|
if (pixels != null)
|
||||||
{
|
{
|
||||||
var BoundsRect = new System.Drawing.Rectangle(0, 0, w, h);
|
var BoundsRect = new System.Drawing.Rectangle(0, 0, w, h);
|
||||||
@ -396,7 +398,7 @@ namespace CodeWalker.Forms
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var cansave = (ExploreForm?.EditMode ?? false);
|
var cansave = (ExploreForm.Instance?.EditMode ?? false);
|
||||||
var s = "Save " + FileName;
|
var s = "Save " + FileName;
|
||||||
var sas = "Save " + FileName + " As...";
|
var sas = "Save " + FileName + " As...";
|
||||||
FileSaveMenu.Text = s;
|
FileSaveMenu.Text = s;
|
||||||
@ -435,7 +437,7 @@ namespace CodeWalker.Forms
|
|||||||
private void SaveYTD(bool saveas = false)
|
private void SaveYTD(bool saveas = false)
|
||||||
{
|
{
|
||||||
if (Ytd == null) return;
|
if (Ytd == null) return;
|
||||||
if (!(ExploreForm?.EditMode ?? false))
|
if (!(ExploreForm.Instance?.EditMode ?? false))
|
||||||
{
|
{
|
||||||
saveas = true;
|
saveas = true;
|
||||||
}
|
}
|
||||||
@ -485,18 +487,18 @@ namespace CodeWalker.Forms
|
|||||||
else if (!isinrpf) //save direct to filesystem in RPF explorer
|
else if (!isinrpf) //save direct to filesystem in RPF explorer
|
||||||
{
|
{
|
||||||
File.WriteAllBytes(rpfFileEntry.Path, data);
|
File.WriteAllBytes(rpfFileEntry.Path, data);
|
||||||
ExploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
}
|
}
|
||||||
else //save to RPF...
|
else //save to RPF...
|
||||||
{
|
{
|
||||||
if (!(ExploreForm?.EnsureRpfValidEncryption(rpfFileEntry.File) ?? false))
|
if (!ExploreForm.EnsureRpfValidEncryption(rpfFileEntry.File))
|
||||||
{
|
{
|
||||||
MessageBox.Show("Unable to save file, RPF encryption needs to be OPEN for this operation!");
|
MessageBox.Show("Unable to save file, RPF encryption needs to be OPEN for this operation!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ytd.RpfFileEntry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
Ytd.RpfFileEntry = RpfFile.CreateFile(rpfFileEntry.Parent, rpfFileEntry.Name, data);
|
||||||
ExploreForm?.RefreshMainListViewInvoke(); //update the file details in explorer...
|
ExploreForm.RefreshMainListViewInvoke(); //update the file details in explorer...
|
||||||
}
|
}
|
||||||
|
|
||||||
Modified = false;
|
Modified = false;
|
||||||
@ -647,4 +649,14 @@ namespace CodeWalker.Forms
|
|||||||
RenameTexture(SelTextureNameTextBox.Text);
|
RenameTexture(SelTextureNameTextBox.Text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PixelBox : PictureBox
|
||||||
|
{
|
||||||
|
protected override void OnPaint(PaintEventArgs pe)
|
||||||
|
{
|
||||||
|
pe.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
|
||||||
|
pe.Graphics.PixelOffsetMode = PixelOffsetMode.Half;
|
||||||
|
base.OnPaint(pe);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using CodeWalker.Properties;
|
using CodeWalker.Properties;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -11,7 +12,7 @@ namespace CodeWalker.GameFiles
|
|||||||
public static class GameFileCacheFactory
|
public static class GameFileCacheFactory
|
||||||
{
|
{
|
||||||
public static GameFileCache _instance = null;
|
public static GameFileCache _instance = null;
|
||||||
public static GameFileCache Create()
|
public static GameFileCache GetInstance()
|
||||||
{
|
{
|
||||||
if (_instance == null)
|
if (_instance == null)
|
||||||
{
|
{
|
||||||
|
@ -36,13 +36,13 @@ namespace CodeWalker
|
|||||||
private void RPFExplorerButton_Click(object sender, EventArgs e)
|
private void RPFExplorerButton_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
ExploreForm f = new ExploreForm();
|
ExploreForm f = new ExploreForm();
|
||||||
f.Show(this);
|
f.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RPFBrowserButton_Click(object sender, EventArgs e)
|
private void RPFBrowserButton_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
BrowseForm f = new BrowseForm();
|
BrowseForm f = new BrowseForm();
|
||||||
f.Show(this);
|
f.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExtractScriptsButton_Click(object sender, EventArgs e)
|
private void ExtractScriptsButton_Click(object sender, EventArgs e)
|
||||||
|
@ -24,7 +24,7 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
public Form Form { get { return this; } } //for DXForm/DXManager use
|
public Form Form { get { return this; } } //for DXForm/DXManager use
|
||||||
|
|
||||||
public Renderer Renderer = null;
|
public Renderer Renderer { get; set; }
|
||||||
public object RenderSyncRoot { get { return Renderer.RenderSyncRoot; } }
|
public object RenderSyncRoot { get { return Renderer.RenderSyncRoot; } }
|
||||||
|
|
||||||
public bool Pauserendering { get; set; }
|
public bool Pauserendering { get; set; }
|
||||||
@ -41,6 +41,8 @@ namespace CodeWalker
|
|||||||
|
|
||||||
Entity camEntity = new Entity();
|
Entity camEntity = new Entity();
|
||||||
|
|
||||||
|
public CancellationTokenSource CancellationTokenSource { get; } = new CancellationTokenSource();
|
||||||
|
|
||||||
|
|
||||||
bool MouseLButtonDown = false;
|
bool MouseLButtonDown = false;
|
||||||
bool MouseRButtonDown = false;
|
bool MouseRButtonDown = false;
|
||||||
@ -50,7 +52,7 @@ namespace CodeWalker
|
|||||||
System.Drawing.Point MouseLastPoint;
|
System.Drawing.Point MouseLastPoint;
|
||||||
|
|
||||||
|
|
||||||
public GameFileCache GameFileCache { get; } = GameFileCacheFactory.Create();
|
public GameFileCache GameFileCache { get; } = GameFileCacheFactory.GetInstance();
|
||||||
|
|
||||||
|
|
||||||
InputManager Input = new InputManager();
|
InputManager Input = new InputManager();
|
||||||
@ -189,7 +191,8 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
formopen = true;
|
formopen = true;
|
||||||
new Thread(new ThreadStart(ContentThread)).Start();
|
|
||||||
|
Task.Run(ContentThread);
|
||||||
|
|
||||||
frametimer.Start();
|
frametimer.Start();
|
||||||
|
|
||||||
@ -207,18 +210,27 @@ namespace CodeWalker
|
|||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void RenderScene(DeviceContext context)
|
public async ValueTask RenderScene(DeviceContext context)
|
||||||
{
|
{
|
||||||
float elapsed = (float)frametimer.Elapsed.TotalSeconds;
|
float elapsed = (float)frametimer.Elapsed.TotalSeconds;
|
||||||
frametimer.Restart();
|
frametimer.Restart();
|
||||||
|
|
||||||
|
if (elapsed < 0.016666)
|
||||||
|
{
|
||||||
|
await Task.Delay((int)(0.016666 * elapsed) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
if (Pauserendering) return;
|
if (Pauserendering) return;
|
||||||
|
|
||||||
GameFileCache.BeginFrame();
|
GameFileCache.BeginFrame();
|
||||||
|
|
||||||
if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50))
|
if (!Monitor.TryEnter(Renderer.RenderSyncRoot, 50))
|
||||||
{ return; } //couldn't get a lock, try again next time
|
{
|
||||||
|
return;
|
||||||
|
} //couldn't get a lock, try again next time
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
UpdateControlInputs(elapsed);
|
UpdateControlInputs(elapsed);
|
||||||
//space.Update(elapsed);
|
//space.Update(elapsed);
|
||||||
|
|
||||||
@ -262,8 +274,11 @@ namespace CodeWalker
|
|||||||
//RenderWidgets();
|
//RenderWidgets();
|
||||||
|
|
||||||
Renderer.EndRender();
|
Renderer.EndRender();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
Monitor.Exit(Renderer.RenderSyncRoot);
|
Monitor.Exit(Renderer.RenderSyncRoot);
|
||||||
|
}
|
||||||
|
|
||||||
//UpdateMarkerSelectionPanelInvoke();
|
//UpdateMarkerSelectionPanelInvoke();
|
||||||
}
|
}
|
||||||
@ -323,6 +338,8 @@ namespace CodeWalker
|
|||||||
|
|
||||||
|
|
||||||
private void ContentThread()
|
private void ContentThread()
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
//main content loading thread.
|
//main content loading thread.
|
||||||
running = true;
|
running = true;
|
||||||
@ -340,6 +357,8 @@ namespace CodeWalker
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!GameFileCache.IsInited)
|
||||||
|
{
|
||||||
GameFileCache.EnableDlc = true;
|
GameFileCache.EnableDlc = true;
|
||||||
GameFileCache.EnableMods = true;
|
GameFileCache.EnableMods = true;
|
||||||
GameFileCache.LoadPeds = true;
|
GameFileCache.LoadPeds = true;
|
||||||
@ -347,7 +366,8 @@ namespace CodeWalker
|
|||||||
GameFileCache.LoadArchetypes = false;//to speed things up a little
|
GameFileCache.LoadArchetypes = false;//to speed things up a little
|
||||||
GameFileCache.BuildExtendedJenkIndex = false;//to speed things up a little
|
GameFileCache.BuildExtendedJenkIndex = false;//to speed things up a little
|
||||||
GameFileCache.DoFullStringIndex = true;//to get all global text from DLC...
|
GameFileCache.DoFullStringIndex = true;//to get all global text from DLC...
|
||||||
GameFileCache.Init(UpdateStatus, LogError);
|
GameFileCache.Init(UpdateStatus, LogError, force: false);
|
||||||
|
}
|
||||||
|
|
||||||
//UpdateDlcListComboBox(gameFileCache.DlcNameList);
|
//UpdateDlcListComboBox(gameFileCache.DlcNameList);
|
||||||
|
|
||||||
@ -367,31 +387,41 @@ namespace CodeWalker
|
|||||||
//UpdateStatus("Ready");
|
//UpdateStatus("Ready");
|
||||||
|
|
||||||
|
|
||||||
Task.Run(() => {
|
Task.Run(async () => {
|
||||||
while (formopen && !IsDisposed) //renderer content loop
|
while (formopen && !IsDisposed) //renderer content loop
|
||||||
{
|
{
|
||||||
bool rcItemsPending = Renderer.ContentThreadProc();
|
bool rcItemsPending = Renderer.ContentThreadProc();
|
||||||
|
|
||||||
if (!rcItemsPending)
|
if (!rcItemsPending)
|
||||||
{
|
{
|
||||||
Thread.Sleep(1); //sleep if there's nothing to do
|
await Task.Delay(ActiveForm == null ? 50 : 1).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
while (formopen && !IsDisposed) //main asset loop
|
while (formopen && !IsDisposed) //main asset loop
|
||||||
{
|
{
|
||||||
bool fcItemsPending = GameFileCache.ContentThreadProc();
|
bool fcItemsPending = GameFileCache.ContentThreadProc();
|
||||||
|
|
||||||
if (!fcItemsPending)
|
if (!fcItemsPending)
|
||||||
{
|
{
|
||||||
Thread.Sleep(1); //sleep if there's nothing to do
|
await Task.Delay(ActiveForm == null ? 50 : 1).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GameFileCache.Clear();
|
|
||||||
|
|
||||||
running = false;
|
running = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Exception occured in PedsForm::ContentThread.\n{ex}");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -662,7 +692,7 @@ namespace CodeWalker
|
|||||||
List<string> ycdlist = new List<string>();
|
List<string> ycdlist = new List<string>();
|
||||||
foreach (var ycde in ycds)
|
foreach (var ycde in ycds)
|
||||||
{
|
{
|
||||||
ycdlist.Add(ycde.GetShortName());
|
ycdlist.Add(ycde.ShortName);
|
||||||
}
|
}
|
||||||
ClipDictComboBox.AutoCompleteCustomSource.AddRange(ycdlist.ToArray());
|
ClipDictComboBox.AutoCompleteCustomSource.AddRange(ycdlist.ToArray());
|
||||||
ClipDictComboBox.Text = "";
|
ClipDictComboBox.Text = "";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using CodeWalker.Forms;
|
using CodeWalker.Core.Utils;
|
||||||
|
using CodeWalker.Forms;
|
||||||
using CodeWalker.GameFiles;
|
using CodeWalker.GameFiles;
|
||||||
using CodeWalker.Properties;
|
using CodeWalker.Properties;
|
||||||
using CodeWalker.Utils;
|
using CodeWalker.Utils;
|
||||||
@ -10,6 +11,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Windows.Shell;
|
using System.Windows.Shell;
|
||||||
@ -29,6 +31,13 @@ namespace CodeWalker
|
|||||||
{
|
{
|
||||||
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
CultureInfo.CurrentCulture = CultureInfo.InvariantCulture;
|
||||||
ConsoleWindow.Hide();
|
ConsoleWindow.Hide();
|
||||||
|
|
||||||
|
Application.ThreadException += (object sender, ThreadExceptionEventArgs e) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Unhandeled exception occured: {e.Exception}");
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
bool menumode = false;
|
bool menumode = false;
|
||||||
bool explorermode = false;
|
bool explorermode = false;
|
||||||
bool projectmode = false;
|
bool projectmode = false;
|
||||||
@ -98,7 +107,13 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
else if (explorermode)
|
else if (explorermode)
|
||||||
{
|
{
|
||||||
Application.Run(new ExploreForm());
|
if (!NamedPipe.TrySendMessageToOtherProcess("explorer"))
|
||||||
|
{
|
||||||
|
var form = new ExploreForm();
|
||||||
|
var namedPipe = new NamedPipe(form);
|
||||||
|
namedPipe.Init();
|
||||||
|
Application.Run(form);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (projectmode)
|
else if (projectmode)
|
||||||
{
|
{
|
||||||
@ -114,15 +129,29 @@ namespace CodeWalker
|
|||||||
}
|
}
|
||||||
else if (path != null)
|
else if (path != null)
|
||||||
{
|
{
|
||||||
var modelForm = new ModelForm();
|
if (!NamedPipe.TrySendMessageToOtherProcess($"open-file {path}"))
|
||||||
modelForm.Load += new EventHandler(async (sender, eventArgs) => {
|
{
|
||||||
modelForm.ViewModel(path);
|
Form form = null;
|
||||||
});
|
try
|
||||||
Application.Run(modelForm);
|
{
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
Application.Run(new WorldForm());
|
var form = new WorldForm();
|
||||||
|
var namedPipe = new NamedPipe(form);
|
||||||
|
namedPipe.Init();
|
||||||
|
Application.Run(form);
|
||||||
}
|
}
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
}
|
}
|
||||||
|
@ -73,20 +73,19 @@ namespace CodeWalker.Project.Panels
|
|||||||
|
|
||||||
var getYtypName = new Func<YtypFile, string>((ytyp) =>
|
var getYtypName = new Func<YtypFile, string>((ytyp) =>
|
||||||
{
|
{
|
||||||
var ytypname = ytyp?.RpfFileEntry?.NameLower;
|
var ytypname = ytyp?.RpfFileEntry?.Name;
|
||||||
if (ytyp != null)
|
if (ytyp != null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(ytypname))
|
if (string.IsNullOrEmpty(ytypname))
|
||||||
{
|
{
|
||||||
ytypname = ytyp.RpfFileEntry?.Name?.ToLowerInvariant();
|
ytypname = ytyp.RpfFileEntry?.Name ?? string.Empty;
|
||||||
if (ytypname == null) ytypname = "";
|
|
||||||
}
|
}
|
||||||
if (ytypname.EndsWith(".ytyp"))
|
if (ytypname.EndsWith(".ytyp", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
ytypname = ytypname.Substring(0, ytypname.Length - 5);
|
ytypname = ytypname.Substring(0, ytypname.Length - 5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ytypname;
|
return ytypname?.ToLowerInvariant();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -97,7 +96,7 @@ namespace CodeWalker.Project.Panels
|
|||||||
sb.AppendLine(" <imapDependencies_2>");
|
sb.AppendLine(" <imapDependencies_2>");
|
||||||
foreach (var ymap in CurrentProjectFile.YmapFiles)
|
foreach (var ymap in CurrentProjectFile.YmapFiles)
|
||||||
{
|
{
|
||||||
var ymapname = ymap.RpfFileEntry?.NameLower;
|
var ymapname = ymap.RpfFileEntry?.Name.ToLowerInvariant();
|
||||||
if (string.IsNullOrEmpty(ymapname))
|
if (string.IsNullOrEmpty(ymapname))
|
||||||
{
|
{
|
||||||
ymapname = ymap.Name.ToLowerInvariant();
|
ymapname = ymap.Name.ToLowerInvariant();
|
||||||
|
@ -60,8 +60,8 @@ namespace CodeWalker.Project.Panels
|
|||||||
|
|
||||||
LoadYmapTreeNodes(ymapfile, ymapnode);
|
LoadYmapTreeNodes(ymapfile, ymapnode);
|
||||||
|
|
||||||
JenkIndex.Ensure(name);
|
JenkIndex.EnsureBoth(name);
|
||||||
JenkIndex.Ensure(Path.GetFileNameWithoutExtension(name));
|
JenkIndex.EnsureBoth(Path.GetFileNameWithoutExtension(name));
|
||||||
}
|
}
|
||||||
ymapsnode.Expand();
|
ymapsnode.Expand();
|
||||||
}
|
}
|
||||||
@ -84,8 +84,8 @@ namespace CodeWalker.Project.Panels
|
|||||||
|
|
||||||
LoadYtypTreeNodes(ytypfile, ytypnode);
|
LoadYtypTreeNodes(ytypfile, ytypnode);
|
||||||
|
|
||||||
JenkIndex.Ensure(name);
|
JenkIndex.EnsureBoth(name);
|
||||||
JenkIndex.Ensure(Path.GetFileNameWithoutExtension(name));
|
JenkIndex.EnsureBoth(Path.GetFileNameWithoutExtension(name));
|
||||||
}
|
}
|
||||||
ytypsnode.Expand();
|
ytypsnode.Expand();
|
||||||
}
|
}
|
||||||
|
@ -530,9 +530,9 @@ namespace CodeWalker.Project
|
|||||||
ytyp.RpfFileEntry.Name = Path.GetFileName(filename);
|
ytyp.RpfFileEntry.Name = Path.GetFileName(filename);
|
||||||
ytyp.FilePath = GetFullFilePath(filename);
|
ytyp.FilePath = GetFullFilePath(filename);
|
||||||
ytyp.Name = ytyp.RpfFileEntry.Name;
|
ytyp.Name = ytyp.RpfFileEntry.Name;
|
||||||
JenkIndex.Ensure(ytyp.Name);
|
JenkIndex.EnsureBoth(ytyp.Name);
|
||||||
JenkIndex.Ensure(Path.GetFileNameWithoutExtension(ytyp.Name));
|
JenkIndex.EnsureBoth(Path.GetFileNameWithoutExtension(ytyp.Name));
|
||||||
JenkIndex.Ensure(filename);
|
JenkIndex.EnsureBoth(filename);
|
||||||
if (!AddYtypFile(ytyp)) return null;
|
if (!AddYtypFile(ytyp)) return null;
|
||||||
return ytyp;
|
return ytyp;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -124,26 +125,22 @@ namespace CodeWalker.Project
|
|||||||
SetTheme(Settings.Default.ProjectWindowTheme, false);
|
SetTheme(Settings.Default.ProjectWindowTheme, false);
|
||||||
ShowDefaultPanels();
|
ShowDefaultPanels();
|
||||||
|
|
||||||
|
GameFileCache = GameFileCacheFactory.GetInstance();
|
||||||
|
|
||||||
if ((WorldForm != null) && (WorldForm.GameFileCache != null))
|
if (!GameFileCache.IsInited)
|
||||||
{
|
{
|
||||||
GameFileCache = WorldForm.GameFileCache;
|
Task.Run(() =>
|
||||||
RpfMan = GameFileCache.RpfMan;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
GameFileCache = GameFileCacheFactory.Create();
|
|
||||||
new Thread(new ThreadStart(() =>
|
|
||||||
{
|
{
|
||||||
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
|
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
|
||||||
GameFileCache.Init(UpdateStatus, UpdateError);
|
GameFileCache.Init(UpdateStatus, UpdateError);
|
||||||
RpfMan = GameFileCache.RpfMan;
|
});
|
||||||
})).Start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RpfMan = GameFileCache.RpfMan;
|
||||||
|
}
|
||||||
private void UpdateStatus(string text)
|
private void UpdateStatus(string text)
|
||||||
{
|
{
|
||||||
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (InvokeRequired)
|
if (InvokeRequired)
|
||||||
@ -168,6 +165,7 @@ namespace CodeWalker.Project
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Console.WriteLine(text);
|
||||||
//TODO: error text
|
//TODO: error text
|
||||||
//ErrorLabel.Text = text;
|
//ErrorLabel.Text = text;
|
||||||
}
|
}
|
||||||
@ -1640,14 +1638,14 @@ namespace CodeWalker.Project
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ".dat":
|
case ".dat":
|
||||||
if (fn.StartsWith("trains"))
|
if (fn.StartsWith("trains", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var track = CurrentProjectFile.AddTrainsFile(file);
|
var track = CurrentProjectFile.AddTrainsFile(file);
|
||||||
if (track != null) LoadTrainTrackFromFile(track, file);
|
if (track != null) LoadTrainTrackFromFile(track, file);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ".rel":
|
case ".rel":
|
||||||
if (fn.EndsWith(".dat151.rel"))
|
if (fn.EndsWith(".dat151.rel", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var dat151 = CurrentProjectFile.AddAudioRelFile(file);
|
var dat151 = CurrentProjectFile.AddAudioRelFile(file);
|
||||||
if (dat151 != null) LoadAudioRelFromFile(dat151, file);
|
if (dat151 != null) LoadAudioRelFromFile(dat151, file);
|
||||||
@ -6129,7 +6127,7 @@ namespace CodeWalker.Project
|
|||||||
var delim = line.Contains(",") ? "," : " ";
|
var delim = line.Contains(",") ? "," : " ";
|
||||||
var vals = line.Split(new[] { delim }, StringSplitOptions.RemoveEmptyEntries);
|
var vals = line.Split(new[] { delim }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (vals.Length < 3) continue;
|
if (vals.Length < 3) continue;
|
||||||
if (vals[0].StartsWith("X")) continue;
|
if (vals[0].StartsWith("X", StringComparison.OrdinalIgnoreCase)) continue;
|
||||||
Vector3 pos = Vector3.Zero;
|
Vector3 pos = Vector3.Zero;
|
||||||
float dir = 0;
|
float dir = 0;
|
||||||
var action = CScenarioChainingEdge__eAction.Move;
|
var action = CScenarioChainingEdge__eAction.Move;
|
||||||
@ -7083,7 +7081,7 @@ namespace CodeWalker.Project
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private DateTime LastProjectCheck = DateTime.MinValue;
|
||||||
public void GetVisibleYmaps(Camera camera, Dictionary<MetaHash, YmapFile> ymaps)
|
public void GetVisibleYmaps(Camera camera, Dictionary<MetaHash, YmapFile> ymaps)
|
||||||
{
|
{
|
||||||
if (hidegtavmap)
|
if (hidegtavmap)
|
||||||
@ -7106,10 +7104,16 @@ namespace CodeWalker.Project
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visiblemloentities.Clear();
|
if (DateTime.Now - LastProjectCheck < TimeSpan.FromSeconds(1))
|
||||||
foreach (var kvp in ymaps)//TODO: improve performance
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LastProjectCheck = DateTime.Now;
|
||||||
|
|
||||||
|
visiblemloentities.Clear();
|
||||||
|
foreach (var ymap in ymaps.Values)//TODO: improve performance
|
||||||
{
|
{
|
||||||
var ymap = kvp.Value;
|
|
||||||
if (ymap.AllEntities != null)//THIS IS TERRIBLE! EATING ALL FPS
|
if (ymap.AllEntities != null)//THIS IS TERRIBLE! EATING ALL FPS
|
||||||
{
|
{
|
||||||
foreach (var ent in ymap.AllEntities)//WHYYYY - maybe only do this after loading/editing ytyp!
|
foreach (var ent in ymap.AllEntities)//WHYYYY - maybe only do this after loading/editing ytyp!
|
||||||
@ -8664,7 +8668,6 @@ namespace CodeWalker.Project
|
|||||||
track.Name = fname;
|
track.Name = fname;
|
||||||
track.FilePath = filename;
|
track.FilePath = filename;
|
||||||
track.RpfFileEntry.Name = fname;
|
track.RpfFileEntry.Name = fname;
|
||||||
track.RpfFileEntry.NameLower = fname.ToLowerInvariant();
|
|
||||||
|
|
||||||
if (WorldForm != null)
|
if (WorldForm != null)
|
||||||
{
|
{
|
||||||
|
3
CodeWalker/Properties/Settings.Designer.cs
generated
3
CodeWalker/Properties/Settings.Designer.cs
generated
@ -8,6 +8,9 @@
|
|||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
namespace CodeWalker.Properties {
|
namespace CodeWalker.Properties {
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,7 +2,8 @@
|
|||||||
"profiles": {
|
"profiles": {
|
||||||
"CodeWalker": {
|
"CodeWalker": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"workingDirectory": ".."
|
"workingDirectory": "..",
|
||||||
|
"nativeDebugging": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
|
||||||
@ -17,12 +18,14 @@ namespace CodeWalker.Rendering
|
|||||||
//So, i've used an interface instead, since really just some of the form properties
|
//So, i've used an interface instead, since really just some of the form properties
|
||||||
//and a couple of extra methods (these callbacks) are needed by DXManager.
|
//and a couple of extra methods (these callbacks) are needed by DXManager.
|
||||||
|
|
||||||
|
public Renderer Renderer { get; set; }
|
||||||
Form Form { get; }
|
Form Form { get; }
|
||||||
|
|
||||||
|
public CancellationTokenSource CancellationTokenSource { get; }
|
||||||
public bool Pauserendering { get; set; }
|
public bool Pauserendering { get; set; }
|
||||||
void InitScene(Device device);
|
void InitScene(Device device);
|
||||||
void CleanupScene();
|
void CleanupScene();
|
||||||
void RenderScene(DeviceContext context);
|
ValueTask RenderScene(DeviceContext context);
|
||||||
void BuffersResized(int w, int h);
|
void BuffersResized(int w, int h);
|
||||||
bool ConfirmQuit();
|
bool ConfirmQuit();
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ using SharpDX.Direct3D;
|
|||||||
using System.Runtime;
|
using System.Runtime;
|
||||||
using CodeWalker.Core.Utils;
|
using CodeWalker.Core.Utils;
|
||||||
using CodeWalker.Properties;
|
using CodeWalker.Properties;
|
||||||
|
using CodeWalker.GameFiles;
|
||||||
|
|
||||||
namespace CodeWalker.Rendering
|
namespace CodeWalker.Rendering
|
||||||
{
|
{
|
||||||
@ -30,10 +31,14 @@ namespace CodeWalker.Rendering
|
|||||||
public RenderTargetView targetview { get; private set; }
|
public RenderTargetView targetview { get; private set; }
|
||||||
public DepthStencilView depthview { get; private set; }
|
public DepthStencilView depthview { get; private set; }
|
||||||
|
|
||||||
|
public CancellationToken cancellationToken;
|
||||||
|
|
||||||
private volatile bool Running = false;
|
private volatile bool Running = false;
|
||||||
private volatile bool Rendering = false;
|
private volatile bool Rendering = false;
|
||||||
private volatile bool Resizing = false;
|
private volatile bool Resizing = false;
|
||||||
private object syncroot = new object(); //for thread safety
|
private SemaphoreSlim semaphore = new SemaphoreSlim(1);
|
||||||
|
|
||||||
|
|
||||||
public int multisamplecount { get; private set; } = Settings.Default.AntiAliasing;
|
public int multisamplecount { get; private set; } = Settings.Default.AntiAliasing;
|
||||||
public int multisamplequality { get; private set; } = 0; //should be a setting...
|
public int multisamplequality { get; private set; } = 0; //should be a setting...
|
||||||
public Color clearcolour { get; private set; } = new Color(0.2f, 0.4f, 0.6f, 1.0f); //gross
|
public Color clearcolour { get; private set; } = new Color(0.2f, 0.4f, 0.6f, 1.0f); //gross
|
||||||
@ -46,6 +51,8 @@ namespace CodeWalker.Rendering
|
|||||||
dxform = form;
|
dxform = form;
|
||||||
autoStartLoop = autostart;
|
autoStartLoop = autostart;
|
||||||
|
|
||||||
|
cancellationToken = form.CancellationTokenSource.Token;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//SharpDX.Configuration.EnableObjectTracking = true;
|
//SharpDX.Configuration.EnableObjectTracking = true;
|
||||||
@ -147,6 +154,9 @@ namespace CodeWalker.Rendering
|
|||||||
|
|
||||||
private void Cleanup()
|
private void Cleanup()
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var _ = new DisposableTimer("DXManager Cleanup");
|
||||||
Running = false;
|
Running = false;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
while (Rendering && (count < 1000))
|
while (Rendering && (count < 1000))
|
||||||
@ -170,8 +180,12 @@ namespace CodeWalker.Rendering
|
|||||||
//var objs = SharpDX.Diagnostics.ObjectTracker.FindActiveObjects();
|
//var objs = SharpDX.Diagnostics.ObjectTracker.FindActiveObjects();
|
||||||
|
|
||||||
if (device != null) device.Dispose();
|
if (device != null) device.Dispose();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
GC.Collect();
|
|
||||||
}
|
}
|
||||||
private void CreateRenderBuffers()
|
private void CreateRenderBuffers()
|
||||||
{
|
{
|
||||||
@ -209,19 +223,22 @@ namespace CodeWalker.Rendering
|
|||||||
}
|
}
|
||||||
private void Resize()
|
private void Resize()
|
||||||
{
|
{
|
||||||
|
Console.WriteLine($"Resizing {Resizing}");
|
||||||
if (Resizing) return;
|
if (Resizing) return;
|
||||||
Monitor.Enter(syncroot);
|
semaphore.Wait();
|
||||||
int width = dxform.Form.ClientSize.Width;
|
int width = dxform.Form.ClientSize.Width;
|
||||||
int height = dxform.Form.ClientSize.Height;
|
int height = dxform.Form.ClientSize.Height;
|
||||||
|
|
||||||
if (targetview != null) targetview.Dispose();
|
if (targetview != null) targetview.Dispose();
|
||||||
if (backbuffer != null) backbuffer.Dispose();
|
if (backbuffer != null) backbuffer.Dispose();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
swapchain.ResizeBuffers(1, width, height, Format.Unknown, SwapChainFlags.AllowModeSwitch);
|
swapchain.ResizeBuffers(1, width, height, Format.Unknown, SwapChainFlags.AllowModeSwitch);
|
||||||
|
|
||||||
CreateRenderBuffers();
|
CreateRenderBuffers();
|
||||||
|
|
||||||
Monitor.Exit(syncroot);
|
semaphore.Release();
|
||||||
|
|
||||||
dxform.BuffersResized(width, height);
|
dxform.BuffersResized(width, height);
|
||||||
}
|
}
|
||||||
@ -244,6 +261,10 @@ namespace CodeWalker.Rendering
|
|||||||
}
|
}
|
||||||
if (!e.Cancel)
|
if (!e.Cancel)
|
||||||
{
|
{
|
||||||
|
if (!dxform.CancellationTokenSource.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
dxform.CancellationTokenSource.Cancel();
|
||||||
|
}
|
||||||
Cleanup();
|
Cleanup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -274,11 +295,38 @@ namespace CodeWalker.Rendering
|
|||||||
}
|
}
|
||||||
private void StartRenderLoop()
|
private void StartRenderLoop()
|
||||||
{
|
{
|
||||||
|
if (Running)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Running = true;
|
Running = true;
|
||||||
new Task(RenderLoop, TaskCreationOptions.LongRunning).Start(TaskScheduler.Default);
|
|
||||||
|
Task.Run(RenderLoop);
|
||||||
//new Thread(new ThreadStart(RenderLoop)).Start();
|
//new Thread(new ThreadStart(RenderLoop)).Start();
|
||||||
}
|
}
|
||||||
private void RenderLoop()
|
|
||||||
|
|
||||||
|
bool isPointVisibleOnAScreen(Point p)
|
||||||
|
{
|
||||||
|
foreach (Screen s in Screen.AllScreens)
|
||||||
|
{
|
||||||
|
if (p.X < s.Bounds.Right && p.X > s.Bounds.Left && p.Y > s.Bounds.Top && p.Y < s.Bounds.Bottom)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFormFullyVisible(Form f)
|
||||||
|
{
|
||||||
|
return isPointVisibleOnAScreen(new Point(f.Left, f.Top))
|
||||||
|
&& isPointVisibleOnAScreen(new Point(f.Right, f.Top))
|
||||||
|
&& isPointVisibleOnAScreen(new Point(f.Left, f.Bottom))
|
||||||
|
&& isPointVisibleOnAScreen(new Point(f.Right, f.Bottom));
|
||||||
|
}
|
||||||
|
|
||||||
|
private int inactiveCount = 0;
|
||||||
|
private async Task RenderLoop()
|
||||||
{
|
{
|
||||||
//SharpDX.Configuration.EnableObjectTracking = true;
|
//SharpDX.Configuration.EnableObjectTracking = true;
|
||||||
//Task.Run(async () =>
|
//Task.Run(async () =>
|
||||||
@ -289,7 +337,9 @@ namespace CodeWalker.Rendering
|
|||||||
// await Task.Delay(5000);
|
// await Task.Delay(5000);
|
||||||
// }
|
// }
|
||||||
//});
|
//});
|
||||||
Thread.CurrentThread.Name = "RenderLoop";
|
|
||||||
|
try
|
||||||
|
{
|
||||||
while (Running)
|
while (Running)
|
||||||
{
|
{
|
||||||
while (Resizing)
|
while (Resizing)
|
||||||
@ -301,13 +351,14 @@ namespace CodeWalker.Rendering
|
|||||||
dxform.Pauserendering = true;
|
dxform.Pauserendering = true;
|
||||||
|
|
||||||
Console.WriteLine("Window is minimized");
|
Console.WriteLine("Window is minimized");
|
||||||
dxform.RenderScene(context);
|
await dxform.RenderScene(context);
|
||||||
|
|
||||||
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
||||||
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
|
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true, true);
|
||||||
while (dxform.Form.WindowState == FormWindowState.Minimized)
|
while (dxform.Form.WindowState == FormWindowState.Minimized)
|
||||||
{
|
{
|
||||||
Thread.Sleep(100); //don't hog CPU when minimised
|
await Task.Delay(100, cancellationToken).ConfigureAwait(false); //don't hog CPU when minimised
|
||||||
if (dxform.Form.IsDisposed) return; //if closed while minimised
|
if (dxform.Form.IsDisposed || cancellationToken.IsCancellationRequested) return; //if closed while minimised
|
||||||
}
|
}
|
||||||
dxform.Pauserendering = false;
|
dxform.Pauserendering = false;
|
||||||
Console.WriteLine("Window is maximized");
|
Console.WriteLine("Window is maximized");
|
||||||
@ -316,20 +367,50 @@ namespace CodeWalker.Rendering
|
|||||||
|
|
||||||
if (Form.ActiveForm == null)
|
if (Form.ActiveForm == null)
|
||||||
{
|
{
|
||||||
Thread.Sleep(100); //reduce the FPS when the app isn't active (maybe this should be configurable?)
|
inactiveCount++;
|
||||||
if (context.IsDisposed) return; //if form closed while sleeping (eg from rightclick on taskbar)
|
if (inactiveCount > 100)
|
||||||
|
{
|
||||||
|
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
|
||||||
|
GC.Collect();
|
||||||
|
while (Form.ActiveForm == null)
|
||||||
|
{
|
||||||
|
await Task.Delay(100, cancellationToken).ConfigureAwait(false); //reduce the FPS when the app isn't active (maybe this should be configurable?)
|
||||||
|
if (context.IsDisposed || dxform.Form.IsDisposed || cancellationToken.IsCancellationRequested) return; //if form closed while sleeping (eg from rightclick on taskbar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Task.Delay(100, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
inactiveCount = 0;
|
||||||
|
if (Form.ActiveForm != dxform.Form)
|
||||||
|
{
|
||||||
|
await Task.Delay(25, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (context.IsDisposed || dxform.Form.IsDisposed || cancellationToken.IsCancellationRequested) return;
|
||||||
|
|
||||||
Rendering = true;
|
Rendering = true;
|
||||||
try
|
|
||||||
{
|
if (!await semaphore.WaitAsync(50, cancellationToken).ConfigureAwait(false))
|
||||||
if (!Monitor.TryEnter(syncroot, 50))
|
|
||||||
{
|
{
|
||||||
Console.WriteLine("Failed to get lock for syncroot");
|
Console.WriteLine("Failed to get lock for syncroot");
|
||||||
Thread.Sleep(10); //don't hog CPU when not able to render...
|
await Task.Delay(10, cancellationToken).ConfigureAwait(false); //don't hog CPU when not able to render...
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dxform.Form.IsDisposed || cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
Rendering = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -345,14 +426,14 @@ namespace CodeWalker.Rendering
|
|||||||
|
|
||||||
if (ok)
|
if (ok)
|
||||||
{
|
{
|
||||||
if (dxform.Form.IsDisposed)
|
if (dxform.Form.IsDisposed || cancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
Monitor.Exit(syncroot);
|
|
||||||
Rendering = false;
|
Rendering = false;
|
||||||
return; //the form was closed... stop!!
|
return; //the form was closed... stop!!
|
||||||
}
|
}
|
||||||
|
|
||||||
dxform.RenderScene(context);
|
await dxform.RenderScene(context);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -366,11 +447,22 @@ namespace CodeWalker.Rendering
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Monitor.Exit(syncroot);
|
semaphore.Release();
|
||||||
Rendering = false;
|
Rendering = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (TaskCanceledException) { }
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Running = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void ClearRenderTarget(DeviceContext ctx)
|
public void ClearRenderTarget(DeviceContext ctx)
|
||||||
|
@ -10,6 +10,7 @@ using Buffer = SharpDX.Direct3D11.Buffer;
|
|||||||
using CodeWalker.World;
|
using CodeWalker.World;
|
||||||
using SharpDX.Direct3D;
|
using SharpDX.Direct3D;
|
||||||
using SharpDX;
|
using SharpDX;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace CodeWalker.Rendering
|
namespace CodeWalker.Rendering
|
||||||
{
|
{
|
||||||
@ -72,6 +73,12 @@ namespace CodeWalker.Rendering
|
|||||||
public RenderableModel[] LowModels;
|
public RenderableModel[] LowModels;
|
||||||
public RenderableModel[] VlowModels;
|
public RenderableModel[] VlowModels;
|
||||||
public RenderableModel[] AllModels;
|
public RenderableModel[] AllModels;
|
||||||
|
|
||||||
|
public float LodDistanceHigh;
|
||||||
|
public float LodDistanceMed;
|
||||||
|
public float LodDistanceLow;
|
||||||
|
public float LodDistanceVLow;
|
||||||
|
|
||||||
//public Dictionary<uint, Texture> TextureDict { get; private set; }
|
//public Dictionary<uint, Texture> TextureDict { get; private set; }
|
||||||
//public long EmbeddedTextureSize { get; private set; }
|
//public long EmbeddedTextureSize { get; private set; }
|
||||||
|
|
||||||
@ -148,6 +155,10 @@ namespace CodeWalker.Rendering
|
|||||||
curmodel += vlow.Length;
|
curmodel += vlow.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LodDistanceHigh = drawable.LodDistHigh;
|
||||||
|
LodDistanceMed = drawable.LodDistMed;
|
||||||
|
LodDistanceLow = drawable.LodDistLow;
|
||||||
|
LodDistanceVLow = drawable.LodDistVlow;
|
||||||
|
|
||||||
//var sg = Drawable.ShaderGroup;
|
//var sg = Drawable.ShaderGroup;
|
||||||
//if ((sg != null) && (sg.TextureDictionary != null))
|
//if ((sg != null) && (sg.TextureDictionary != null))
|
||||||
@ -346,6 +357,30 @@ namespace CodeWalker.Rendering
|
|||||||
Lights = rlights;
|
Lights = rlights;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public RenderableModel[] GetModels(float distance)
|
||||||
|
{
|
||||||
|
if (distance > LodDistanceVLow)
|
||||||
|
{
|
||||||
|
return Array.Empty<RenderableModel>();
|
||||||
|
}
|
||||||
|
else if (distance > LodDistanceLow)
|
||||||
|
{
|
||||||
|
return VlowModels ?? Array.Empty<RenderableModel>();
|
||||||
|
}
|
||||||
|
else if (distance > LodDistanceMed)
|
||||||
|
{
|
||||||
|
return LowModels ?? Array.Empty<RenderableModel>();
|
||||||
|
}
|
||||||
|
else if (distance > LodDistanceHigh)
|
||||||
|
{
|
||||||
|
return MedModels ?? Array.Empty<RenderableModel>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return HDModels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private RenderableModel InitModel(DrawableModel dm)
|
private RenderableModel InitModel(DrawableModel dm)
|
||||||
{
|
{
|
||||||
var rmodel = new RenderableModel();
|
var rmodel = new RenderableModel();
|
||||||
@ -723,7 +758,7 @@ namespace CodeWalker.Rendering
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var model in HDModels) //TODO: figure out which models/geometries this should be applying to!
|
foreach (var model in AllModels) //TODO: figure out which models/geometries this should be applying to!
|
||||||
{
|
{
|
||||||
if (model == null) continue;
|
if (model == null) continue;
|
||||||
foreach (var geom in model.Geometries)
|
foreach (var geom in model.Geometries)
|
||||||
|
@ -11,6 +11,7 @@ using System.Collections.Concurrent;
|
|||||||
using CodeWalker.GameFiles;
|
using CodeWalker.GameFiles;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using CodeWalker.Properties;
|
using CodeWalker.Properties;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace CodeWalker.Rendering
|
namespace CodeWalker.Rendering
|
||||||
{
|
{
|
||||||
@ -20,7 +21,7 @@ namespace CodeWalker.Rendering
|
|||||||
public DateTime LastUnload = DateTime.UtcNow;
|
public DateTime LastUnload = DateTime.UtcNow;
|
||||||
public double CacheTime = Settings.Default.GPUCacheTime;// 10.0; //seconds to keep something that's not used
|
public double CacheTime = Settings.Default.GPUCacheTime;// 10.0; //seconds to keep something that's not used
|
||||||
public double UnloadTime = Settings.Default.GPUCacheFlushTime;// 0.1; //seconds between running unload cycles
|
public double UnloadTime = Settings.Default.GPUCacheFlushTime;// 0.1; //seconds between running unload cycles
|
||||||
public int MaxItemsPerLoop = 1; //to keep things flowing
|
public int MaxItemsPerLoop = 3; //to keep things flowing
|
||||||
|
|
||||||
public long TotalGraphicsMemoryUse
|
public long TotalGraphicsMemoryUse
|
||||||
{
|
{
|
||||||
@ -117,6 +118,11 @@ namespace CodeWalker.Rendering
|
|||||||
{
|
{
|
||||||
currentDevice = null;
|
currentDevice = null;
|
||||||
|
|
||||||
|
Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
renderables.Clear();
|
renderables.Clear();
|
||||||
textures.Clear();
|
textures.Clear();
|
||||||
boundcomps.Clear();
|
boundcomps.Clear();
|
||||||
@ -132,8 +138,8 @@ namespace CodeWalker.Rendering
|
|||||||
if (currentDevice == null) return false; //can't do anything with no device
|
if (currentDevice == null) return false; //can't do anything with no device
|
||||||
|
|
||||||
Monitor.Enter(updateSyncRoot);
|
Monitor.Enter(updateSyncRoot);
|
||||||
|
try
|
||||||
|
{
|
||||||
//load the queued items if possible
|
//load the queued items if possible
|
||||||
int renderablecount = renderables.LoadProc(currentDevice, MaxItemsPerLoop);
|
int renderablecount = renderables.LoadProc(currentDevice, MaxItemsPerLoop);
|
||||||
int texturecount = textures.LoadProc(currentDevice, MaxItemsPerLoop);
|
int texturecount = textures.LoadProc(currentDevice, MaxItemsPerLoop);
|
||||||
@ -160,7 +166,8 @@ namespace CodeWalker.Rendering
|
|||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
var deltat = (now - LastUpdate).TotalSeconds;
|
var deltat = (now - LastUpdate).TotalSeconds;
|
||||||
var unloadt = (now - LastUnload).TotalSeconds;
|
var unloadt = (now - LastUnload).TotalSeconds;
|
||||||
if ((unloadt > UnloadTime) && (deltat < 0.25)) //don't try the unload on every loop... or when really busy
|
//Console.WriteLine($"deltat: {deltat}; unloadt: {unloadt}; UnloadTime: {UnloadTime};");
|
||||||
|
if ((unloadt > UnloadTime) && (deltat < 1.0)) //don't try the unload on every loop... or when really busy
|
||||||
{
|
{
|
||||||
|
|
||||||
//unload items that haven't been used in longer than the cache period.
|
//unload items that haven't been used in longer than the cache period.
|
||||||
@ -179,10 +186,18 @@ namespace CodeWalker.Rendering
|
|||||||
|
|
||||||
LastUpdate = DateTime.UtcNow;
|
LastUpdate = DateTime.UtcNow;
|
||||||
|
|
||||||
Monitor.Exit(updateSyncRoot);
|
|
||||||
|
|
||||||
return itemsStillPending;
|
return itemsStillPending;
|
||||||
}
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine(ex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Monitor.Exit(updateSyncRoot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void RenderThreadSync()
|
public void RenderThreadSync()
|
||||||
{
|
{
|
||||||
@ -255,13 +270,20 @@ namespace CodeWalker.Rendering
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum LoadFlags
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
IsLoaded = 1,
|
||||||
|
LoadQueued = 2,
|
||||||
|
}
|
||||||
|
|
||||||
public abstract class RenderableCacheItem<TKey>
|
public abstract class RenderableCacheItem<TKey>
|
||||||
{
|
{
|
||||||
public TKey Key;
|
public TKey Key;
|
||||||
public volatile bool IsLoaded = false;
|
public volatile bool IsLoaded = false;
|
||||||
public volatile bool LoadQueued = false;
|
public volatile bool LoadQueued = false;
|
||||||
public long LastUseTime = 0;
|
public Stopwatch LastUseTime = Stopwatch.StartNew();
|
||||||
//public DateTime LastUseTime { get; set; }
|
//public DateTime LastUseTime { get; set; }
|
||||||
public long DataSize { get; set; }
|
public long DataSize { get; set; }
|
||||||
|
|
||||||
@ -333,7 +355,14 @@ namespace CodeWalker.Rendering
|
|||||||
LoadedCount = 0;
|
LoadedCount = 0;
|
||||||
while (itemsToLoad.TryDequeue(out item))
|
while (itemsToLoad.TryDequeue(out item))
|
||||||
{
|
{
|
||||||
if (item.IsLoaded) continue; //don't load it again...
|
if (item.IsLoaded)
|
||||||
|
{
|
||||||
|
item.LoadQueued = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
LoadedCount++;
|
LoadedCount++;
|
||||||
long gcachefree = CacheLimit - Interlocked.Read(ref CacheUse);// CacheUse;
|
long gcachefree = CacheLimit - Interlocked.Read(ref CacheUse);// CacheUse;
|
||||||
if (gcachefree > item.DataSize)
|
if (gcachefree > item.DataSize)
|
||||||
@ -344,15 +373,21 @@ namespace CodeWalker.Rendering
|
|||||||
loadeditems.AddLast(item);
|
loadeditems.AddLast(item);
|
||||||
Interlocked.Add(ref CacheUse, item.DataSize);
|
Interlocked.Add(ref CacheUse, item.DataSize);
|
||||||
}
|
}
|
||||||
catch //(Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
//todo: error handling...
|
Console.WriteLine(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
item.LoadQueued = false; //can try load it again later..
|
Console.WriteLine(ex);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
item.LoadQueued = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (LoadedCount >= maxitemsperloop) break;
|
if (LoadedCount >= maxitemsperloop) break;
|
||||||
}
|
}
|
||||||
return LoadedCount;
|
return LoadedCount;
|
||||||
@ -361,12 +396,12 @@ namespace CodeWalker.Rendering
|
|||||||
public void UnloadProc()
|
public void UnloadProc()
|
||||||
{
|
{
|
||||||
//unload items that haven't been used in longer than the cache period.
|
//unload items that haven't been used in longer than the cache period.
|
||||||
var now = DateTime.UtcNow;
|
//var now = DateTime.UtcNow;
|
||||||
var rnode = loadeditems.First;
|
var rnode = loadeditems.First;
|
||||||
while (rnode != null)
|
while (rnode != null)
|
||||||
{
|
{
|
||||||
var lu = DateTime.FromBinary(Interlocked.Read(ref rnode.Value.LastUseTime));
|
var lastUsed = rnode.Value.LastUseTime.Elapsed;
|
||||||
if ((now - lu).TotalSeconds > CacheTime)
|
if (lastUsed.TotalSeconds > CacheTime)
|
||||||
{
|
{
|
||||||
var nextnode = rnode.Next;
|
var nextnode = rnode.Next;
|
||||||
itemsToUnload.Enqueue(rnode.Value);
|
itemsToUnload.Enqueue(rnode.Value);
|
||||||
@ -399,7 +434,7 @@ namespace CodeWalker.Rendering
|
|||||||
}
|
}
|
||||||
while (itemsToUnload.TryDequeue(out item))
|
while (itemsToUnload.TryDequeue(out item))
|
||||||
{
|
{
|
||||||
if ((item.Key != null) && (cacheitems.ContainsKey(item.Key)))
|
if (item.Key != null && cacheitems.ContainsKey(item.Key))
|
||||||
{
|
{
|
||||||
cacheitems.Remove(item.Key);
|
cacheitems.Remove(item.Key);
|
||||||
}
|
}
|
||||||
@ -420,7 +455,7 @@ namespace CodeWalker.Rendering
|
|||||||
item.Init(key);
|
item.Init(key);
|
||||||
cacheitems.Add(key, item);
|
cacheitems.Add(key, item);
|
||||||
}
|
}
|
||||||
Interlocked.Exchange(ref item.LastUseTime, LastFrameTime);
|
item.LastUseTime.Restart();
|
||||||
if ((!item.IsLoaded) && (!item.LoadQueued))// ||
|
if ((!item.IsLoaded) && (!item.LoadQueued))// ||
|
||||||
{
|
{
|
||||||
item.LoadQueued = true;
|
item.LoadQueued = true;
|
||||||
|
@ -173,7 +173,7 @@ namespace CodeWalker.Rendering
|
|||||||
public Renderer(DXForm form, GameFileCache cache)
|
public Renderer(DXForm form, GameFileCache cache)
|
||||||
{
|
{
|
||||||
Form = form;
|
Form = form;
|
||||||
gameFileCache = cache ?? GameFileCacheFactory.Create();
|
gameFileCache = cache ?? GameFileCacheFactory.GetInstance();
|
||||||
renderableCache = new RenderableCache();
|
renderableCache = new RenderableCache();
|
||||||
|
|
||||||
var s = Settings.Default;
|
var s = Settings.Default;
|
||||||
@ -386,8 +386,11 @@ namespace CodeWalker.Rendering
|
|||||||
var ctc = renderableCache.LoadedTextureCount;
|
var ctc = renderableCache.LoadedTextureCount;
|
||||||
var vr = renderableCache.TotalGraphicsMemoryUse + (shaders != null ? shaders.TotalGraphicsMemoryUse : 0);
|
var vr = renderableCache.TotalGraphicsMemoryUse + (shaders != null ? shaders.TotalGraphicsMemoryUse : 0);
|
||||||
var vram = TextUtil.GetBytesReadable(vr);
|
var vram = TextUtil.GetBytesReadable(vr);
|
||||||
|
var cacheUsage = TextUtil.GetBytesReadable(gameFileCache.MemoryUsage);
|
||||||
|
var cacheMax = TextUtil.GetBytesReadable(gameFileCache.MaxMemoryUsage);
|
||||||
|
|
||||||
return $"Drawn: {rgc} geom, Loaded: {crc} dr, {ctc} tx, Vram: {vram}, Fps: {fps}";
|
|
||||||
|
return $"Drawn: {rgc} geom, Loaded: {crc} dr, {ctc} tx, Vram: {vram}, Fps: {fps}, Cache: {cacheUsage}/{cacheMax}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1690,7 +1693,7 @@ namespace CodeWalker.Rendering
|
|||||||
for (int i = 0; i < frag.Layers.Length; i++)
|
for (int i = 0; i < frag.Layers.Length; i++)
|
||||||
{
|
{
|
||||||
CloudHatFragLayer layer = frag.Layers[i];
|
CloudHatFragLayer layer = frag.Layers[i];
|
||||||
uint dhash = JenkHash.GenHash(layer.Filename.ToLowerInvariant());
|
uint dhash = JenkHash.GenHashLower(layer.Filename);
|
||||||
Archetype arch = gameFileCache.GetArchetype(dhash);
|
Archetype arch = gameFileCache.GetArchetype(dhash);
|
||||||
if (arch == null)
|
if (arch == null)
|
||||||
{ continue; }
|
{ continue; }
|
||||||
@ -1700,8 +1703,10 @@ namespace CodeWalker.Rendering
|
|||||||
var drw = gameFileCache.TryGetDrawable(arch);
|
var drw = gameFileCache.TryGetDrawable(arch);
|
||||||
var rnd = TryGetRenderable(arch, drw);
|
var rnd = TryGetRenderable(arch, drw);
|
||||||
|
|
||||||
if ((rnd == null) || (rnd.IsLoaded == false) || (rnd.AllTexturesLoaded == false))
|
if (rnd == null || !rnd.IsLoaded || !rnd.AllTexturesLoaded)
|
||||||
{ continue; }
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
RenderableInst rinst = new RenderableInst();
|
RenderableInst rinst = new RenderableInst();
|
||||||
@ -2051,7 +2056,7 @@ namespace CodeWalker.Rendering
|
|||||||
|
|
||||||
|
|
||||||
ent.Distance = dist;
|
ent.Distance = dist;
|
||||||
ent.IsVisible = (dist <= loddist);
|
ent.IsWithinLodDist = (dist <= loddist);
|
||||||
ent.ChildrenVisible = (dist <= cloddist) && (ent._CEntityDef.numChildren > 0);
|
ent.ChildrenVisible = (dist <= cloddist) && (ent._CEntityDef.numChildren > 0);
|
||||||
|
|
||||||
|
|
||||||
@ -2061,7 +2066,7 @@ namespace CodeWalker.Rendering
|
|||||||
if ((ent._CEntityDef.lodLevel == rage__eLodType.LODTYPES_DEPTH_ORPHANHD) ||
|
if ((ent._CEntityDef.lodLevel == rage__eLodType.LODTYPES_DEPTH_ORPHANHD) ||
|
||||||
(ent._CEntityDef.lodLevel < renderworldMaxLOD))
|
(ent._CEntityDef.lodLevel < renderworldMaxLOD))
|
||||||
{
|
{
|
||||||
ent.IsVisible = false;
|
ent.IsWithinLodDist = false;
|
||||||
ent.ChildrenVisible = false;
|
ent.ChildrenVisible = false;
|
||||||
}
|
}
|
||||||
if (ent._CEntityDef.lodLevel == renderworldMaxLOD)
|
if (ent._CEntityDef.lodLevel == renderworldMaxLOD)
|
||||||
@ -2090,9 +2095,10 @@ namespace CodeWalker.Rendering
|
|||||||
}
|
}
|
||||||
private void RenderWorldRecurseAddEntities(YmapEntityDef ent)
|
private void RenderWorldRecurseAddEntities(YmapEntityDef ent)
|
||||||
{
|
{
|
||||||
bool hide = ent.ChildrenVisible;
|
bool childrenVisible = ent.ChildrenVisible;
|
||||||
bool force = (ent.Parent != null) && ent.Parent.ChildrenVisible && !hide;
|
var parentChildrenVisible = ent.Parent?.ChildrenVisible ?? true;
|
||||||
if (force || (ent.IsVisible && !hide))
|
bool force = parentChildrenVisible && !childrenVisible;
|
||||||
|
if (force || (ent.IsWithinLodDist && !childrenVisible))
|
||||||
{
|
{
|
||||||
if (ent.Archetype != null)
|
if (ent.Archetype != null)
|
||||||
{
|
{
|
||||||
@ -2115,7 +2121,7 @@ namespace CodeWalker.Rendering
|
|||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ent.IsVisible && ent.ChildrenVisible && (ent.Children != null))
|
if (ent.IsWithinLodDist && ent.ChildrenVisible && (ent.Children != null))
|
||||||
{
|
{
|
||||||
for (int i = 0; i < ent.Children.Length; i++)
|
for (int i = 0; i < ent.Children.Length; i++)
|
||||||
{
|
{
|
||||||
@ -2167,7 +2173,7 @@ namespace CodeWalker.Rendering
|
|||||||
if (intent?.Archetype == null) continue; //missing archetype...
|
if (intent?.Archetype == null) continue; //missing archetype...
|
||||||
if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something..
|
if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something..
|
||||||
|
|
||||||
intent.IsVisible = true;
|
intent.IsWithinLodDist = true;
|
||||||
|
|
||||||
if (!camera.ViewFrustum.ContainsAABBNoClip(ref intent.BBCenter, ref intent.BBExtent))
|
if (!camera.ViewFrustum.ContainsAABBNoClip(ref intent.BBCenter, ref intent.BBExtent))
|
||||||
{
|
{
|
||||||
@ -2192,7 +2198,7 @@ namespace CodeWalker.Rendering
|
|||||||
if (intent?.Archetype == null) continue; //missing archetype...
|
if (intent?.Archetype == null) continue; //missing archetype...
|
||||||
if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something..
|
if (!RenderIsEntityFinalRender(intent)) continue; //proxy or something..
|
||||||
|
|
||||||
intent.IsVisible = true;
|
intent.IsWithinLodDist = true;
|
||||||
|
|
||||||
if (!camera.ViewFrustum.ContainsAABBNoClip(ref intent.BBCenter, ref intent.BBExtent))
|
if (!camera.ViewFrustum.ContainsAABBNoClip(ref intent.BBCenter, ref intent.BBExtent))
|
||||||
{
|
{
|
||||||
@ -2390,8 +2396,11 @@ namespace CodeWalker.Rendering
|
|||||||
{
|
{
|
||||||
var drawable = gameFileCache.TryGetDrawable(arch);
|
var drawable = gameFileCache.TryGetDrawable(arch);
|
||||||
rndbl = TryGetRenderable(arch, drawable);
|
rndbl = TryGetRenderable(arch, drawable);
|
||||||
|
if (rndbl != null && rndbl.IsLoaded)
|
||||||
|
{
|
||||||
ArchetypeRenderables[arch] = rndbl;
|
ArchetypeRenderables[arch] = rndbl;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if ((rndbl != null) && rndbl.IsLoaded && (rndbl.AllTexturesLoaded || !waitforchildrentoload))
|
if ((rndbl != null) && rndbl.IsLoaded && (rndbl.AllTexturesLoaded || !waitforchildrentoload))
|
||||||
{
|
{
|
||||||
return rndbl;
|
return rndbl;
|
||||||
@ -2457,7 +2466,10 @@ namespace CodeWalker.Rendering
|
|||||||
}
|
}
|
||||||
private bool RenderYmapLOD(YmapFile ymap, YmapEntityDef entity)
|
private bool RenderYmapLOD(YmapFile ymap, YmapEntityDef entity)
|
||||||
{
|
{
|
||||||
if (!ymap.Loaded) return false;
|
if (!ymap.Loaded)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ymap.EnsureChildYmaps(gameFileCache);
|
ymap.EnsureChildYmaps(gameFileCache);
|
||||||
|
|
||||||
@ -3020,8 +3032,11 @@ namespace CodeWalker.Rendering
|
|||||||
rndbl = TryGetRenderable(arche, drawable);
|
rndbl = TryGetRenderable(arche, drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rndbl != null)
|
if (rndbl == null || !rndbl.IsLoaded)
|
||||||
{
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (animClip != null)
|
if (animClip != null)
|
||||||
{
|
{
|
||||||
rndbl.ClipMapEntry = animClip;
|
rndbl.ClipMapEntry = animClip;
|
||||||
@ -3041,14 +3056,13 @@ namespace CodeWalker.Rendering
|
|||||||
if ((frag != null) && (frag.DrawableCloth != null)) //cloth...
|
if ((frag != null) && (frag.DrawableCloth != null)) //cloth...
|
||||||
{
|
{
|
||||||
rndbl = TryGetRenderable(arche, frag.DrawableCloth);
|
rndbl = TryGetRenderable(arche, frag.DrawableCloth);
|
||||||
if (rndbl != null)
|
if (rndbl != null && rndbl.IsLoaded)
|
||||||
{
|
{
|
||||||
bool res2 = RenderRenderable(rndbl, arche, entity);
|
bool res2 = RenderRenderable(rndbl, arche, entity);
|
||||||
res = res || res2;
|
res = res || res2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -3062,7 +3076,7 @@ namespace CodeWalker.Rendering
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Renderable rndbl = TryGetRenderable(arche, drawable, txdHash, txdExtra, diffOverride);
|
Renderable rndbl = TryGetRenderable(arche, drawable, txdHash, txdExtra, diffOverride);
|
||||||
if (rndbl == null)
|
if (rndbl == null || !rndbl.IsLoaded)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (animClip != null)
|
if (animClip != null)
|
||||||
@ -3243,7 +3257,7 @@ namespace CodeWalker.Rendering
|
|||||||
rginst.Inst.CastShadow = castshadow;
|
rginst.Inst.CastShadow = castshadow;
|
||||||
|
|
||||||
|
|
||||||
RenderableModel[] models = isselected ? rndbl.AllModels : rndbl.HDModels;
|
RenderableModel[] models = isselected ? rndbl.HDModels : rndbl.GetModels(distance);
|
||||||
|
|
||||||
for (int mi = 0; mi < models.Length; mi++)
|
for (int mi = 0; mi < models.Length; mi++)
|
||||||
{
|
{
|
||||||
@ -3568,17 +3582,23 @@ namespace CodeWalker.Rendering
|
|||||||
MetaHash ahash = arche.Hash;
|
MetaHash ahash = arche.Hash;
|
||||||
if (ycd.ClipMap.TryGetValue(ahash, out rndbl.ClipMapEntry)) rndbl.HasAnims = true;
|
if (ycd.ClipMap.TryGetValue(ahash, out rndbl.ClipMapEntry)) rndbl.HasAnims = true;
|
||||||
|
|
||||||
foreach (var model in rndbl.HDModels)
|
var models = rndbl.HDModels;
|
||||||
|
for (int i = 0; i < models.Length; i++)
|
||||||
{
|
{
|
||||||
if (model == null) continue;
|
var model = models[i];
|
||||||
foreach (var geom in model.Geometries)
|
if (models[i] == null)
|
||||||
|
continue;
|
||||||
|
for (int j = 0; j < model.Geometries.Length; j++)
|
||||||
{
|
{
|
||||||
if (geom == null) continue;
|
var geom = model.Geometries[j];
|
||||||
|
if (geom == null)
|
||||||
|
continue;
|
||||||
if (geom.globalAnimUVEnable)
|
if (geom.globalAnimUVEnable)
|
||||||
{
|
{
|
||||||
uint cmeindex = geom.DrawableGeom.ShaderID + 1u;
|
uint cmeindex = geom.DrawableGeom.ShaderID + 1u;
|
||||||
MetaHash cmehash = ahash + cmeindex; //this goes to at least uv5! (from uv0) - see hw1_09.ycd
|
MetaHash cmehash = ahash + cmeindex; //this goes to at least uv5! (from uv0) - see hw1_09.ycd
|
||||||
if (ycd.ClipMap.TryGetValue(cmehash, out geom.ClipMapEntryUV)) rndbl.HasAnims = true;
|
if (ycd.ClipMap.TryGetValue(cmehash, out geom.ClipMapEntryUV))
|
||||||
|
rndbl.HasAnims = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3587,7 +3607,8 @@ namespace CodeWalker.Rendering
|
|||||||
|
|
||||||
|
|
||||||
var extraTexDict = (drawable.Owner as YptFile)?.PtfxList?.TextureDictionary;
|
var extraTexDict = (drawable.Owner as YptFile)?.PtfxList?.TextureDictionary;
|
||||||
if (extraTexDict == null) extraTexDict = txdExtra;
|
if (extraTexDict == null)
|
||||||
|
extraTexDict = txdExtra;
|
||||||
|
|
||||||
bool cacheSD = (rndbl.SDtxds == null);
|
bool cacheSD = (rndbl.SDtxds == null);
|
||||||
bool cacheHD = (renderhdtextures && (rndbl.HDtxds == null));
|
bool cacheHD = (renderhdtextures && (rndbl.HDtxds == null));
|
||||||
|
@ -851,10 +851,11 @@ namespace CodeWalker.Rendering
|
|||||||
if (batch.Renderable.HDModels.Length > 1)
|
if (batch.Renderable.HDModels.Length > 1)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
foreach (var model in batch.Renderable.HDModels)
|
for(int i = 0; i < batch.Renderable.HDModels.Length; i++)
|
||||||
{
|
{
|
||||||
if (model.Geometries.Length > 1)
|
var model = batch.Renderable.HDModels[i];
|
||||||
{ }
|
if (model.Geometries.Length == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
Basic.SetModelVars(context, model);
|
Basic.SetModelVars(context, model);
|
||||||
foreach (var geom in model.Geometries)
|
foreach (var geom in model.Geometries)
|
||||||
@ -866,6 +867,7 @@ namespace CodeWalker.Rendering
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ namespace CodeWalker.Tools
|
|||||||
|
|
||||||
curfile++;
|
curfile++;
|
||||||
|
|
||||||
if (fentry.Name.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase))
|
if (fentry.IsExtension(".rpf"))
|
||||||
{ continue; }
|
{ continue; }
|
||||||
|
|
||||||
if (onlyexts != null)
|
if (onlyexts != null)
|
||||||
|
6
CodeWalker/Tools/BrowseForm.Designer.cs
generated
6
CodeWalker/Tools/BrowseForm.Designer.cs
generated
@ -1,4 +1,6 @@
|
|||||||
namespace CodeWalker.Tools
|
using CodeWalker.Forms;
|
||||||
|
|
||||||
|
namespace CodeWalker.Tools
|
||||||
{
|
{
|
||||||
partial class BrowseForm
|
partial class BrowseForm
|
||||||
{
|
{
|
||||||
@ -78,7 +80,7 @@
|
|||||||
this.SelTextureMipTrackBar = new System.Windows.Forms.TrackBar();
|
this.SelTextureMipTrackBar = new System.Windows.Forms.TrackBar();
|
||||||
this.label4 = new System.Windows.Forms.Label();
|
this.label4 = new System.Windows.Forms.Label();
|
||||||
this.SelTextureNameTextBox = new System.Windows.Forms.TextBox();
|
this.SelTextureNameTextBox = new System.Windows.Forms.TextBox();
|
||||||
this.SelTexturePictureBox = new System.Windows.Forms.PictureBox();
|
this.SelTexturePictureBox = new PixelBox();
|
||||||
this.MainStatusStrip = new System.Windows.Forms.StatusStrip();
|
this.MainStatusStrip = new System.Windows.Forms.StatusStrip();
|
||||||
this.StatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
this.StatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
|
||||||
this.TestAllButton = new System.Windows.Forms.Button();
|
this.TestAllButton = new System.Windows.Forms.Button();
|
||||||
|
@ -218,7 +218,7 @@ namespace CodeWalker.Tools
|
|||||||
{
|
{
|
||||||
if (entry is RpfFileEntry)
|
if (entry is RpfFileEntry)
|
||||||
{
|
{
|
||||||
bool show = !entry.Name.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase); //rpf entries get their own root node..
|
bool show = !entry.IsExtension(".rpf"); //rpf entries get their own root node..
|
||||||
if (show)
|
if (show)
|
||||||
{
|
{
|
||||||
//string text = entry.Path.Substring(file.Path.Length + 1); //includes \ on the end
|
//string text = entry.Path.Substring(file.Path.Length + 1); //includes \ on the end
|
||||||
@ -234,14 +234,14 @@ namespace CodeWalker.Tools
|
|||||||
JenkIndex.Ensure(file.Name);
|
JenkIndex.Ensure(file.Name);
|
||||||
foreach (RpfEntry entry in file.AllEntries)
|
foreach (RpfEntry entry in file.AllEntries)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(entry.Name)) continue;
|
if (string.IsNullOrEmpty(entry.Name))
|
||||||
JenkIndex.Ensure(entry.Name);
|
continue;
|
||||||
JenkIndex.Ensure(entry.NameLower);
|
|
||||||
int ind = entry.Name.LastIndexOf('.');
|
JenkIndex.EnsureBoth(entry.Name);
|
||||||
if (ind > 0)
|
var shortName = entry.ShortName;
|
||||||
|
if (shortName != entry.Name)
|
||||||
{
|
{
|
||||||
JenkIndex.Ensure(entry.Name.Substring(0, ind));
|
JenkIndex.EnsureBoth(shortName);
|
||||||
JenkIndex.Ensure(entry.NameLower.Substring(0, ind));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -368,43 +368,43 @@ namespace CodeWalker.Tools
|
|||||||
bool istexdict = false;
|
bool istexdict = false;
|
||||||
|
|
||||||
|
|
||||||
if (rfe.NameLower.EndsWith(".ymap"))
|
if (rfe.IsExtension(".ymap"))
|
||||||
{
|
{
|
||||||
YmapFile ymap = new YmapFile(rfe);
|
YmapFile ymap = new YmapFile(rfe);
|
||||||
ymap.Load(data, rfe);
|
ymap.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = ymap;
|
DetailsPropertyGrid.SelectedObject = ymap;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ytyp"))
|
else if (rfe.IsExtension(".ytyp"))
|
||||||
{
|
{
|
||||||
YtypFile ytyp = new YtypFile();
|
YtypFile ytyp = new YtypFile();
|
||||||
ytyp.Load(data, rfe);
|
ytyp.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = ytyp;
|
DetailsPropertyGrid.SelectedObject = ytyp;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ymf"))
|
else if (rfe.IsExtension(".ymf"))
|
||||||
{
|
{
|
||||||
YmfFile ymf = new YmfFile();
|
YmfFile ymf = new YmfFile();
|
||||||
ymf.Load(data, rfe);
|
ymf.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = ymf;
|
DetailsPropertyGrid.SelectedObject = ymf;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ymt"))
|
else if (rfe.IsExtension(".ymt"))
|
||||||
{
|
{
|
||||||
YmtFile ymt = new YmtFile();
|
YmtFile ymt = new YmtFile();
|
||||||
ymt.Load(data, rfe);
|
ymt.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = ymt;
|
DetailsPropertyGrid.SelectedObject = ymt;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ybn"))
|
else if (rfe.IsExtension(".ybn"))
|
||||||
{
|
{
|
||||||
YbnFile ybn = new YbnFile();
|
YbnFile ybn = new YbnFile();
|
||||||
ybn.Load(data, rfe);
|
ybn.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = ybn;
|
DetailsPropertyGrid.SelectedObject = ybn;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".fxc"))
|
else if (rfe.IsExtension(".fxc"))
|
||||||
{
|
{
|
||||||
FxcFile fxc = new FxcFile();
|
FxcFile fxc = new FxcFile();
|
||||||
fxc.Load(data, rfe);
|
fxc.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = fxc;
|
DetailsPropertyGrid.SelectedObject = fxc;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".yft"))
|
else if (rfe.IsExtension(".yft"))
|
||||||
{
|
{
|
||||||
YftFile yft = new YftFile();
|
YftFile yft = new YftFile();
|
||||||
yft.Load(data, rfe);
|
yft.Load(data, rfe);
|
||||||
@ -416,7 +416,7 @@ namespace CodeWalker.Tools
|
|||||||
istexdict = true;
|
istexdict = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ydr"))
|
else if (rfe.IsExtension(".ydr"))
|
||||||
{
|
{
|
||||||
YdrFile ydr = new YdrFile();
|
YdrFile ydr = new YdrFile();
|
||||||
ydr.Load(data, rfe);
|
ydr.Load(data, rfe);
|
||||||
@ -428,14 +428,14 @@ namespace CodeWalker.Tools
|
|||||||
istexdict = true;
|
istexdict = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ydd"))
|
else if (rfe.IsExtension(".ydd"))
|
||||||
{
|
{
|
||||||
YddFile ydd = new YddFile();
|
YddFile ydd = new YddFile();
|
||||||
ydd.Load(data, rfe);
|
ydd.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = ydd;
|
DetailsPropertyGrid.SelectedObject = ydd;
|
||||||
//todo: show embedded texdicts in ydd's? is this possible?
|
//todo: show embedded texdicts in ydd's? is this possible?
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ytd"))
|
else if (rfe.IsExtension(".ytd"))
|
||||||
{
|
{
|
||||||
YtdFile ytd = new YtdFile();
|
YtdFile ytd = new YtdFile();
|
||||||
ytd.Load(data, rfe);
|
ytd.Load(data, rfe);
|
||||||
@ -443,43 +443,43 @@ namespace CodeWalker.Tools
|
|||||||
ShowTextures(ytd.TextureDict);
|
ShowTextures(ytd.TextureDict);
|
||||||
istexdict = true;
|
istexdict = true;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ycd"))
|
else if (rfe.IsExtension(".ycd"))
|
||||||
{
|
{
|
||||||
YcdFile ycd = new YcdFile();
|
YcdFile ycd = new YcdFile();
|
||||||
ycd.Load(data, rfe);
|
ycd.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = ycd;
|
DetailsPropertyGrid.SelectedObject = ycd;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ynd"))
|
else if (rfe.IsExtension(".ynd"))
|
||||||
{
|
{
|
||||||
YndFile ynd = new YndFile();
|
YndFile ynd = new YndFile();
|
||||||
ynd.Load(data, rfe);
|
ynd.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = ynd;
|
DetailsPropertyGrid.SelectedObject = ynd;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".ynv"))
|
else if (rfe.IsExtension(".ynv"))
|
||||||
{
|
{
|
||||||
YnvFile ynv = new YnvFile();
|
YnvFile ynv = new YnvFile();
|
||||||
ynv.Load(data, rfe);
|
ynv.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = ynv;
|
DetailsPropertyGrid.SelectedObject = ynv;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith("_cache_y.dat"))
|
else if (rfe.Name.EndsWith("_cache_y.dat", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
CacheDatFile cdf = new CacheDatFile();
|
CacheDatFile cdf = new CacheDatFile();
|
||||||
cdf.Load(data, rfe);
|
cdf.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = cdf;
|
DetailsPropertyGrid.SelectedObject = cdf;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".rel"))
|
else if (rfe.IsExtension(".rel"))
|
||||||
{
|
{
|
||||||
RelFile rel = new RelFile(rfe);
|
RelFile rel = new RelFile(rfe);
|
||||||
rel.Load(data, rfe);
|
rel.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = rel;
|
DetailsPropertyGrid.SelectedObject = rel;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".gxt2"))
|
else if (rfe.IsExtension(".gxt2"))
|
||||||
{
|
{
|
||||||
Gxt2File gxt2 = new Gxt2File();
|
Gxt2File gxt2 = new Gxt2File();
|
||||||
gxt2.Load(data, rfe);
|
gxt2.Load(data, rfe);
|
||||||
DetailsPropertyGrid.SelectedObject = gxt2;
|
DetailsPropertyGrid.SelectedObject = gxt2;
|
||||||
}
|
}
|
||||||
else if (rfe.NameLower.EndsWith(".pso"))
|
else if (rfe.IsExtension(".pso"))
|
||||||
{
|
{
|
||||||
JPsoFile pso = new JPsoFile();
|
JPsoFile pso = new JPsoFile();
|
||||||
pso.Load(data, rfe);
|
pso.Load(data, rfe);
|
||||||
@ -797,14 +797,14 @@ namespace CodeWalker.Tools
|
|||||||
int max = 500;
|
int max = 500;
|
||||||
foreach (RpfFile file in ScannedFiles)
|
foreach (RpfFile file in ScannedFiles)
|
||||||
{
|
{
|
||||||
if (file.NameLower.Contains(find))
|
if (file.Name.Contains(find, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
AddFileNode(file, null);
|
AddFileNode(file, null);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
foreach (RpfEntry entry in file.AllEntries)
|
foreach (RpfEntry entry in file.AllEntries)
|
||||||
{
|
{
|
||||||
if (entry.NameLower.Contains(find))
|
if (entry.Name.Contains(find, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (entry is RpfDirectoryEntry direntry)
|
if (entry is RpfDirectoryEntry direntry)
|
||||||
{
|
{
|
||||||
@ -819,7 +819,8 @@ namespace CodeWalker.Tools
|
|||||||
}
|
}
|
||||||
else if (entry is RpfBinaryFileEntry)
|
else if (entry is RpfBinaryFileEntry)
|
||||||
{
|
{
|
||||||
if (entry.Name.EndsWith(".rpf", StringComparison.OrdinalIgnoreCase)) continue;
|
if (entry.IsExtension(".rpf"))
|
||||||
|
continue;
|
||||||
AddEntryNode(entry, null);
|
AddEntryNode(entry, null);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@ -1079,7 +1080,7 @@ namespace CodeWalker.Tools
|
|||||||
|
|
||||||
curfile++;
|
curfile++;
|
||||||
|
|
||||||
if (fentry.NameLower.EndsWith(".rpf"))
|
if (fentry.IsExtension(".rpf"))
|
||||||
{ continue; }
|
{ continue; }
|
||||||
|
|
||||||
if (ignoreexts != null)
|
if (ignoreexts != null)
|
||||||
@ -1087,7 +1088,7 @@ namespace CodeWalker.Tools
|
|||||||
bool ignore = false;
|
bool ignore = false;
|
||||||
for (int i = 0; i < ignoreexts.Length; i++)
|
for (int i = 0; i < ignoreexts.Length; i++)
|
||||||
{
|
{
|
||||||
if (fentry.NameLower.EndsWith(ignoreexts[i]))
|
if (fentry.Name.EndsWith(ignoreexts[i], StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
ignore = true;
|
ignore = true;
|
||||||
break;
|
break;
|
||||||
|
@ -142,11 +142,11 @@ namespace CodeWalker.Tools
|
|||||||
bool extract = false;
|
bool extract = false;
|
||||||
if (endswith)
|
if (endswith)
|
||||||
{
|
{
|
||||||
extract = entry.NameLower.EndsWith(matchstr);
|
extract = entry.Name.EndsWith(matchstr, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
extract = entry.NameLower.Contains(matchstr);
|
extract = entry.Name.Contains(matchstr, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
var fentry = entry as RpfFileEntry;
|
var fentry = entry as RpfFileEntry;
|
||||||
if (fentry == null)
|
if (fentry == null)
|
||||||
|
@ -130,7 +130,7 @@ namespace CodeWalker.Tools
|
|||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (entry.NameLower.EndsWith(".fxc"))
|
if (entry.IsExtension(".fxc"))
|
||||||
{
|
{
|
||||||
UpdateExtractStatus(entry.Path);
|
UpdateExtractStatus(entry.Path);
|
||||||
FxcFile fxc = rpfman.GetFile<FxcFile>(entry);
|
FxcFile fxc = rpfman.GetFile<FxcFile>(entry);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user