theme commit

This commit is contained in:
skylumz 2018-03-13 22:28:58 -04:00
parent 79a9cf1eb6
commit bc3c6c02b0
470 changed files with 200426 additions and 0 deletions

96
AboutForm.Designer.cs generated Normal file
View File

@ -0,0 +1,96 @@
namespace CodeWalker
{
partial class AboutForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutForm));
this.OkButton = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// OkButton
//
this.OkButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.OkButton.Location = new System.Drawing.Point(317, 173);
this.OkButton.Name = "OkButton";
this.OkButton.Size = new System.Drawing.Size(75, 23);
this.OkButton.TabIndex = 0;
this.OkButton.Text = "Ok";
this.OkButton.UseVisualStyleBackColor = true;
this.OkButton.Click += new System.EventHandler(this.OkButton_Click);
//
// label1
//
this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label1.Location = new System.Drawing.Point(12, 35);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(380, 164);
this.label1.TabIndex = 1;
this.label1.Text = resources.GetString("label1.Text");
this.label1.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// label2
//
this.label2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.label2.Location = new System.Drawing.Point(12, 9);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(380, 26);
this.label2.TabIndex = 2;
this.label2.Text = "CodeWalker by dexyfex";
this.label2.TextAlign = System.Drawing.ContentAlignment.TopCenter;
//
// AboutForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(404, 208);
this.Controls.Add(this.label2);
this.Controls.Add(this.OkButton);
this.Controls.Add(this.label1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "AboutForm";
this.Text = "About CodeWalker by dexyfex";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button OkButton;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Label label2;
}
}

25
AboutForm.cs Normal file
View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CodeWalker
{
public partial class AboutForm : Form
{
public AboutForm()
{
InitializeComponent();
}
private void OkButton_Click(object sender, EventArgs e)
{
Close();
}
}
}

419
AboutForm.resx Normal file
View File

@ -0,0 +1,419 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="label1.Text" xml:space="preserve">
<value>A tool for visualising data pertaining to the search for the next paradigm.
Special thanks to:
-- Neodymium -- tgascoigne -- CamxxCore --
-- Tadden -- Gramz -- Kai -- Vertigo -- HL -- Pouaichh --
-- Dilapidated -- dav90 -- Neos7 -- Jevi -- sollaholla --
-- The .White team -- CP -- Kilian -- PNWParksFan --</value>
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
6P///ysvjWVqtP///////wAAAAAAAAAAAP////D0/0hPpsDG6////////6y02d7k8////3qAx+/z/f//
/wAAAAAAAAAAAAAAAAAAAP///////////////8zT8V5ns1Rcrdzh9f///////////wAAAAAAAAAAAAAA
AAAAAP////////7+/6ix3nmBxFthtmdwu09WqbC54/v9//r8//j6//39/wAAAAAAAAAAAOjt/H6I0FJc
skpSqHF+wRMahFZhs4iT1AsNc1pgrm52v2RsuO/z/gAAAP////////L2/cLJ7rrD64+V4DY+ozU+mYmU
0X2Hy1hfss7V8urv/PP2/v///wAAAP///+Pp+d/k9////////+Pp/4uR3ysymW14xYOM0fD0/P///+Xq
+ri/6Pj6/wAAAOrv/j5DnbS75P////////////X4/+/0/ubr+/r7/////////9rh+hgZhKGo2QAAAPDz
/eLn+f////j6/2Nqttrg9////+Hn+P3+//3+/1hescLJ6/////L2/eru/AAAAAAAAAAAAP///8rR70tR
p/3+//v8/zY6jNPY7////09WqWpwu////wAAAAAAAAAAAAAAAAAAAAAAAPb4/vr7//////v8/5Wd1eHm
+P////v8//T3/wAAAAAAAAAAAAAAAP//AAD8PwAA/D8AAPwDAACAAwAAgAMAAIAHAADABwAAwAEAAMAB
AAAAAQAAAAEAAAABAAAAAQAAwAcAAOAPAAAoAAAAQAAAAIAAAAABABgAAAAAAAAwAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7//P3//P3//P3/
/f7//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/
+fv/+fv/+Pr/+fv/+vv//P3//v//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA/f7/+fr/8/b/7PL/5+3/6e/+9Pf/+vv//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA/P3/9/r/6O7/cXe1UVaet7z17fL/+Pr//f3/AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+/z/9Pj/4Oj/NzyCUlOd2dz/6O//9Pf//P3/AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8vb/2+P9X2OmREGLnqPd
4+v/8vb/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8fb/
1N35bXK1JSRtbHGz5O7/8fX/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA+vv/8PX/3Ob/U1eaDwtXjZLT4+z/8fX/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA+vv/8fb/2eP+MjR6AAA+c3i34Or/8fX/+/z/AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8vb/1d/7MS91AAA1UFSS4On/8vb/+/z/AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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
/v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/+vz/+fv/+Pr/+Pr/+vv//f3//v//AAAAAAAAAAAAAAAA
/v//+fv/9Pf/2+L/SVGtAABsLTaZytL58fX/9/n//f7/AAAAAAAAAAAAAAAA/v7/+/z/9/n/9fj/9vn/
9fj/9vj/+vz//f7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7//f3//f3//f3//v7//v//AAAA
AAAAAAAAAAAAAAAAAAAA+/z/9vn/6e//mZ7gTVarr7bp6/H/9fj/+vv//v7/AAAAAAAAAAAAAAAAAAAA
/v7//f7/+/z/+/z/+/z//P3//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/f3/+Pr/9fj/6e7/4+n/8fb/9Pf/+Pr//f3/AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/+fv/+fv/+vv/+Pr/+vv/
/P3//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7/
/f3//P3//f7//v7//v//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////
///////4D/////////AH////////8Af////////wB/////////AH////////8Af////////wB///////
//AH////////8Af////////wB/////////AH////////8AfwP//////wB8Af//+Af/AHgB///wA/8AcA
H///AB/wBgAf//8AD/AGAB///wAH8AYAH///AAPwBAAf//8AA/AEAD///wAD8AQAP///AAPwBAB///+A
A/AEAP///8AD4AAA////4AcAAAH////wDgAAAf/////8AAAH//////gAAAf/////4AAAAf/////gAAAA
/f//+AAAAAAAD//AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+A
AAAAAAAP/4AAAAAAAB//wAAAAABAf/4HwAAAAYAf8APAAAADgA/gA+AAAAMAA8AD8AAABwADgAP8AAAf
AAOAA/4AAB8AA4ADAAAAAQADgAIAcA4AgAOABgBwDgBAA4AMAGAMADADwDwAYAwAOAfg+ABgBAAeH//4
AEAEAB////gAwAYAH///+ADABgAf///4AcAGAB////gBwAcAH///+APAB4A////8B+AHwH//////4A//
///////gD/////////Af//////////////8=
</value>
</data>
</root>

207
App.config Normal file
View File

@ -0,0 +1,207 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="CodeWalker.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<userSettings>
<CodeWalker.Properties.Settings>
<setting name="Key" serializeAs="String">
<value />
</setting>
<setting name="GTAFolder" serializeAs="String">
<value>C:\Program Files (x86)\Steam\SteamApps\common\Grand Theft Auto V</value>
</setting>
<setting name="CompiledScriptFolder" serializeAs="String">
<value />
</setting>
<setting name="DecompiledScriptFolder" serializeAs="String">
<value />
</setting>
<setting name="GTAExeDumpFile" serializeAs="String">
<value />
</setting>
<setting name="ExtractedTexturesFolder" serializeAs="String">
<value />
</setting>
<setting name="ExtractedRawFilesFolder" serializeAs="String">
<value />
</setting>
<setting name="ExtractedShadersFolder" serializeAs="String">
<value />
</setting>
<setting name="FullScreen" serializeAs="String">
<value>False</value>
</setting>
<setting name="Wireframe" serializeAs="String">
<value>False</value>
</setting>
<setting name="Skydome" serializeAs="String">
<value>True</value>
</setting>
<setting name="ShowTimedEntities" serializeAs="String">
<value>True</value>
</setting>
<setting name="ShowCollisionMeshes" serializeAs="String">
<value>False</value>
</setting>
<setting name="CollisionMeshRange" serializeAs="String">
<value>4</value>
</setting>
<setting name="DynamicLOD" serializeAs="String">
<value>True</value>
</setting>
<setting name="DetailDist" serializeAs="String">
<value>5</value>
</setting>
<setting name="MarkerStyle" serializeAs="String">
<value>Glokon Marker</value>
</setting>
<setting name="LocatorStyle" serializeAs="String">
<value>Glokon Debug</value>
</setting>
<setting name="MarkerDepthClip" serializeAs="String">
<value>False</value>
</setting>
<setting name="BoundsStyle" serializeAs="String">
<value>None</value>
</setting>
<setting name="BoundsDepthClip" serializeAs="String">
<value>True</value>
</setting>
<setting name="BoundsRange" serializeAs="String">
<value>100</value>
</setting>
<setting name="ShowErrorConsole" serializeAs="String">
<value>False</value>
</setting>
<setting name="Shadows" serializeAs="String">
<value>True</value>
</setting>
<setting name="ShadowCascades" serializeAs="String">
<value>6</value>
</setting>
<setting name="Grass" serializeAs="String">
<value>True</value>
</setting>
<setting name="ShowStatusBar" serializeAs="String">
<value>True</value>
</setting>
<setting name="WaitForChildren" serializeAs="String">
<value>False</value>
</setting>
<setting name="CacheSize" serializeAs="String">
<value>2147483648</value>
</setting>
<setting name="CacheTime" serializeAs="String">
<value>10</value>
</setting>
<setting name="GPUGeometryCacheSize" serializeAs="String">
<value>536870912</value>
</setting>
<setting name="GPUTextureCacheSize" serializeAs="String">
<value>1073741824</value>
</setting>
<setting name="GPUBoundCompCacheSize" serializeAs="String">
<value>134217728</value>
</setting>
<setting name="GPUCacheTime" serializeAs="String">
<value>1</value>
</setting>
<setting name="GPUCacheFlushTime" serializeAs="String">
<value>0.1</value>
</setting>
<setting name="CameraSmoothing" serializeAs="String">
<value>10</value>
</setting>
<setting name="CameraSensitivity" serializeAs="String">
<value>0.005</value>
</setting>
<setting name="CameraFieldOfView" serializeAs="String">
<value>1</value>
</setting>
<setting name="RenderMode" serializeAs="String">
<value>Default</value>
</setting>
<setting name="RenderTextureSampler" serializeAs="String">
<value>DiffuseSampler</value>
</setting>
<setting name="RenderTextureSamplerCoord" serializeAs="String">
<value>Texture coord 1</value>
</setting>
<setting name="ExcludeFolders" serializeAs="String">
<value>Installers;_CommonRedist</value>
</setting>
<setting name="AnisotropicFiltering" serializeAs="String">
<value>True</value>
</setting>
<setting name="HDR" serializeAs="String">
<value>True</value>
</setting>
<setting name="WindowMaximized" serializeAs="String">
<value>False</value>
</setting>
<setting name="EnableMods" serializeAs="String">
<value>False</value>
</setting>
<setting name="DLC" serializeAs="String">
<value />
</setting>
<setting name="KeyBindings" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>Move Forwards: W</string>
<string>Move Backwards: S</string>
<string>Move Left: A</string>
<string>Move Right: D</string>
<string>Move Up: R</string>
<string>Move Down: F</string>
<string>Move Slower / Zoom In: Z</string>
<string>Move Faster / Zoom Out: X</string>
<string>Toggle Mouse Select: C</string>
<string>Toggle Toolbar: T</string>
<string>Exit Edit Mode: Q</string>
<string>Edit Position: W</string>
<string>Edit Rotation: E</string>
<string>Edit Scale: R</string>
</ArrayOfString>
</value>
</setting>
<setting name="XInputLThumbInvert" serializeAs="String">
<value>True</value>
</setting>
<setting name="XInputRThumbInvert" serializeAs="String">
<value>False</value>
</setting>
<setting name="XInputLThumbSensitivity" serializeAs="String">
<value>2</value>
</setting>
<setting name="XInputRThumbSensitivity" serializeAs="String">
<value>2</value>
</setting>
<setting name="XInputZoomSpeed" serializeAs="String">
<value>2</value>
</setting>
<setting name="XInputMoveSpeed" serializeAs="String">
<value>15</value>
</setting>
<setting name="MouseInvert" serializeAs="String">
<value>False</value>
</setting>
<setting name="RememberGTAFolder" serializeAs="String">
<value>True</value>
</setting>
<setting name="ProjectWindowTheme" serializeAs="String">
<value>Blue</value>
</setting>
<setting name="ExplorerWindowTheme" serializeAs="String">
<value>Windows</value>
</setting>
</CodeWalker.Properties.Settings>
</userSettings>
</configuration>

625
BinarySearchForm.Designer.cs generated Normal file
View File

@ -0,0 +1,625 @@
namespace CodeWalker
{
partial class BinarySearchForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BinarySearchForm));
this.FileSearchTextRadio = new System.Windows.Forms.RadioButton();
this.FileSearchHexRadio = new System.Windows.Forms.RadioButton();
this.FileSearchAbortButton = new System.Windows.Forms.Button();
this.FileSearchResultsTextBox = new System.Windows.Forms.TextBox();
this.FileSearchTextBox = new System.Windows.Forms.TextBox();
this.FileSearchFolderBrowseButton = new System.Windows.Forms.Button();
this.FileSearchButton = new System.Windows.Forms.Button();
this.label2 = new System.Windows.Forms.Label();
this.FileSearchFolderTextBox = new System.Windows.Forms.TextBox();
this.FolderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
this.MainTabControl = new System.Windows.Forms.TabControl();
this.SearchRPFTabPage = new System.Windows.Forms.TabPage();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.RpfSearchOnlyTextBox = new System.Windows.Forms.TextBox();
this.RpfSearchOnlyCheckBox = new System.Windows.Forms.CheckBox();
this.RpfSearchSaveResultsButton = new System.Windows.Forms.Button();
this.RpfSearchIgnoreTextBox = new System.Windows.Forms.TextBox();
this.RpfSearchIgnoreCheckBox = new System.Windows.Forms.CheckBox();
this.RpfSearchBothDirectionsCheckBox = new System.Windows.Forms.CheckBox();
this.RpfSearchCaseSensitiveCheckBox = new System.Windows.Forms.CheckBox();
this.RpfSearchHexRadioButton = new System.Windows.Forms.RadioButton();
this.RpfSearchTextRadioButton = new System.Windows.Forms.RadioButton();
this.RpfSearchResultsListView = new System.Windows.Forms.ListView();
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.RpfSearchAbortButton = new System.Windows.Forms.Button();
this.RpfSearchButton = new System.Windows.Forms.Button();
this.label3 = new System.Windows.Forms.Label();
this.RpfSearchTextBox = new System.Windows.Forms.TextBox();
this.ExportCompressCheckBox = new System.Windows.Forms.CheckBox();
this.ExportButton = new System.Windows.Forms.Button();
this.FileInfoLabel = new System.Windows.Forms.Label();
this.ShowLargeFileContentsCheckBox = new System.Windows.Forms.CheckBox();
this.DataHexLineCombo = new System.Windows.Forms.ComboBox();
this.DataTextRadio = new System.Windows.Forms.RadioButton();
this.DataHexRadio = new System.Windows.Forms.RadioButton();
this.DataTextBox = new System.Windows.Forms.TextBox();
this.SearchFileSystemTab = new System.Windows.Forms.TabPage();
this.FileSearchPanel = new System.Windows.Forms.Panel();
this.MainStatusStrip = new System.Windows.Forms.StatusStrip();
this.StatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.SaveFileDialog = new System.Windows.Forms.SaveFileDialog();
this.MainTabControl.SuspendLayout();
this.SearchRPFTabPage.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.SearchFileSystemTab.SuspendLayout();
this.FileSearchPanel.SuspendLayout();
this.MainStatusStrip.SuspendLayout();
this.SuspendLayout();
//
// FileSearchTextRadio
//
this.FileSearchTextRadio.AutoSize = true;
this.FileSearchTextRadio.Location = new System.Drawing.Point(162, 30);
this.FileSearchTextRadio.Name = "FileSearchTextRadio";
this.FileSearchTextRadio.Size = new System.Drawing.Size(48, 19);
this.FileSearchTextRadio.TabIndex = 45;
this.FileSearchTextRadio.Text = "Text";
this.FileSearchTextRadio.UseVisualStyleBackColor = true;
//
// FileSearchHexRadio
//
this.FileSearchHexRadio.AutoSize = true;
this.FileSearchHexRadio.Checked = true;
this.FileSearchHexRadio.Location = new System.Drawing.Point(112, 30);
this.FileSearchHexRadio.Name = "FileSearchHexRadio";
this.FileSearchHexRadio.Size = new System.Drawing.Size(47, 19);
this.FileSearchHexRadio.TabIndex = 44;
this.FileSearchHexRadio.TabStop = true;
this.FileSearchHexRadio.Text = "Hex";
this.FileSearchHexRadio.UseVisualStyleBackColor = true;
//
// FileSearchAbortButton
//
this.FileSearchAbortButton.Location = new System.Drawing.Point(420, 27);
this.FileSearchAbortButton.Name = "FileSearchAbortButton";
this.FileSearchAbortButton.Size = new System.Drawing.Size(75, 23);
this.FileSearchAbortButton.TabIndex = 43;
this.FileSearchAbortButton.Text = "Abort";
this.FileSearchAbortButton.UseVisualStyleBackColor = true;
this.FileSearchAbortButton.Click += new System.EventHandler(this.FileSearchAbortButton_Click);
//
// FileSearchResultsTextBox
//
this.FileSearchResultsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.FileSearchResultsTextBox.Location = new System.Drawing.Point(85, 78);
this.FileSearchResultsTextBox.Multiline = true;
this.FileSearchResultsTextBox.Name = "FileSearchResultsTextBox";
this.FileSearchResultsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.FileSearchResultsTextBox.Size = new System.Drawing.Size(685, 403);
this.FileSearchResultsTextBox.TabIndex = 42;
this.FileSearchResultsTextBox.WordWrap = false;
//
// FileSearchTextBox
//
this.FileSearchTextBox.Location = new System.Drawing.Point(214, 29);
this.FileSearchTextBox.Name = "FileSearchTextBox";
this.FileSearchTextBox.Size = new System.Drawing.Size(119, 20);
this.FileSearchTextBox.TabIndex = 41;
this.FileSearchTextBox.Text = "4a03746e";
//
// FileSearchFolderBrowseButton
//
this.FileSearchFolderBrowseButton.Location = new System.Drawing.Point(339, 1);
this.FileSearchFolderBrowseButton.Name = "FileSearchFolderBrowseButton";
this.FileSearchFolderBrowseButton.Size = new System.Drawing.Size(27, 23);
this.FileSearchFolderBrowseButton.TabIndex = 40;
this.FileSearchFolderBrowseButton.Text = "...";
this.FileSearchFolderBrowseButton.UseVisualStyleBackColor = true;
this.FileSearchFolderBrowseButton.Click += new System.EventHandler(this.FileSearchFolderBrowseButton_Click);
//
// FileSearchButton
//
this.FileSearchButton.Location = new System.Drawing.Point(339, 27);
this.FileSearchButton.Name = "FileSearchButton";
this.FileSearchButton.Size = new System.Drawing.Size(75, 23);
this.FileSearchButton.TabIndex = 39;
this.FileSearchButton.Text = "Search";
this.FileSearchButton.UseVisualStyleBackColor = true;
this.FileSearchButton.Click += new System.EventHandler(this.FileSearchButton_Click);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(3, 6);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(83, 15);
this.label2.TabIndex = 38;
this.label2.Text = "Search folder:";
//
// FileSearchFolderTextBox
//
this.FileSearchFolderTextBox.Location = new System.Drawing.Point(82, 3);
this.FileSearchFolderTextBox.Name = "FileSearchFolderTextBox";
this.FileSearchFolderTextBox.Size = new System.Drawing.Size(251, 20);
this.FileSearchFolderTextBox.TabIndex = 37;
this.FileSearchFolderTextBox.Text = "Compiled944";
//
// MainTabControl
//
this.MainTabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.MainTabControl.Controls.Add(this.SearchRPFTabPage);
this.MainTabControl.Controls.Add(this.SearchFileSystemTab);
this.MainTabControl.Location = new System.Drawing.Point(3, 5);
this.MainTabControl.Name = "MainTabControl";
this.MainTabControl.SelectedIndex = 0;
this.MainTabControl.Size = new System.Drawing.Size(846, 525);
this.MainTabControl.TabIndex = 46;
//
// SearchRPFTabPage
//
this.SearchRPFTabPage.Controls.Add(this.splitContainer1);
this.SearchRPFTabPage.Location = new System.Drawing.Point(4, 22);
this.SearchRPFTabPage.Name = "SearchRPFTabPage";
this.SearchRPFTabPage.Padding = new System.Windows.Forms.Padding(3);
this.SearchRPFTabPage.Size = new System.Drawing.Size(838, 499);
this.SearchRPFTabPage.TabIndex = 0;
this.SearchRPFTabPage.Text = "Search RPF contents";
this.SearchRPFTabPage.UseVisualStyleBackColor = true;
//
// splitContainer1
//
this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel1;
this.splitContainer1.Location = new System.Drawing.Point(3, 3);
this.splitContainer1.Name = "splitContainer1";
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchOnlyTextBox);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchOnlyCheckBox);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchSaveResultsButton);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchIgnoreTextBox);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchIgnoreCheckBox);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchBothDirectionsCheckBox);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchCaseSensitiveCheckBox);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchHexRadioButton);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchTextRadioButton);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchResultsListView);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchAbortButton);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchButton);
this.splitContainer1.Panel1.Controls.Add(this.label3);
this.splitContainer1.Panel1.Controls.Add(this.RpfSearchTextBox);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.ExportCompressCheckBox);
this.splitContainer1.Panel2.Controls.Add(this.ExportButton);
this.splitContainer1.Panel2.Controls.Add(this.FileInfoLabel);
this.splitContainer1.Panel2.Controls.Add(this.ShowLargeFileContentsCheckBox);
this.splitContainer1.Panel2.Controls.Add(this.DataHexLineCombo);
this.splitContainer1.Panel2.Controls.Add(this.DataTextRadio);
this.splitContainer1.Panel2.Controls.Add(this.DataHexRadio);
this.splitContainer1.Panel2.Controls.Add(this.DataTextBox);
this.splitContainer1.Size = new System.Drawing.Size(832, 493);
this.splitContainer1.SplitterDistance = 270;
this.splitContainer1.TabIndex = 1;
//
// RpfSearchOnlyTextBox
//
this.RpfSearchOnlyTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.RpfSearchOnlyTextBox.Enabled = false;
this.RpfSearchOnlyTextBox.Location = new System.Drawing.Point(68, 92);
this.RpfSearchOnlyTextBox.Name = "RpfSearchOnlyTextBox";
this.RpfSearchOnlyTextBox.Size = new System.Drawing.Size(198, 20);
this.RpfSearchOnlyTextBox.TabIndex = 66;
this.RpfSearchOnlyTextBox.Text = ".ysc, .rel";
//
// RpfSearchOnlyCheckBox
//
this.RpfSearchOnlyCheckBox.AutoSize = true;
this.RpfSearchOnlyCheckBox.Location = new System.Drawing.Point(9, 94);
this.RpfSearchOnlyCheckBox.Name = "RpfSearchOnlyCheckBox";
this.RpfSearchOnlyCheckBox.Size = new System.Drawing.Size(53, 19);
this.RpfSearchOnlyCheckBox.TabIndex = 65;
this.RpfSearchOnlyCheckBox.Text = "Only:";
this.RpfSearchOnlyCheckBox.UseVisualStyleBackColor = true;
this.RpfSearchOnlyCheckBox.CheckedChanged += new System.EventHandler(this.RpfSearchOnlyCheckBox_CheckedChanged);
//
// RpfSearchSaveResultsButton
//
this.RpfSearchSaveResultsButton.Enabled = false;
this.RpfSearchSaveResultsButton.Location = new System.Drawing.Point(181, 118);
this.RpfSearchSaveResultsButton.Name = "RpfSearchSaveResultsButton";
this.RpfSearchSaveResultsButton.Size = new System.Drawing.Size(86, 22);
this.RpfSearchSaveResultsButton.TabIndex = 62;
this.RpfSearchSaveResultsButton.Text = "Save results...";
this.RpfSearchSaveResultsButton.UseVisualStyleBackColor = true;
this.RpfSearchSaveResultsButton.Click += new System.EventHandler(this.RpfSearchSaveResultsButton_Click);
//
// RpfSearchIgnoreTextBox
//
this.RpfSearchIgnoreTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.RpfSearchIgnoreTextBox.Location = new System.Drawing.Point(68, 68);
this.RpfSearchIgnoreTextBox.Name = "RpfSearchIgnoreTextBox";
this.RpfSearchIgnoreTextBox.Size = new System.Drawing.Size(198, 20);
this.RpfSearchIgnoreTextBox.TabIndex = 59;
this.RpfSearchIgnoreTextBox.Text = ".ydr, .ydd, .ytd, .yft, .ybn, .ycd, .awc, .bik";
//
// RpfSearchIgnoreCheckBox
//
this.RpfSearchIgnoreCheckBox.AutoSize = true;
this.RpfSearchIgnoreCheckBox.Checked = true;
this.RpfSearchIgnoreCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
this.RpfSearchIgnoreCheckBox.Location = new System.Drawing.Point(9, 70);
this.RpfSearchIgnoreCheckBox.Name = "RpfSearchIgnoreCheckBox";
this.RpfSearchIgnoreCheckBox.Size = new System.Drawing.Size(64, 19);
this.RpfSearchIgnoreCheckBox.TabIndex = 58;
this.RpfSearchIgnoreCheckBox.Text = "Ignore:";
this.RpfSearchIgnoreCheckBox.UseVisualStyleBackColor = true;
this.RpfSearchIgnoreCheckBox.CheckedChanged += new System.EventHandler(this.RpfSearchIgnoreCheckBox_CheckedChanged);
//
// RpfSearchBothDirectionsCheckBox
//
this.RpfSearchBothDirectionsCheckBox.AutoSize = true;
this.RpfSearchBothDirectionsCheckBox.Checked = true;
this.RpfSearchBothDirectionsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
this.RpfSearchBothDirectionsCheckBox.Location = new System.Drawing.Point(109, 48);
this.RpfSearchBothDirectionsCheckBox.Name = "RpfSearchBothDirectionsCheckBox";
this.RpfSearchBothDirectionsCheckBox.Size = new System.Drawing.Size(107, 19);
this.RpfSearchBothDirectionsCheckBox.TabIndex = 57;
this.RpfSearchBothDirectionsCheckBox.Text = "Both directions";
this.RpfSearchBothDirectionsCheckBox.UseVisualStyleBackColor = true;
//
// RpfSearchCaseSensitiveCheckBox
//
this.RpfSearchCaseSensitiveCheckBox.AutoSize = true;
this.RpfSearchCaseSensitiveCheckBox.Location = new System.Drawing.Point(9, 48);
this.RpfSearchCaseSensitiveCheckBox.Name = "RpfSearchCaseSensitiveCheckBox";
this.RpfSearchCaseSensitiveCheckBox.Size = new System.Drawing.Size(105, 19);
this.RpfSearchCaseSensitiveCheckBox.TabIndex = 56;
this.RpfSearchCaseSensitiveCheckBox.Text = "Case-sensitive";
this.RpfSearchCaseSensitiveCheckBox.UseVisualStyleBackColor = true;
//
// RpfSearchHexRadioButton
//
this.RpfSearchHexRadioButton.AutoSize = true;
this.RpfSearchHexRadioButton.Location = new System.Drawing.Point(158, 5);
this.RpfSearchHexRadioButton.Name = "RpfSearchHexRadioButton";
this.RpfSearchHexRadioButton.Size = new System.Drawing.Size(47, 19);
this.RpfSearchHexRadioButton.TabIndex = 55;
this.RpfSearchHexRadioButton.Text = "Hex";
this.RpfSearchHexRadioButton.UseVisualStyleBackColor = true;
//
// RpfSearchTextRadioButton
//
this.RpfSearchTextRadioButton.AutoSize = true;
this.RpfSearchTextRadioButton.Checked = true;
this.RpfSearchTextRadioButton.Location = new System.Drawing.Point(106, 5);
this.RpfSearchTextRadioButton.Name = "RpfSearchTextRadioButton";
this.RpfSearchTextRadioButton.Size = new System.Drawing.Size(48, 19);
this.RpfSearchTextRadioButton.TabIndex = 54;
this.RpfSearchTextRadioButton.TabStop = true;
this.RpfSearchTextRadioButton.Text = "Text";
this.RpfSearchTextRadioButton.UseVisualStyleBackColor = true;
this.RpfSearchTextRadioButton.CheckedChanged += new System.EventHandler(this.RpfSearchTextRadioButton_CheckedChanged);
//
// RpfSearchResultsListView
//
this.RpfSearchResultsListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.RpfSearchResultsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2});
this.RpfSearchResultsListView.FullRowSelect = true;
this.RpfSearchResultsListView.HideSelection = false;
this.RpfSearchResultsListView.Location = new System.Drawing.Point(3, 146);
this.RpfSearchResultsListView.MultiSelect = false;
this.RpfSearchResultsListView.Name = "RpfSearchResultsListView";
this.RpfSearchResultsListView.Size = new System.Drawing.Size(263, 347);
this.RpfSearchResultsListView.TabIndex = 63;
this.RpfSearchResultsListView.UseCompatibleStateImageBehavior = false;
this.RpfSearchResultsListView.View = System.Windows.Forms.View.Details;
this.RpfSearchResultsListView.VirtualMode = true;
this.RpfSearchResultsListView.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.RpfSearchResultsListView_RetrieveVirtualItem);
this.RpfSearchResultsListView.SelectedIndexChanged += new System.EventHandler(this.RpfSearchResultsListView_SelectedIndexChanged);
//
// columnHeader1
//
this.columnHeader1.Text = "File";
this.columnHeader1.Width = 176;
//
// columnHeader2
//
this.columnHeader2.Text = "Offset";
//
// RpfSearchAbortButton
//
this.RpfSearchAbortButton.Location = new System.Drawing.Point(90, 118);
this.RpfSearchAbortButton.Name = "RpfSearchAbortButton";
this.RpfSearchAbortButton.Size = new System.Drawing.Size(75, 22);
this.RpfSearchAbortButton.TabIndex = 61;
this.RpfSearchAbortButton.Text = "Abort";
this.RpfSearchAbortButton.UseVisualStyleBackColor = true;
this.RpfSearchAbortButton.Click += new System.EventHandler(this.RpfSearchAbortButton_Click);
//
// RpfSearchButton
//
this.RpfSearchButton.Location = new System.Drawing.Point(9, 119);
this.RpfSearchButton.Name = "RpfSearchButton";
this.RpfSearchButton.Size = new System.Drawing.Size(75, 22);
this.RpfSearchButton.TabIndex = 60;
this.RpfSearchButton.Text = "Search";
this.RpfSearchButton.UseVisualStyleBackColor = true;
this.RpfSearchButton.Click += new System.EventHandler(this.RpfSearchButton_Click);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(7, 7);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(104, 15);
this.label3.TabIndex = 64;
this.label3.Text = "Search in files for:";
//
// RpfSearchTextBox
//
this.RpfSearchTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.RpfSearchTextBox.Location = new System.Drawing.Point(3, 23);
this.RpfSearchTextBox.Name = "RpfSearchTextBox";
this.RpfSearchTextBox.Size = new System.Drawing.Size(263, 20);
this.RpfSearchTextBox.TabIndex = 53;
//
// ExportCompressCheckBox
//
this.ExportCompressCheckBox.AutoSize = true;
this.ExportCompressCheckBox.Location = new System.Drawing.Point(87, 35);
this.ExportCompressCheckBox.Name = "ExportCompressCheckBox";
this.ExportCompressCheckBox.Size = new System.Drawing.Size(119, 19);
this.ExportCompressCheckBox.TabIndex = 112;
this.ExportCompressCheckBox.Text = "Compress export";
this.ExportCompressCheckBox.UseVisualStyleBackColor = true;
//
// ExportButton
//
this.ExportButton.Location = new System.Drawing.Point(6, 31);
this.ExportButton.Name = "ExportButton";
this.ExportButton.Size = new System.Drawing.Size(75, 23);
this.ExportButton.TabIndex = 111;
this.ExportButton.Text = "Export...";
this.ExportButton.UseVisualStyleBackColor = true;
this.ExportButton.Click += new System.EventHandler(this.ExportButton_Click);
//
// FileInfoLabel
//
this.FileInfoLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.FileInfoLabel.AutoEllipsis = true;
this.FileInfoLabel.Location = new System.Drawing.Point(3, 7);
this.FileInfoLabel.Name = "FileInfoLabel";
this.FileInfoLabel.Size = new System.Drawing.Size(549, 16);
this.FileInfoLabel.TabIndex = 110;
this.FileInfoLabel.Text = "[Nothing selected]";
//
// ShowLargeFileContentsCheckBox
//
this.ShowLargeFileContentsCheckBox.AutoSize = true;
this.ShowLargeFileContentsCheckBox.Location = new System.Drawing.Point(392, 62);
this.ShowLargeFileContentsCheckBox.Name = "ShowLargeFileContentsCheckBox";
this.ShowLargeFileContentsCheckBox.Size = new System.Drawing.Size(156, 19);
this.ShowLargeFileContentsCheckBox.TabIndex = 109;
this.ShowLargeFileContentsCheckBox.Text = "Show large file contents";
this.ShowLargeFileContentsCheckBox.UseVisualStyleBackColor = true;
this.ShowLargeFileContentsCheckBox.CheckedChanged += new System.EventHandler(this.ShowLargeFileContentsCheckBox_CheckedChanged);
//
// DataHexLineCombo
//
this.DataHexLineCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.DataHexLineCombo.FormattingEnabled = true;
this.DataHexLineCombo.Items.AddRange(new object[] {
"8",
"16",
"32"});
this.DataHexLineCombo.Location = new System.Drawing.Point(56, 60);
this.DataHexLineCombo.Name = "DataHexLineCombo";
this.DataHexLineCombo.Size = new System.Drawing.Size(49, 21);
this.DataHexLineCombo.TabIndex = 106;
this.DataHexLineCombo.SelectedIndexChanged += new System.EventHandler(this.DataHexLineCombo_SelectedIndexChanged);
//
// DataTextRadio
//
this.DataTextRadio.AutoSize = true;
this.DataTextRadio.Location = new System.Drawing.Point(135, 61);
this.DataTextRadio.Name = "DataTextRadio";
this.DataTextRadio.Size = new System.Drawing.Size(48, 19);
this.DataTextRadio.TabIndex = 107;
this.DataTextRadio.Text = "Text";
this.DataTextRadio.UseVisualStyleBackColor = true;
//
// DataHexRadio
//
this.DataHexRadio.AutoSize = true;
this.DataHexRadio.Checked = true;
this.DataHexRadio.Location = new System.Drawing.Point(6, 61);
this.DataHexRadio.Name = "DataHexRadio";
this.DataHexRadio.Size = new System.Drawing.Size(47, 19);
this.DataHexRadio.TabIndex = 105;
this.DataHexRadio.TabStop = true;
this.DataHexRadio.Text = "Hex";
this.DataHexRadio.UseVisualStyleBackColor = true;
this.DataHexRadio.CheckedChanged += new System.EventHandler(this.DataHexRadio_CheckedChanged);
//
// DataTextBox
//
this.DataTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.DataTextBox.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.DataTextBox.HideSelection = false;
this.DataTextBox.Location = new System.Drawing.Point(4, 92);
this.DataTextBox.Multiline = true;
this.DataTextBox.Name = "DataTextBox";
this.DataTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.DataTextBox.Size = new System.Drawing.Size(552, 401);
this.DataTextBox.TabIndex = 108;
this.DataTextBox.Text = "[Please select a search result]";
this.DataTextBox.WordWrap = false;
//
// SearchFileSystemTab
//
this.SearchFileSystemTab.Controls.Add(this.FileSearchPanel);
this.SearchFileSystemTab.Controls.Add(this.FileSearchResultsTextBox);
this.SearchFileSystemTab.Location = new System.Drawing.Point(4, 22);
this.SearchFileSystemTab.Name = "SearchFileSystemTab";
this.SearchFileSystemTab.Padding = new System.Windows.Forms.Padding(3);
this.SearchFileSystemTab.Size = new System.Drawing.Size(838, 499);
this.SearchFileSystemTab.TabIndex = 1;
this.SearchFileSystemTab.Text = "Search file system";
this.SearchFileSystemTab.UseVisualStyleBackColor = true;
//
// FileSearchPanel
//
this.FileSearchPanel.Controls.Add(this.FileSearchFolderTextBox);
this.FileSearchPanel.Controls.Add(this.FileSearchFolderBrowseButton);
this.FileSearchPanel.Controls.Add(this.FileSearchTextRadio);
this.FileSearchPanel.Controls.Add(this.FileSearchTextBox);
this.FileSearchPanel.Controls.Add(this.FileSearchButton);
this.FileSearchPanel.Controls.Add(this.FileSearchHexRadio);
this.FileSearchPanel.Controls.Add(this.FileSearchAbortButton);
this.FileSearchPanel.Controls.Add(this.label2);
this.FileSearchPanel.Location = new System.Drawing.Point(3, 6);
this.FileSearchPanel.Name = "FileSearchPanel";
this.FileSearchPanel.Size = new System.Drawing.Size(536, 66);
this.FileSearchPanel.TabIndex = 46;
//
// MainStatusStrip
//
this.MainStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.StatusLabel});
this.MainStatusStrip.Location = new System.Drawing.Point(0, 533);
this.MainStatusStrip.Name = "MainStatusStrip";
this.MainStatusStrip.Size = new System.Drawing.Size(852, 22);
this.MainStatusStrip.TabIndex = 47;
this.MainStatusStrip.Text = "statusStrip1";
//
// StatusLabel
//
this.StatusLabel.Name = "StatusLabel";
this.StatusLabel.Size = new System.Drawing.Size(806, 17);
this.StatusLabel.Spring = true;
this.StatusLabel.Text = "Initialising...";
this.StatusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// SaveFileDialog
//
this.SaveFileDialog.AddExtension = false;
//
// BinarySearchForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(852, 555);
this.Controls.Add(this.MainStatusStrip);
this.Controls.Add(this.MainTabControl);
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "BinarySearchForm";
this.Text = "Binary Search - CodeWalker by dexyfex";
this.Load += new System.EventHandler(this.BinarySearchForm_Load);
this.MainTabControl.ResumeLayout(false);
this.SearchRPFTabPage.ResumeLayout(false);
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel1.PerformLayout();
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.Panel2.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
this.splitContainer1.ResumeLayout(false);
this.SearchFileSystemTab.ResumeLayout(false);
this.SearchFileSystemTab.PerformLayout();
this.FileSearchPanel.ResumeLayout(false);
this.FileSearchPanel.PerformLayout();
this.MainStatusStrip.ResumeLayout(false);
this.MainStatusStrip.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.RadioButton FileSearchTextRadio;
private System.Windows.Forms.RadioButton FileSearchHexRadio;
private System.Windows.Forms.Button FileSearchAbortButton;
private System.Windows.Forms.TextBox FileSearchResultsTextBox;
private System.Windows.Forms.TextBox FileSearchTextBox;
private System.Windows.Forms.Button FileSearchFolderBrowseButton;
private System.Windows.Forms.Button FileSearchButton;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox FileSearchFolderTextBox;
private System.Windows.Forms.FolderBrowserDialog FolderBrowserDialog;
private System.Windows.Forms.TabControl MainTabControl;
private System.Windows.Forms.TabPage SearchRPFTabPage;
private System.Windows.Forms.TabPage SearchFileSystemTab;
private System.Windows.Forms.ToolStripStatusLabel StatusLabel;
private System.Windows.Forms.Panel FileSearchPanel;
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.Button RpfSearchSaveResultsButton;
private System.Windows.Forms.TextBox RpfSearchIgnoreTextBox;
private System.Windows.Forms.CheckBox RpfSearchIgnoreCheckBox;
private System.Windows.Forms.CheckBox RpfSearchBothDirectionsCheckBox;
private System.Windows.Forms.CheckBox RpfSearchCaseSensitiveCheckBox;
private System.Windows.Forms.RadioButton RpfSearchHexRadioButton;
private System.Windows.Forms.RadioButton RpfSearchTextRadioButton;
private System.Windows.Forms.ListView RpfSearchResultsListView;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.Button RpfSearchAbortButton;
private System.Windows.Forms.Button RpfSearchButton;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox RpfSearchTextBox;
private System.Windows.Forms.TextBox RpfSearchOnlyTextBox;
private System.Windows.Forms.CheckBox RpfSearchOnlyCheckBox;
private System.Windows.Forms.CheckBox ShowLargeFileContentsCheckBox;
private System.Windows.Forms.ComboBox DataHexLineCombo;
private System.Windows.Forms.RadioButton DataTextRadio;
private System.Windows.Forms.RadioButton DataHexRadio;
private System.Windows.Forms.TextBox DataTextBox;
private System.Windows.Forms.Label FileInfoLabel;
private System.Windows.Forms.SaveFileDialog SaveFileDialog;
private System.Windows.Forms.CheckBox ExportCompressCheckBox;
private System.Windows.Forms.Button ExportButton;
public System.Windows.Forms.StatusStrip MainStatusStrip;
}
}

980
BinarySearchForm.cs Normal file
View File

@ -0,0 +1,980 @@
using CodeWalker.GameFiles;
using CodeWalker.Properties;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CodeWalker
{
public partial class BinarySearchForm : Form
{
private volatile bool InProgress = false;
private volatile bool AbortOperation = false;
private GameFileCache FileCache = null;
private RpfManager RpfMan = null;
public BinarySearchForm(GameFileCache cache = null)
{
FileCache = cache;
RpfMan = cache?.RpfMan;
InitializeComponent();
}
private void BinarySearchForm_Load(object sender, EventArgs e)
{
FileSearchFolderTextBox.Text = Settings.Default.CompiledScriptFolder;
DataHexLineCombo.Text = "16";
DataTextBox.SetTabStopWidth(3);
if (RpfMan == null)
{
Task.Run(() =>
{
GTA5Keys.LoadFromPath(GTAFolder.CurrentGTAFolder, Settings.Default.Key);
RpfMan = new RpfManager();
RpfMan.Init(GTAFolder.CurrentGTAFolder, UpdateStatus, UpdateStatus, false, false);
RPFScanComplete();
});
}
else
{
RPFScanComplete();
}
}
private void UpdateStatus(string text)
{
try
{
if (InvokeRequired)
{
Invoke(new Action(() => { UpdateStatus(text); }));
}
else
{
StatusLabel.Text = text;
}
}
catch { }
}
private void RPFScanComplete()
{
try
{
if (InvokeRequired)
{
Invoke(new Action(() => { RPFScanComplete(); }));
}
else
{
StatusLabel.Text = "Ready";
//RpfSearchPanel.Enabled = true;
}
}
catch { }
}
private void FileSearchFolderBrowseButton_Click(object sender, EventArgs e)
{
FolderBrowserDialog.SelectedPath = FileSearchFolderTextBox.Text;
DialogResult res = FolderBrowserDialog.ShowDialog();
if (res == DialogResult.OK)
{
FileSearchFolderTextBox.Text = FolderBrowserDialog.SelectedPath;
}
}
private void FileSearchButton_Click(object sender, EventArgs e)
{
string searchtxt = FileSearchTextBox.Text;
string searchfolder = FileSearchFolderTextBox.Text;
AbortOperation = false;
if (InProgress) return;
if (searchfolder.Length == 0)
{
MessageBox.Show("Please select a folder...");
return;
}
if (!Directory.Exists(searchfolder))
{
MessageBox.Show("Please select a valid folder!");
return;
}
FileSearchResultsTextBox.Clear();
byte[] searchbytes1;
byte[] searchbytes2;
int bytelen;
if (FileSearchHexRadio.Checked)
{
try
{
bytelen = searchtxt.Length / 2;
searchbytes1 = new byte[bytelen];
searchbytes2 = new byte[bytelen];
for (int i = 0; i < bytelen; i++)
{
searchbytes1[i] = Convert.ToByte(searchtxt.Substring(i * 2, 2), 16);
searchbytes2[bytelen - i - 1] = searchbytes1[i];
}
}
catch
{
MessageBox.Show("Please enter a valid hex string.");
return;
}
}
else
{
bytelen = searchtxt.Length;
searchbytes1 = new byte[bytelen];
searchbytes2 = new byte[bytelen];
for (int i = 0; i < bytelen; i++)
{
searchbytes1[i] = (byte)searchtxt[i];
searchbytes2[bytelen - i - 1] = searchbytes1[i];
}
}
FileSearchPanel.Enabled = false;
InProgress = true;
Task.Run(() =>
{
FileSearchAddResult("Searching " + searchfolder + "...");
string[] filenames = Directory.GetFiles(searchfolder);
int matchcount = 0;
foreach (string filename in filenames)
{
FileInfo finf = new FileInfo(filename);
byte[] filebytes = File.ReadAllBytes(filename);
int hitlen1 = 0;
int hitlen2 = 0;
for (int i = 0; i < filebytes.Length; i++)
{
byte b = filebytes[i];
byte b1 = searchbytes1[hitlen1]; //current test byte 1
byte b2 = searchbytes2[hitlen2];
if (b == b1) hitlen1++; else hitlen1 = 0;
if (b == b2) hitlen2++; else hitlen2 = 0;
if (hitlen1 == bytelen)
{
FileSearchAddResult(finf.Name + ":" + (i - bytelen));
matchcount++;
hitlen1 = 0;
}
if (hitlen2 == bytelen)
{
FileSearchAddResult(finf.Name + ":" + (i - bytelen));
matchcount++;
hitlen2 = 0;
}
if (AbortOperation)
{
FileSearchAddResult("Search aborted.");
FileSearchComplete();
InProgress = false;
return;
}
}
}
FileSearchAddResult(string.Format("Search complete. {0} results found.", matchcount));
FileSearchComplete();
InProgress = false;
});
}
private void FileSearchAddResult(string result)
{
try
{
if (InvokeRequired)
{
Invoke(new Action(() => { FileSearchAddResult(result); }));
}
else
{
FileSearchResultsTextBox.AppendText(result + "\r\n");
}
}
catch { }
}
private void FileSearchComplete()
{
try
{
if (InvokeRequired)
{
Invoke(new Action(() => { FileSearchComplete(); }));
}
else
{
FileSearchPanel.Enabled = true;
}
}
catch { }
}
private void FileSearchAbortButton_Click(object sender, EventArgs e)
{
AbortOperation = true;
}
private List<RpfSearchResult> RpfSearchResults = new List<RpfSearchResult>();
private RpfEntry RpfSelectedEntry = null;
private int RpfSelectedOffset = -1;
private int RpfSelectedLength = 0;
private class RpfSearchResult
{
public RpfFileEntry FileEntry { get; set; }
public int Offset { get; set; }
public int Length { get; set; }
public RpfSearchResult(RpfFileEntry entry, int offset, int length)
{
FileEntry = entry;
Offset = offset;
Length = length;
}
}
private byte LowerCaseByte(byte b)
{
if ((b >= 65) && (b <= 90)) //upper case alphabet...
{
b += 32;
}
return b;
}
private void RpfSearchAddResult(RpfSearchResult result)
{
try
{
if (InvokeRequired)
{
Invoke(new Action(() => { RpfSearchAddResult(result); }));
}
else
{
RpfSearchResults.Add(result);
RpfSearchResultsListView.VirtualListSize = RpfSearchResults.Count;
}
}
catch { }
}
private void RpfSearch()
{
if (InProgress) return;
if (!(RpfMan?.IsInited ?? false))
{
MessageBox.Show("Please wait for the scan to complete.");
return;
}
if (RpfSearchTextBox.Text.Length == 0)
{
MessageBox.Show("Please enter a search term.");
return;
}
string searchtxt = RpfSearchTextBox.Text;
bool hex = RpfSearchHexRadioButton.Checked;
bool casesen = RpfSearchCaseSensitiveCheckBox.Checked || hex;
bool bothdirs = RpfSearchBothDirectionsCheckBox.Checked;
string[] ignoreexts = null;
string[] onlyexts = null;
byte[] searchbytes1;
byte[] searchbytes2;
int bytelen;
if (!casesen) searchtxt = searchtxt.ToLowerInvariant(); //case sensitive search in lower case.
if (RpfSearchIgnoreCheckBox.Checked)
{
ignoreexts = RpfSearchIgnoreTextBox.Text.Split(',');
for (int i = 0; i < ignoreexts.Length; i++)
{
ignoreexts[i] = ignoreexts[i].Trim();
}
}
if (RpfSearchOnlyCheckBox.Checked)
{
onlyexts = RpfSearchOnlyTextBox.Text.Split(',');
for (int i = 0; i < onlyexts.Length; i++)
{
onlyexts[i] = onlyexts[i].Trim();
}
}
if (hex)
{
if (searchtxt.Length < 2)
{
MessageBox.Show("Please enter at least one byte of hex (2 characters).");
return;
}
try
{
bytelen = searchtxt.Length / 2;
searchbytes1 = new byte[bytelen];
searchbytes2 = new byte[bytelen];
for (int i = 0; i < bytelen; i++)
{
searchbytes1[i] = Convert.ToByte(searchtxt.Substring(i * 2, 2), 16);
searchbytes2[bytelen - i - 1] = searchbytes1[i];
}
}
catch
{
MessageBox.Show("Please enter a valid hex string.");
return;
}
}
else
{
bytelen = searchtxt.Length;
searchbytes1 = new byte[bytelen];
searchbytes2 = new byte[bytelen]; //reversed text...
for (int i = 0; i < bytelen; i++)
{
searchbytes1[i] = (byte)searchtxt[i];
searchbytes2[bytelen - i - 1] = searchbytes1[i];
}
}
RpfSearchTextBox.Enabled = false;
RpfSearchHexRadioButton.Enabled = false;
RpfSearchTextRadioButton.Enabled = false;
RpfSearchCaseSensitiveCheckBox.Enabled = false;
RpfSearchBothDirectionsCheckBox.Enabled = false;
RpfSearchIgnoreCheckBox.Enabled = false;
RpfSearchIgnoreTextBox.Enabled = false;
RpfSearchButton.Enabled = false;
RpfSearchSaveResultsButton.Enabled = false;
InProgress = true;
AbortOperation = false;
RpfSearchResultsListView.VirtualListSize = 0;
RpfSearchResults.Clear();
uint totfiles = 0;
uint curfile = 0;
var scannedFiles = RpfMan.AllRpfs;
Task.Run(() =>
{
DateTime starttime = DateTime.Now;
int resultcount = 0;
for (int f = 0; f < scannedFiles.Count; f++)
{
var rpffile = scannedFiles[f];
totfiles += rpffile.TotalFileCount;
}
for (int f = 0; f < scannedFiles.Count; f++)
{
var rpffile = scannedFiles[f];
foreach (var entry in rpffile.AllEntries)
{
var duration = DateTime.Now - starttime;
if (AbortOperation)
{
UpdateStatus(duration.ToString(@"hh\:mm\:ss") + " - Search aborted.");
InProgress = false;
RpfSearchComplete();
return;
}
RpfFileEntry fentry = entry as RpfFileEntry;
if (fentry == null) continue;
curfile++;
if (fentry.NameLower.EndsWith(".rpf"))
{ continue; }
if (onlyexts != null)
{
bool ignore = true;
for (int i = 0; i < onlyexts.Length; i++)
{
if (fentry.NameLower.EndsWith(onlyexts[i]))
{
ignore = false;
break;
}
}
if (ignore)
{ continue; }
}
if (ignoreexts != null)
{
bool ignore = false;
for (int i = 0; i < ignoreexts.Length; i++)
{
if (fentry.NameLower.EndsWith(ignoreexts[i]))
{
ignore = true;
break;
}
}
if (ignore)
{ continue; }
}
UpdateStatus(string.Format("{0} - Searching {1}/{2} : {3}", duration.ToString(@"hh\:mm\:ss"), curfile, totfiles, fentry.Path));
byte[] filebytes = fentry.File.ExtractFile(fentry);
if (filebytes == null) continue;
int hitlen1 = 0;
int hitlen2 = 0;
for (int i = 0; i < filebytes.Length; i++)
{
byte b = casesen ? filebytes[i] : LowerCaseByte(filebytes[i]);
byte b1 = searchbytes1[hitlen1]; //current test byte 1
byte b2 = searchbytes2[hitlen2];
if (b == b1) hitlen1++; else hitlen1 = 0;
if (hitlen1 == bytelen)
{
RpfSearchAddResult(new RpfSearchResult(fentry, (i - bytelen), bytelen));
resultcount++;
hitlen1 = 0;
}
if (bothdirs)
{
if (b == b2) hitlen2++; else hitlen2 = 0;
if (hitlen2 == bytelen)
{
RpfSearchAddResult(new RpfSearchResult(fentry, (i - bytelen), bytelen));
resultcount++;
hitlen2 = 0;
}
}
}
}
}
var totdur = DateTime.Now - starttime;
UpdateStatus(totdur.ToString(@"hh\:mm\:ss") + " - Search complete. " + resultcount.ToString() + " results found.");
InProgress = false;
RpfSearchComplete();
});
}
private void RpfSearchComplete()
{
try
{
if (InvokeRequired)
{
Invoke(new Action(() => { RpfSearchComplete(); }));
}
else
{
RpfSearchTextBox.Enabled = true;
RpfSearchHexRadioButton.Enabled = true;
RpfSearchTextRadioButton.Enabled = true;
RpfSearchCaseSensitiveCheckBox.Enabled = RpfSearchTextRadioButton.Checked;
RpfSearchBothDirectionsCheckBox.Enabled = true;
RpfSearchIgnoreCheckBox.Enabled = true;
RpfSearchIgnoreTextBox.Enabled = RpfSearchIgnoreCheckBox.Checked;
RpfSearchButton.Enabled = true;
RpfSearchSaveResultsButton.Enabled = true;
}
}
catch { }
}
private void RpfSearchButton_Click(object sender, EventArgs e)
{
RpfSearch();
}
private void RpfSearchAbortButton_Click(object sender, EventArgs e)
{
AbortOperation = true;
}
private void RpfSearchSaveResultsButton_Click(object sender, EventArgs e)
{
SaveFileDialog.FileName = "SearchResults.txt";
if (SaveFileDialog.ShowDialog() == DialogResult.OK)
{
string fpath = SaveFileDialog.FileName;
StringBuilder sb = new StringBuilder();
sb.AppendLine("CodeWalker Search Results for \"" + RpfSearchTextBox.Text + "\"");
sb.AppendLine("[File path], [Byte offset]");
if (RpfSearchResults != null)
{
foreach (var r in RpfSearchResults)
{
sb.AppendLine(r.FileEntry.Path + ", " + r.Offset.ToString());
}
}
File.WriteAllText(fpath, sb.ToString());
}
}
private void RpfSearchIgnoreCheckBox_CheckedChanged(object sender, EventArgs e)
{
RpfSearchIgnoreTextBox.Enabled = RpfSearchIgnoreCheckBox.Checked;
if (RpfSearchIgnoreCheckBox.Checked)
{
RpfSearchOnlyCheckBox.Checked = false;
}
}
private void RpfSearchOnlyCheckBox_CheckedChanged(object sender, EventArgs e)
{
RpfSearchOnlyTextBox.Enabled = RpfSearchOnlyCheckBox.Checked;
if (RpfSearchOnlyCheckBox.Checked)
{
RpfSearchIgnoreCheckBox.Checked = false;
}
}
private void RpfSearchTextRadioButton_CheckedChanged(object sender, EventArgs e)
{
RpfSearchCaseSensitiveCheckBox.Enabled = RpfSearchTextRadioButton.Checked;
}
private void RpfSearchResultsListView_SelectedIndexChanged(object sender, EventArgs e)
{
if (RpfSearchResultsListView.SelectedIndices.Count == 1)
{
var i = RpfSearchResultsListView.SelectedIndices[0];
if ((i >= 0) && (i < RpfSearchResults.Count))
{
var r = RpfSearchResults[i];
SelectFile(r.FileEntry, r.Offset + 1, r.Length);
}
else
{
SelectFile(null, -1, 0);
}
}
else
{
SelectFile(null, -1, 0);
}
}
private void RpfSearchResultsListView_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
{
var item = new ListViewItem();
if (e.ItemIndex < RpfSearchResults.Count)
{
RpfSearchResult r = RpfSearchResults[e.ItemIndex];
item.Text = r.FileEntry.Name;
item.SubItems.Add(r.Offset.ToString());
item.Tag = r;
}
e.Item = item;
}
private void SelectFile()
{
SelectFile(RpfSelectedEntry, RpfSelectedOffset, RpfSelectedLength);
}
private void SelectFile(RpfEntry entry, int offset, int length)
{
RpfSelectedEntry = entry;
RpfSelectedOffset = offset;
RpfSelectedLength = length;
RpfFileEntry rfe = entry as RpfFileEntry;
if (rfe == null)
{
RpfDirectoryEntry rde = entry as RpfDirectoryEntry;
if (rde != null)
{
FileInfoLabel.Text = rde.Path + " (Directory)";
DataTextBox.Text = "[Please select a data file]";
}
else
{
FileInfoLabel.Text = "[Nothing selected]";
DataTextBox.Text = "[Please select a search result]";
}
return;
}
Cursor = Cursors.WaitCursor;
string typestr = "Resource";
if (rfe is RpfBinaryFileEntry)
{
typestr = "Binary";
}
byte[] data = rfe.File.ExtractFile(rfe);
int datalen = (data != null) ? data.Length : 0;
FileInfoLabel.Text = rfe.Path + " (" + typestr + " file) - " + TextUtil.GetBytesReadable(datalen);
if (ShowLargeFileContentsCheckBox.Checked || (datalen < 524287)) //512K
{
DisplayFileContentsText(rfe, data, length, offset);
}
else
{
DataTextBox.Text = "[Filesize >512KB. Select the Show large files option to view its contents]";
}
//bool istexdict = false;
//if (rfe.NameLower.EndsWith(".ymap"))
//{
// YmapFile ymap = new YmapFile(rfe);
// ymap.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ymap;
//}
//else if (rfe.NameLower.EndsWith(".ytyp"))
//{
// YtypFile ytyp = new YtypFile();
// ytyp.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ytyp;
//}
//else if (rfe.NameLower.EndsWith(".ymf"))
//{
// YmfFile ymf = new YmfFile();
// ymf.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ymf;
//}
//else if (rfe.NameLower.EndsWith(".ymt"))
//{
// YmtFile ymt = new YmtFile();
// ymt.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ymt;
//}
//else if (rfe.NameLower.EndsWith(".ybn"))
//{
// YbnFile ybn = new YbnFile();
// ybn.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ybn;
//}
//else if (rfe.NameLower.EndsWith(".fxc"))
//{
// FxcFile fxc = new FxcFile();
// fxc.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = fxc;
//}
//else if (rfe.NameLower.EndsWith(".yft"))
//{
// YftFile yft = new YftFile();
// yft.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = yft;
// if ((yft.Fragment != null) && (yft.Fragment.Drawable != null) && (yft.Fragment.Drawable.ShaderGroup != null) && (yft.Fragment.Drawable.ShaderGroup.TextureDictionary != null))
// {
// ShowTextures(yft.Fragment.Drawable.ShaderGroup.TextureDictionary);
// istexdict = true;
// }
//}
//else if (rfe.NameLower.EndsWith(".ydr"))
//{
// YdrFile ydr = new YdrFile();
// ydr.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ydr;
// if ((ydr.Drawable != null) && (ydr.Drawable.ShaderGroup != null) && (ydr.Drawable.ShaderGroup.TextureDictionary != null))
// {
// ShowTextures(ydr.Drawable.ShaderGroup.TextureDictionary);
// istexdict = true;
// }
//}
//else if (rfe.NameLower.EndsWith(".ydd"))
//{
// YddFile ydd = new YddFile();
// ydd.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ydd;
// //todo: show embedded texdicts in ydd's? is this possible?
//}
//else if (rfe.NameLower.EndsWith(".ytd"))
//{
// YtdFile ytd = new YtdFile();
// ytd.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ytd;
// ShowTextures(ytd.TextureDict);
// istexdict = true;
//}
//else if (rfe.NameLower.EndsWith(".ycd"))
//{
// YcdFile ycd = new YcdFile();
// ycd.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ycd;
//}
//else if (rfe.NameLower.EndsWith(".ynd"))
//{
// YndFile ynd = new YndFile();
// ynd.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ynd;
//}
//else if (rfe.NameLower.EndsWith(".ynv"))
//{
// YnvFile ynv = new YnvFile();
// ynv.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = ynv;
//}
//else if (rfe.NameLower.EndsWith("_cache_y.dat"))
//{
// CacheDatFile cdf = new CacheDatFile();
// cdf.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = cdf;
//}
//else if (rfe.NameLower.EndsWith(".rel"))
//{
// RelFile rel = new RelFile(rfe);
// rel.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = rel;
//}
//else if (rfe.NameLower.EndsWith(".gxt2"))
//{
// Gxt2File gxt2 = new Gxt2File();
// gxt2.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = gxt2;
//}
//else if (rfe.NameLower.EndsWith(".pso"))
//{
// JPsoFile pso = new JPsoFile();
// pso.Load(data, rfe);
// DetailsPropertyGrid.SelectedObject = pso;
//}
//else
//{
// DetailsPropertyGrid.SelectedObject = null;
//}
//if (!istexdict)
//{
// ShowTextures(null);
//}
Cursor = Cursors.Default;
}
private void DisplayFileContentsText(RpfFileEntry rfe, byte[] data, int length, int offset)
{
if (data == null)
{
Cursor = Cursors.Default;
DataTextBox.Text = "[Error extracting file! " + rfe.File.LastError + "]";
return;
}
int selline = -1;
int selstartc = -1;
int selendc = -1;
if (DataHexRadio.Checked)
{
int charsperln = int.Parse(DataHexLineCombo.Text);
int lines = (data.Length / charsperln) + (((data.Length % charsperln) > 0) ? 1 : 0);
StringBuilder hexb = new StringBuilder();
StringBuilder texb = new StringBuilder();
StringBuilder finb = new StringBuilder();
if (offset > 0)
{
selline = offset / charsperln;
}
for (int i = 0; i < lines; i++)
{
int pos = i * charsperln;
int poslim = pos + charsperln;
hexb.Clear();
texb.Clear();
hexb.AppendFormat("{0:X4}: ", pos);
for (int c = pos; c < poslim; c++)
{
if (c < data.Length)
{
byte b = data[c];
hexb.AppendFormat("{0:X2} ", b);
if (char.IsControl((char)b))
{
texb.Append(".");
}
else
{
texb.Append(Encoding.ASCII.GetString(data, c, 1));
}
}
else
{
hexb.Append(" ");
texb.Append(" ");
}
}
if (i == selline) selstartc = finb.Length;
finb.AppendLine(hexb.ToString() + "| " + texb.ToString());
if (i == selline) selendc = finb.Length - 1;
}
DataTextBox.Text = finb.ToString();
}
else
{
string text = Encoding.UTF8.GetString(data);
DataTextBox.Text = text;
if (offset > 0)
{
selstartc = offset;
selendc = offset + length;
}
}
if ((selstartc > 0) && (selendc > 0))
{
DataTextBox.SelectionStart = selstartc;
DataTextBox.SelectionLength = selendc - selstartc;
DataTextBox.ScrollToCaret();
}
}
private void ExportButton_Click(object sender, EventArgs e)
{
if (InProgress) return;
if (!(RpfMan?.IsInited ?? false))
{
MessageBox.Show("Please wait for the scan to complete.");
return;
}
RpfFileEntry rfe = RpfSelectedEntry as RpfFileEntry;
if (rfe == null)
{
MessageBox.Show("Please select a file to export.");
return;
}
SaveFileDialog.FileName = rfe.Name;
if (SaveFileDialog.ShowDialog() == DialogResult.OK)
{
string fpath = SaveFileDialog.FileName;
byte[] data = rfe.File.ExtractFile(rfe);
if (ExportCompressCheckBox.Checked)
{
data = ResourceBuilder.Compress(data);
}
RpfResourceFileEntry rrfe = rfe as RpfResourceFileEntry;
if (rrfe != null) //add resource header if this is a resource file.
{
data = ResourceBuilder.AddResourceHeader(rrfe, data);
}
if (data == null)
{
MessageBox.Show("Error extracting file! " + rfe.File.LastError);
return;
}
try
{
File.WriteAllBytes(fpath, data);
}
catch (Exception ex)
{
MessageBox.Show("Error saving file! " + ex.ToString());
}
}
}
private void DataHexRadio_CheckedChanged(object sender, EventArgs e)
{
SelectFile();
}
private void DataHexLineCombo_SelectedIndexChanged(object sender, EventArgs e)
{
SelectFile();
}
private void ShowLargeFileContentsCheckBox_CheckedChanged(object sender, EventArgs e)
{
SelectFile();
}
}
}

418
BinarySearchForm.resx Normal file
View File

@ -0,0 +1,418 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="FolderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="MainStatusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>182, 17</value>
</metadata>
<metadata name="SaveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>317, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
6P///ysvjWVqtP///////wAAAAAAAAAAAP////D0/0hPpsDG6////////6y02d7k8////3qAx+/z/f//
/wAAAAAAAAAAAAAAAAAAAP///////////////8zT8V5ns1Rcrdzh9f///////////wAAAAAAAAAAAAAA
AAAAAP////////7+/6ix3nmBxFthtmdwu09WqbC54/v9//r8//j6//39/wAAAAAAAAAAAOjt/H6I0FJc
skpSqHF+wRMahFZhs4iT1AsNc1pgrm52v2RsuO/z/gAAAP////////L2/cLJ7rrD64+V4DY+ozU+mYmU
0X2Hy1hfss7V8urv/PP2/v///wAAAP///+Pp+d/k9////////+Pp/4uR3ysymW14xYOM0fD0/P///+Xq
+ri/6Pj6/wAAAOrv/j5DnbS75P////////////X4/+/0/ubr+/r7/////////9rh+hgZhKGo2QAAAPDz
/eLn+f////j6/2Nqttrg9////+Hn+P3+//3+/1hescLJ6/////L2/eru/AAAAAAAAAAAAP///8rR70tR
p/3+//v8/zY6jNPY7////09WqWpwu////wAAAAAAAAAAAAAAAAAAAAAAAPb4/vr7//////v8/5Wd1eHm
+P////v8//T3/wAAAAAAAAAAAAAAAP//AAD8PwAA/D8AAPwDAACAAwAAgAMAAIAHAADABwAAwAEAAMAB
AAAAAQAAAAEAAAABAAAAAQAAwAcAAOAPAAAoAAAAQAAAAIAAAAABABgAAAAAAAAwAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7//P3//P3//P3/
/f7//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/
+fv/+fv/+Pr/+fv/+vv//P3//v//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA/f7/+fr/8/b/7PL/5+3/6e/+9Pf/+vv//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA/P3/9/r/6O7/cXe1UVaet7z17fL/+Pr//f3/AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+/z/9Pj/4Oj/NzyCUlOd2dz/6O//9Pf//P3/AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8vb/2+P9X2OmREGLnqPd
4+v/8vb/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8fb/
1N35bXK1JSRtbHGz5O7/8fX/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA+vv/8PX/3Ob/U1eaDwtXjZLT4+z/8fX/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA+vv/8fb/2eP+MjR6AAA+c3i34Or/8fX/+/z/AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8vb/1d/7MS91AAA1UFSS4On/8vb/+/z/AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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
/v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/+vz/+fv/+Pr/+Pr/+vv//f3//v//AAAAAAAAAAAAAAAA
/v//+fv/9Pf/2+L/SVGtAABsLTaZytL58fX/9/n//f7/AAAAAAAAAAAAAAAA/v7/+/z/9/n/9fj/9vn/
9fj/9vj/+vz//f7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7//f3//f3//f3//v7//v//AAAA
AAAAAAAAAAAAAAAAAAAA+/z/9vn/6e//mZ7gTVarr7bp6/H/9fj/+vv//v7/AAAAAAAAAAAAAAAAAAAA
/v7//f7/+/z/+/z/+/z//P3//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/f3/+Pr/9fj/6e7/4+n/8fb/9Pf/+Pr//f3/AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/+fv/+fv/+vv/+Pr/+vv/
/P3//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7/
/f3//P3//f7//v7//v//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////
///////4D/////////AH////////8Af////////wB/////////AH////////8Af////////wB///////
//AH////////8Af////////wB/////////AH////////8AfwP//////wB8Af//+Af/AHgB///wA/8AcA
H///AB/wBgAf//8AD/AGAB///wAH8AYAH///AAPwBAAf//8AA/AEAD///wAD8AQAP///AAPwBAB///+A
A/AEAP///8AD4AAA////4AcAAAH////wDgAAAf/////8AAAH//////gAAAf/////4AAAAf/////gAAAA
/f//+AAAAAAAD//AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+A
AAAAAAAP/4AAAAAAAB//wAAAAABAf/4HwAAAAYAf8APAAAADgA/gA+AAAAMAA8AD8AAABwADgAP8AAAf
AAOAA/4AAB8AA4ADAAAAAQADgAIAcA4AgAOABgBwDgBAA4AMAGAMADADwDwAYAwAOAfg+ABgBAAeH//4
AEAEAB////gAwAYAH///+ADABgAf///4AcAGAB////gBwAcAH///+APAB4A////8B+AHwH//////4A//
///////gD/////////Af//////////////8=
</value>
</data>
</root>

846
BrowseForm.Designer.cs generated Normal file
View File

@ -0,0 +1,846 @@
namespace CodeWalker
{
partial class BrowseForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BrowseForm));
this.label1 = new System.Windows.Forms.Label();
this.FolderBrowseButton = new System.Windows.Forms.Button();
this.FolderTextBox = new System.Windows.Forms.TextBox();
this.ScanButton = new System.Windows.Forms.Button();
this.FolderBrowserDialog = new System.Windows.Forms.FolderBrowserDialog();
this.splitContainer1 = new System.Windows.Forms.SplitContainer();
this.tabControl1 = new System.Windows.Forms.TabControl();
this.tabPage1 = new System.Windows.Forms.TabPage();
this.FlattenStructureCheckBox = new System.Windows.Forms.CheckBox();
this.FindButton = new System.Windows.Forms.Button();
this.MainTreeView = new System.Windows.Forms.TreeView();
this.label2 = new System.Windows.Forms.Label();
this.FindTextBox = new System.Windows.Forms.TextBox();
this.tabPage2 = new System.Windows.Forms.TabPage();
this.SearchSaveResultsButton = new System.Windows.Forms.Button();
this.SearchIgnoreTextBox = new System.Windows.Forms.TextBox();
this.SearchIgnoreCheckBox = new System.Windows.Forms.CheckBox();
this.SearchBothDirectionsCheckBox = new System.Windows.Forms.CheckBox();
this.SearchCaseSensitiveCheckBox = new System.Windows.Forms.CheckBox();
this.SearchHexRadioButton = new System.Windows.Forms.RadioButton();
this.SearchTextRadioButton = new System.Windows.Forms.RadioButton();
this.SearchResultsListView = new System.Windows.Forms.ListView();
this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.SearchAbortButton = new System.Windows.Forms.Button();
this.SearchButton = new System.Windows.Forms.Button();
this.label3 = new System.Windows.Forms.Label();
this.SearchTextBox = new System.Windows.Forms.TextBox();
this.ExportCompressCheckBox = new System.Windows.Forms.CheckBox();
this.ExportButton = new System.Windows.Forms.Button();
this.FileInfoLabel = new System.Windows.Forms.Label();
this.SelectionTabControl = new System.Windows.Forms.TabControl();
this.tabPage3 = new System.Windows.Forms.TabPage();
this.ShowLargeFileContentsCheckBox = new System.Windows.Forms.CheckBox();
this.DataHexLineCombo = new System.Windows.Forms.ComboBox();
this.DataTextRadio = new System.Windows.Forms.RadioButton();
this.DataHexRadio = new System.Windows.Forms.RadioButton();
this.DataTextBox = new System.Windows.Forms.TextBox();
this.tabPage4 = new System.Windows.Forms.TabPage();
this.DetailsPropertyGrid = new CodeWalker.WinForms.PropertyGridFix();
this.TexturesTabPage = new System.Windows.Forms.TabPage();
this.splitContainer2 = new System.Windows.Forms.SplitContainer();
this.SelTexturesListView = new System.Windows.Forms.ListView();
this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.SelTextureMipLabel = new System.Windows.Forms.Label();
this.label5 = new System.Windows.Forms.Label();
this.SelTextureDimensionsLabel = new System.Windows.Forms.Label();
this.SelTextureMipTrackBar = new System.Windows.Forms.TrackBar();
this.label4 = new System.Windows.Forms.Label();
this.SelTextureNameTextBox = new System.Windows.Forms.TextBox();
this.SelTexturePictureBox = new System.Windows.Forms.PictureBox();
this.MainStatusStrip = new System.Windows.Forms.StatusStrip();
this.StatusLabel = new System.Windows.Forms.ToolStripStatusLabel();
this.TestAllButton = new System.Windows.Forms.Button();
this.AbortButton = new System.Windows.Forms.Button();
this.SaveFileDialog = new System.Windows.Forms.SaveFileDialog();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit();
this.splitContainer1.Panel1.SuspendLayout();
this.splitContainer1.Panel2.SuspendLayout();
this.splitContainer1.SuspendLayout();
this.tabControl1.SuspendLayout();
this.tabPage1.SuspendLayout();
this.tabPage2.SuspendLayout();
this.SelectionTabControl.SuspendLayout();
this.tabPage3.SuspendLayout();
this.tabPage4.SuspendLayout();
this.TexturesTabPage.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit();
this.splitContainer2.Panel1.SuspendLayout();
this.splitContainer2.Panel2.SuspendLayout();
this.splitContainer2.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.SelTextureMipTrackBar)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.SelTexturePictureBox)).BeginInit();
this.MainStatusStrip.SuspendLayout();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(68, 13);
this.label1.TabIndex = 47;
this.label1.Text = "GTAV folder:";
//
// FolderBrowseButton
//
this.FolderBrowseButton.Location = new System.Drawing.Point(347, 4);
this.FolderBrowseButton.Name = "FolderBrowseButton";
this.FolderBrowseButton.Size = new System.Drawing.Size(27, 23);
this.FolderBrowseButton.TabIndex = 2;
this.FolderBrowseButton.Text = "...";
this.FolderBrowseButton.UseVisualStyleBackColor = true;
this.FolderBrowseButton.Click += new System.EventHandler(this.FolderBrowseButton_Click);
//
// FolderTextBox
//
this.FolderTextBox.Location = new System.Drawing.Point(90, 6);
this.FolderTextBox.Name = "FolderTextBox";
this.FolderTextBox.ReadOnly = true;
this.FolderTextBox.Size = new System.Drawing.Size(251, 20);
this.FolderTextBox.TabIndex = 1;
//
// ScanButton
//
this.ScanButton.Location = new System.Drawing.Point(380, 4);
this.ScanButton.Name = "ScanButton";
this.ScanButton.Size = new System.Drawing.Size(75, 23);
this.ScanButton.TabIndex = 0;
this.ScanButton.Text = "Scan";
this.ScanButton.UseVisualStyleBackColor = true;
this.ScanButton.Click += new System.EventHandler(this.ScanButton_Click);
//
// splitContainer1
//
this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.splitContainer1.Location = new System.Drawing.Point(0, 32);
this.splitContainer1.Name = "splitContainer1";
//
// splitContainer1.Panel1
//
this.splitContainer1.Panel1.Controls.Add(this.tabControl1);
//
// splitContainer1.Panel2
//
this.splitContainer1.Panel2.Controls.Add(this.ExportCompressCheckBox);
this.splitContainer1.Panel2.Controls.Add(this.ExportButton);
this.splitContainer1.Panel2.Controls.Add(this.FileInfoLabel);
this.splitContainer1.Panel2.Controls.Add(this.SelectionTabControl);
this.splitContainer1.Size = new System.Drawing.Size(855, 492);
this.splitContainer1.SplitterDistance = 281;
this.splitContainer1.TabIndex = 5;
//
// tabControl1
//
this.tabControl1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.tabControl1.Controls.Add(this.tabPage1);
this.tabControl1.Controls.Add(this.tabPage2);
this.tabControl1.Location = new System.Drawing.Point(0, 3);
this.tabControl1.Name = "tabControl1";
this.tabControl1.SelectedIndex = 0;
this.tabControl1.Size = new System.Drawing.Size(278, 489);
this.tabControl1.TabIndex = 0;
//
// tabPage1
//
this.tabPage1.Controls.Add(this.FlattenStructureCheckBox);
this.tabPage1.Controls.Add(this.FindButton);
this.tabPage1.Controls.Add(this.MainTreeView);
this.tabPage1.Controls.Add(this.label2);
this.tabPage1.Controls.Add(this.FindTextBox);
this.tabPage1.Location = new System.Drawing.Point(4, 22);
this.tabPage1.Name = "tabPage1";
this.tabPage1.Padding = new System.Windows.Forms.Padding(3);
this.tabPage1.Size = new System.Drawing.Size(270, 463);
this.tabPage1.TabIndex = 0;
this.tabPage1.Text = "Browse";
this.tabPage1.UseVisualStyleBackColor = true;
//
// FlattenStructureCheckBox
//
this.FlattenStructureCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.FlattenStructureCheckBox.AutoSize = true;
this.FlattenStructureCheckBox.Location = new System.Drawing.Point(3, 443);
this.FlattenStructureCheckBox.Name = "FlattenStructureCheckBox";
this.FlattenStructureCheckBox.Size = new System.Drawing.Size(128, 17);
this.FlattenStructureCheckBox.TabIndex = 50;
this.FlattenStructureCheckBox.Text = "Flatten RPF Structure";
this.FlattenStructureCheckBox.UseVisualStyleBackColor = true;
this.FlattenStructureCheckBox.CheckedChanged += new System.EventHandler(this.FlattenStructureCheckBox_CheckedChanged);
//
// FindButton
//
this.FindButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.FindButton.Location = new System.Drawing.Point(240, 4);
this.FindButton.Name = "FindButton";
this.FindButton.Size = new System.Drawing.Size(27, 22);
this.FindButton.TabIndex = 11;
this.FindButton.Text = ">";
this.FindButton.UseVisualStyleBackColor = true;
this.FindButton.Click += new System.EventHandler(this.FindButton_Click);
//
// MainTreeView
//
this.MainTreeView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.MainTreeView.HideSelection = false;
this.MainTreeView.Location = new System.Drawing.Point(0, 32);
this.MainTreeView.Name = "MainTreeView";
this.MainTreeView.Size = new System.Drawing.Size(267, 408);
this.MainTreeView.TabIndex = 12;
this.MainTreeView.AfterSelect += new System.Windows.Forms.TreeViewEventHandler(this.MainTreeView_AfterSelect);
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(4, 8);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(30, 13);
this.label2.TabIndex = 49;
this.label2.Text = "Find:";
//
// FindTextBox
//
this.FindTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.FindTextBox.Location = new System.Drawing.Point(38, 5);
this.FindTextBox.Name = "FindTextBox";
this.FindTextBox.Size = new System.Drawing.Size(199, 20);
this.FindTextBox.TabIndex = 10;
this.FindTextBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.FindTextBox_KeyPress);
//
// tabPage2
//
this.tabPage2.Controls.Add(this.SearchSaveResultsButton);
this.tabPage2.Controls.Add(this.SearchIgnoreTextBox);
this.tabPage2.Controls.Add(this.SearchIgnoreCheckBox);
this.tabPage2.Controls.Add(this.SearchBothDirectionsCheckBox);
this.tabPage2.Controls.Add(this.SearchCaseSensitiveCheckBox);
this.tabPage2.Controls.Add(this.SearchHexRadioButton);
this.tabPage2.Controls.Add(this.SearchTextRadioButton);
this.tabPage2.Controls.Add(this.SearchResultsListView);
this.tabPage2.Controls.Add(this.SearchAbortButton);
this.tabPage2.Controls.Add(this.SearchButton);
this.tabPage2.Controls.Add(this.label3);
this.tabPage2.Controls.Add(this.SearchTextBox);
this.tabPage2.Location = new System.Drawing.Point(4, 22);
this.tabPage2.Name = "tabPage2";
this.tabPage2.Padding = new System.Windows.Forms.Padding(3);
this.tabPage2.Size = new System.Drawing.Size(270, 463);
this.tabPage2.TabIndex = 1;
this.tabPage2.Text = "Search";
this.tabPage2.UseVisualStyleBackColor = true;
//
// SearchSaveResultsButton
//
this.SearchSaveResultsButton.Enabled = false;
this.SearchSaveResultsButton.Location = new System.Drawing.Point(178, 95);
this.SearchSaveResultsButton.Name = "SearchSaveResultsButton";
this.SearchSaveResultsButton.Size = new System.Drawing.Size(86, 22);
this.SearchSaveResultsButton.TabIndex = 19;
this.SearchSaveResultsButton.Text = "Save results...";
this.SearchSaveResultsButton.UseVisualStyleBackColor = true;
this.SearchSaveResultsButton.Click += new System.EventHandler(this.SearchSaveResultsButton_Click);
//
// SearchIgnoreTextBox
//
this.SearchIgnoreTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.SearchIgnoreTextBox.Location = new System.Drawing.Point(65, 70);
this.SearchIgnoreTextBox.Name = "SearchIgnoreTextBox";
this.SearchIgnoreTextBox.Size = new System.Drawing.Size(202, 20);
this.SearchIgnoreTextBox.TabIndex = 16;
this.SearchIgnoreTextBox.Text = ".ydr, .ydd, .ytd, .yft, .ybn, .ycd, .awc, .bik";
//
// SearchIgnoreCheckBox
//
this.SearchIgnoreCheckBox.AutoSize = true;
this.SearchIgnoreCheckBox.Checked = true;
this.SearchIgnoreCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
this.SearchIgnoreCheckBox.Location = new System.Drawing.Point(6, 72);
this.SearchIgnoreCheckBox.Name = "SearchIgnoreCheckBox";
this.SearchIgnoreCheckBox.Size = new System.Drawing.Size(59, 17);
this.SearchIgnoreCheckBox.TabIndex = 15;
this.SearchIgnoreCheckBox.Text = "Ignore:";
this.SearchIgnoreCheckBox.UseVisualStyleBackColor = true;
this.SearchIgnoreCheckBox.CheckedChanged += new System.EventHandler(this.SearchIgnoreCheckBox_CheckedChanged);
//
// SearchBothDirectionsCheckBox
//
this.SearchBothDirectionsCheckBox.AutoSize = true;
this.SearchBothDirectionsCheckBox.Checked = true;
this.SearchBothDirectionsCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
this.SearchBothDirectionsCheckBox.Location = new System.Drawing.Point(106, 50);
this.SearchBothDirectionsCheckBox.Name = "SearchBothDirectionsCheckBox";
this.SearchBothDirectionsCheckBox.Size = new System.Drawing.Size(96, 17);
this.SearchBothDirectionsCheckBox.TabIndex = 14;
this.SearchBothDirectionsCheckBox.Text = "Both directions";
this.SearchBothDirectionsCheckBox.UseVisualStyleBackColor = true;
//
// SearchCaseSensitiveCheckBox
//
this.SearchCaseSensitiveCheckBox.AutoSize = true;
this.SearchCaseSensitiveCheckBox.Location = new System.Drawing.Point(6, 50);
this.SearchCaseSensitiveCheckBox.Name = "SearchCaseSensitiveCheckBox";
this.SearchCaseSensitiveCheckBox.Size = new System.Drawing.Size(94, 17);
this.SearchCaseSensitiveCheckBox.TabIndex = 13;
this.SearchCaseSensitiveCheckBox.Text = "Case-sensitive";
this.SearchCaseSensitiveCheckBox.UseVisualStyleBackColor = true;
//
// SearchHexRadioButton
//
this.SearchHexRadioButton.AutoSize = true;
this.SearchHexRadioButton.Location = new System.Drawing.Point(155, 7);
this.SearchHexRadioButton.Name = "SearchHexRadioButton";
this.SearchHexRadioButton.Size = new System.Drawing.Size(44, 17);
this.SearchHexRadioButton.TabIndex = 12;
this.SearchHexRadioButton.Text = "Hex";
this.SearchHexRadioButton.UseVisualStyleBackColor = true;
this.SearchHexRadioButton.CheckedChanged += new System.EventHandler(this.SearchHexRadioButton_CheckedChanged);
//
// SearchTextRadioButton
//
this.SearchTextRadioButton.AutoSize = true;
this.SearchTextRadioButton.Checked = true;
this.SearchTextRadioButton.Location = new System.Drawing.Point(103, 7);
this.SearchTextRadioButton.Name = "SearchTextRadioButton";
this.SearchTextRadioButton.Size = new System.Drawing.Size(46, 17);
this.SearchTextRadioButton.TabIndex = 11;
this.SearchTextRadioButton.TabStop = true;
this.SearchTextRadioButton.Text = "Text";
this.SearchTextRadioButton.UseVisualStyleBackColor = true;
this.SearchTextRadioButton.CheckedChanged += new System.EventHandler(this.SearchTextRadioButton_CheckedChanged);
//
// SearchResultsListView
//
this.SearchResultsListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.SearchResultsListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader1,
this.columnHeader2});
this.SearchResultsListView.FullRowSelect = true;
this.SearchResultsListView.HideSelection = false;
this.SearchResultsListView.Location = new System.Drawing.Point(0, 123);
this.SearchResultsListView.MultiSelect = false;
this.SearchResultsListView.Name = "SearchResultsListView";
this.SearchResultsListView.Size = new System.Drawing.Size(267, 340);
this.SearchResultsListView.TabIndex = 20;
this.SearchResultsListView.UseCompatibleStateImageBehavior = false;
this.SearchResultsListView.View = System.Windows.Forms.View.Details;
this.SearchResultsListView.VirtualMode = true;
this.SearchResultsListView.RetrieveVirtualItem += new System.Windows.Forms.RetrieveVirtualItemEventHandler(this.SearchResultsListView_RetrieveVirtualItem);
this.SearchResultsListView.SelectedIndexChanged += new System.EventHandler(this.SearchResultsListView_SelectedIndexChanged);
//
// columnHeader1
//
this.columnHeader1.Text = "File";
this.columnHeader1.Width = 176;
//
// columnHeader2
//
this.columnHeader2.Text = "Offset";
//
// SearchAbortButton
//
this.SearchAbortButton.Location = new System.Drawing.Point(87, 95);
this.SearchAbortButton.Name = "SearchAbortButton";
this.SearchAbortButton.Size = new System.Drawing.Size(75, 22);
this.SearchAbortButton.TabIndex = 18;
this.SearchAbortButton.Text = "Abort";
this.SearchAbortButton.UseVisualStyleBackColor = true;
this.SearchAbortButton.Click += new System.EventHandler(this.SearchAbortButton_Click);
//
// SearchButton
//
this.SearchButton.Location = new System.Drawing.Point(6, 95);
this.SearchButton.Name = "SearchButton";
this.SearchButton.Size = new System.Drawing.Size(75, 22);
this.SearchButton.TabIndex = 17;
this.SearchButton.Text = "Search";
this.SearchButton.UseVisualStyleBackColor = true;
this.SearchButton.Click += new System.EventHandler(this.SearchButton_Click);
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(4, 9);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(91, 13);
this.label3.TabIndex = 52;
this.label3.Text = "Search in files for:";
//
// SearchTextBox
//
this.SearchTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.SearchTextBox.Location = new System.Drawing.Point(3, 27);
this.SearchTextBox.Name = "SearchTextBox";
this.SearchTextBox.Size = new System.Drawing.Size(264, 20);
this.SearchTextBox.TabIndex = 10;
//
// ExportCompressCheckBox
//
this.ExportCompressCheckBox.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.ExportCompressCheckBox.AutoSize = true;
this.ExportCompressCheckBox.Location = new System.Drawing.Point(414, 5);
this.ExportCompressCheckBox.Name = "ExportCompressCheckBox";
this.ExportCompressCheckBox.Size = new System.Drawing.Size(72, 17);
this.ExportCompressCheckBox.TabIndex = 105;
this.ExportCompressCheckBox.Text = "Compress";
this.ExportCompressCheckBox.UseVisualStyleBackColor = true;
//
// ExportButton
//
this.ExportButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.ExportButton.Location = new System.Drawing.Point(488, 2);
this.ExportButton.Name = "ExportButton";
this.ExportButton.Size = new System.Drawing.Size(75, 23);
this.ExportButton.TabIndex = 104;
this.ExportButton.Text = "Export...";
this.ExportButton.UseVisualStyleBackColor = true;
this.ExportButton.Click += new System.EventHandler(this.ExportButton_Click);
//
// FileInfoLabel
//
this.FileInfoLabel.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.FileInfoLabel.AutoEllipsis = true;
this.FileInfoLabel.Location = new System.Drawing.Point(7, 6);
this.FileInfoLabel.Name = "FileInfoLabel";
this.FileInfoLabel.Size = new System.Drawing.Size(401, 16);
this.FileInfoLabel.TabIndex = 51;
this.FileInfoLabel.Text = "[Nothing selected]";
//
// SelectionTabControl
//
this.SelectionTabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.SelectionTabControl.Controls.Add(this.tabPage3);
this.SelectionTabControl.Controls.Add(this.tabPage4);
this.SelectionTabControl.Controls.Add(this.TexturesTabPage);
this.SelectionTabControl.Location = new System.Drawing.Point(3, 30);
this.SelectionTabControl.Name = "SelectionTabControl";
this.SelectionTabControl.SelectedIndex = 0;
this.SelectionTabControl.Size = new System.Drawing.Size(564, 462);
this.SelectionTabControl.TabIndex = 0;
//
// tabPage3
//
this.tabPage3.Controls.Add(this.ShowLargeFileContentsCheckBox);
this.tabPage3.Controls.Add(this.DataHexLineCombo);
this.tabPage3.Controls.Add(this.DataTextRadio);
this.tabPage3.Controls.Add(this.DataHexRadio);
this.tabPage3.Controls.Add(this.DataTextBox);
this.tabPage3.Location = new System.Drawing.Point(4, 22);
this.tabPage3.Name = "tabPage3";
this.tabPage3.Padding = new System.Windows.Forms.Padding(3);
this.tabPage3.Size = new System.Drawing.Size(556, 436);
this.tabPage3.TabIndex = 0;
this.tabPage3.Text = "Data";
this.tabPage3.UseVisualStyleBackColor = true;
//
// ShowLargeFileContentsCheckBox
//
this.ShowLargeFileContentsCheckBox.AutoSize = true;
this.ShowLargeFileContentsCheckBox.Location = new System.Drawing.Point(395, 7);
this.ShowLargeFileContentsCheckBox.Name = "ShowLargeFileContentsCheckBox";
this.ShowLargeFileContentsCheckBox.Size = new System.Drawing.Size(139, 17);
this.ShowLargeFileContentsCheckBox.TabIndex = 104;
this.ShowLargeFileContentsCheckBox.Text = "Show large file contents";
this.ShowLargeFileContentsCheckBox.UseVisualStyleBackColor = true;
this.ShowLargeFileContentsCheckBox.CheckedChanged += new System.EventHandler(this.ShowLargeFileContentsCheckBox_CheckedChanged);
//
// DataHexLineCombo
//
this.DataHexLineCombo.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.DataHexLineCombo.FormattingEnabled = true;
this.DataHexLineCombo.Items.AddRange(new object[] {
"8",
"16",
"32"});
this.DataHexLineCombo.Location = new System.Drawing.Point(56, 5);
this.DataHexLineCombo.Name = "DataHexLineCombo";
this.DataHexLineCombo.Size = new System.Drawing.Size(49, 21);
this.DataHexLineCombo.TabIndex = 101;
this.DataHexLineCombo.SelectedIndexChanged += new System.EventHandler(this.DataHexLineCombo_SelectedIndexChanged);
//
// DataTextRadio
//
this.DataTextRadio.AutoSize = true;
this.DataTextRadio.Location = new System.Drawing.Point(176, 6);
this.DataTextRadio.Name = "DataTextRadio";
this.DataTextRadio.Size = new System.Drawing.Size(46, 17);
this.DataTextRadio.TabIndex = 102;
this.DataTextRadio.Text = "Text";
this.DataTextRadio.UseVisualStyleBackColor = true;
this.DataTextRadio.CheckedChanged += new System.EventHandler(this.DataTextRadio_CheckedChanged);
//
// DataHexRadio
//
this.DataHexRadio.AutoSize = true;
this.DataHexRadio.Checked = true;
this.DataHexRadio.Location = new System.Drawing.Point(6, 6);
this.DataHexRadio.Name = "DataHexRadio";
this.DataHexRadio.Size = new System.Drawing.Size(44, 17);
this.DataHexRadio.TabIndex = 100;
this.DataHexRadio.TabStop = true;
this.DataHexRadio.Text = "Hex";
this.DataHexRadio.UseVisualStyleBackColor = true;
this.DataHexRadio.CheckedChanged += new System.EventHandler(this.DataHexRadio_CheckedChanged);
//
// DataTextBox
//
this.DataTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.DataTextBox.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.DataTextBox.HideSelection = false;
this.DataTextBox.Location = new System.Drawing.Point(6, 29);
this.DataTextBox.Multiline = true;
this.DataTextBox.Name = "DataTextBox";
this.DataTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.DataTextBox.Size = new System.Drawing.Size(544, 401);
this.DataTextBox.TabIndex = 103;
this.DataTextBox.Text = "[Please select a data file]";
this.DataTextBox.WordWrap = false;
//
// tabPage4
//
this.tabPage4.Controls.Add(this.DetailsPropertyGrid);
this.tabPage4.Location = new System.Drawing.Point(4, 22);
this.tabPage4.Name = "tabPage4";
this.tabPage4.Padding = new System.Windows.Forms.Padding(3);
this.tabPage4.Size = new System.Drawing.Size(556, 436);
this.tabPage4.TabIndex = 1;
this.tabPage4.Text = "Details";
this.tabPage4.UseVisualStyleBackColor = true;
//
// DetailsPropertyGrid
//
this.DetailsPropertyGrid.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.DetailsPropertyGrid.Location = new System.Drawing.Point(6, 6);
this.DetailsPropertyGrid.Name = "DetailsPropertyGrid";
this.DetailsPropertyGrid.Size = new System.Drawing.Size(544, 424);
this.DetailsPropertyGrid.TabIndex = 104;
//
// TexturesTabPage
//
this.TexturesTabPage.Controls.Add(this.splitContainer2);
this.TexturesTabPage.Location = new System.Drawing.Point(4, 22);
this.TexturesTabPage.Name = "TexturesTabPage";
this.TexturesTabPage.Size = new System.Drawing.Size(556, 436);
this.TexturesTabPage.TabIndex = 2;
this.TexturesTabPage.Text = "Textures";
this.TexturesTabPage.UseVisualStyleBackColor = true;
//
// splitContainer2
//
this.splitContainer2.Dock = System.Windows.Forms.DockStyle.Fill;
this.splitContainer2.Location = new System.Drawing.Point(0, 0);
this.splitContainer2.Name = "splitContainer2";
//
// splitContainer2.Panel1
//
this.splitContainer2.Panel1.Controls.Add(this.SelTexturesListView);
//
// splitContainer2.Panel2
//
this.splitContainer2.Panel2.Controls.Add(this.SelTextureMipLabel);
this.splitContainer2.Panel2.Controls.Add(this.label5);
this.splitContainer2.Panel2.Controls.Add(this.SelTextureDimensionsLabel);
this.splitContainer2.Panel2.Controls.Add(this.SelTextureMipTrackBar);
this.splitContainer2.Panel2.Controls.Add(this.label4);
this.splitContainer2.Panel2.Controls.Add(this.SelTextureNameTextBox);
this.splitContainer2.Panel2.Controls.Add(this.SelTexturePictureBox);
this.splitContainer2.Size = new System.Drawing.Size(556, 436);
this.splitContainer2.SplitterDistance = 177;
this.splitContainer2.TabIndex = 0;
//
// SelTexturesListView
//
this.SelTexturesListView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.SelTexturesListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.columnHeader5});
this.SelTexturesListView.FullRowSelect = true;
this.SelTexturesListView.HideSelection = false;
this.SelTexturesListView.Location = new System.Drawing.Point(3, 3);
this.SelTexturesListView.MultiSelect = false;
this.SelTexturesListView.Name = "SelTexturesListView";
this.SelTexturesListView.Size = new System.Drawing.Size(171, 430);
this.SelTexturesListView.TabIndex = 21;
this.SelTexturesListView.UseCompatibleStateImageBehavior = false;
this.SelTexturesListView.View = System.Windows.Forms.View.Details;
this.SelTexturesListView.SelectedIndexChanged += new System.EventHandler(this.SelTexturesListView_SelectedIndexChanged);
//
// columnHeader5
//
this.columnHeader5.Text = "Texture";
this.columnHeader5.Width = 146;
//
// SelTextureMipLabel
//
this.SelTextureMipLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.SelTextureMipLabel.AutoSize = true;
this.SelTextureMipLabel.Location = new System.Drawing.Point(41, 401);
this.SelTextureMipLabel.Name = "SelTextureMipLabel";
this.SelTextureMipLabel.Size = new System.Drawing.Size(13, 13);
this.SelTextureMipLabel.TabIndex = 44;
this.SelTextureMipLabel.Text = "0";
//
// label5
//
this.label5.AutoSize = true;
this.label5.Location = new System.Drawing.Point(10, 10);
this.label5.Name = "label5";
this.label5.Size = new System.Drawing.Size(38, 13);
this.label5.TabIndex = 43;
this.label5.Text = "Name:";
//
// SelTextureDimensionsLabel
//
this.SelTextureDimensionsLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.SelTextureDimensionsLabel.AutoSize = true;
this.SelTextureDimensionsLabel.Location = new System.Drawing.Point(301, 401);
this.SelTextureDimensionsLabel.Name = "SelTextureDimensionsLabel";
this.SelTextureDimensionsLabel.Size = new System.Drawing.Size(10, 13);
this.SelTextureDimensionsLabel.TabIndex = 42;
this.SelTextureDimensionsLabel.Text = "-";
//
// SelTextureMipTrackBar
//
this.SelTextureMipTrackBar.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.SelTextureMipTrackBar.AutoSize = false;
this.SelTextureMipTrackBar.BackColor = System.Drawing.SystemColors.ControlLightLight;
this.SelTextureMipTrackBar.LargeChange = 1;
this.SelTextureMipTrackBar.Location = new System.Drawing.Point(60, 395);
this.SelTextureMipTrackBar.Maximum = 0;
this.SelTextureMipTrackBar.Name = "SelTextureMipTrackBar";
this.SelTextureMipTrackBar.Size = new System.Drawing.Size(234, 31);
this.SelTextureMipTrackBar.TabIndex = 41;
this.SelTextureMipTrackBar.Scroll += new System.EventHandler(this.SelTextureMipTrackBar_Scroll);
//
// label4
//
this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.label4.AutoSize = true;
this.label4.Location = new System.Drawing.Point(10, 401);
this.label4.Name = "label4";
this.label4.Size = new System.Drawing.Size(27, 13);
this.label4.TabIndex = 40;
this.label4.Text = "Mip:";
//
// SelTextureNameTextBox
//
this.SelTextureNameTextBox.Location = new System.Drawing.Point(60, 7);
this.SelTextureNameTextBox.Name = "SelTextureNameTextBox";
this.SelTextureNameTextBox.Size = new System.Drawing.Size(192, 20);
this.SelTextureNameTextBox.TabIndex = 39;
//
// SelTexturePictureBox
//
this.SelTexturePictureBox.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.SelTexturePictureBox.BackColor = System.Drawing.Color.DarkGray;
this.SelTexturePictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.SelTexturePictureBox.Location = new System.Drawing.Point(3, 33);
this.SelTexturePictureBox.Name = "SelTexturePictureBox";
this.SelTexturePictureBox.Size = new System.Drawing.Size(369, 351);
this.SelTexturePictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.SelTexturePictureBox.TabIndex = 38;
this.SelTexturePictureBox.TabStop = false;
//
// MainStatusStrip
//
this.MainStatusStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.StatusLabel});
this.MainStatusStrip.Location = new System.Drawing.Point(0, 527);
this.MainStatusStrip.Name = "MainStatusStrip";
this.MainStatusStrip.Size = new System.Drawing.Size(855, 22);
this.MainStatusStrip.TabIndex = 50;
this.MainStatusStrip.Text = "statusStrip1";
//
// StatusLabel
//
this.StatusLabel.Name = "StatusLabel";
this.StatusLabel.Size = new System.Drawing.Size(840, 17);
this.StatusLabel.Spring = true;
this.StatusLabel.Text = "Scan the GTAV folder to begin.";
this.StatusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
//
// TestAllButton
//
this.TestAllButton.Location = new System.Drawing.Point(537, 4);
this.TestAllButton.Name = "TestAllButton";
this.TestAllButton.Size = new System.Drawing.Size(75, 23);
this.TestAllButton.TabIndex = 3;
this.TestAllButton.Text = "Test all files";
this.TestAllButton.UseVisualStyleBackColor = true;
this.TestAllButton.Click += new System.EventHandler(this.TestAllButton_Click);
//
// AbortButton
//
this.AbortButton.Location = new System.Drawing.Point(618, 4);
this.AbortButton.Name = "AbortButton";
this.AbortButton.Size = new System.Drawing.Size(75, 23);
this.AbortButton.TabIndex = 4;
this.AbortButton.Text = "Abort";
this.AbortButton.UseVisualStyleBackColor = true;
this.AbortButton.Click += new System.EventHandler(this.AbortButton_Click);
//
// SaveFileDialog
//
this.SaveFileDialog.AddExtension = false;
//
// BrowseForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(855, 549);
this.Controls.Add(this.AbortButton);
this.Controls.Add(this.TestAllButton);
this.Controls.Add(this.MainStatusStrip);
this.Controls.Add(this.splitContainer1);
this.Controls.Add(this.ScanButton);
this.Controls.Add(this.label1);
this.Controls.Add(this.FolderBrowseButton);
this.Controls.Add(this.FolderTextBox);
this.DoubleBuffered = true;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "BrowseForm";
this.Text = "RPF Browser - CodeWalker by dexyfex";
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.BrowseForm_FormClosed);
this.Load += new System.EventHandler(this.BrowseForm_Load);
this.splitContainer1.Panel1.ResumeLayout(false);
this.splitContainer1.Panel2.ResumeLayout(false);
this.splitContainer1.Panel2.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit();
this.splitContainer1.ResumeLayout(false);
this.tabControl1.ResumeLayout(false);
this.tabPage1.ResumeLayout(false);
this.tabPage1.PerformLayout();
this.tabPage2.ResumeLayout(false);
this.tabPage2.PerformLayout();
this.SelectionTabControl.ResumeLayout(false);
this.tabPage3.ResumeLayout(false);
this.tabPage3.PerformLayout();
this.tabPage4.ResumeLayout(false);
this.TexturesTabPage.ResumeLayout(false);
this.splitContainer2.Panel1.ResumeLayout(false);
this.splitContainer2.Panel2.ResumeLayout(false);
this.splitContainer2.Panel2.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).EndInit();
this.splitContainer2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.SelTextureMipTrackBar)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.SelTexturePictureBox)).EndInit();
this.MainStatusStrip.ResumeLayout(false);
this.MainStatusStrip.PerformLayout();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label label1;
private System.Windows.Forms.Button FolderBrowseButton;
private System.Windows.Forms.TextBox FolderTextBox;
private System.Windows.Forms.Button ScanButton;
private System.Windows.Forms.FolderBrowserDialog FolderBrowserDialog;
private System.Windows.Forms.SplitContainer splitContainer1;
private System.Windows.Forms.TreeView MainTreeView;
private System.Windows.Forms.StatusStrip MainStatusStrip;
private System.Windows.Forms.ToolStripStatusLabel StatusLabel;
private System.Windows.Forms.TabControl tabControl1;
private System.Windows.Forms.TabPage tabPage1;
private System.Windows.Forms.TabPage tabPage2;
private System.Windows.Forms.TabControl SelectionTabControl;
private System.Windows.Forms.TabPage tabPage3;
private System.Windows.Forms.TabPage tabPage4;
private System.Windows.Forms.RadioButton DataTextRadio;
private System.Windows.Forms.RadioButton DataHexRadio;
private System.Windows.Forms.TextBox DataTextBox;
private System.Windows.Forms.ComboBox DataHexLineCombo;
private System.Windows.Forms.Label FileInfoLabel;
private System.Windows.Forms.Button TestAllButton;
private System.Windows.Forms.Button AbortButton;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox FindTextBox;
private System.Windows.Forms.Button FindButton;
private System.Windows.Forms.Button ExportButton;
private System.Windows.Forms.SaveFileDialog SaveFileDialog;
private CodeWalker.WinForms.PropertyGridFix DetailsPropertyGrid;
private System.Windows.Forms.Button SearchAbortButton;
private System.Windows.Forms.Button SearchButton;
private System.Windows.Forms.Label label3;
private System.Windows.Forms.TextBox SearchTextBox;
private System.Windows.Forms.RadioButton SearchHexRadioButton;
private System.Windows.Forms.RadioButton SearchTextRadioButton;
private System.Windows.Forms.ListView SearchResultsListView;
private System.Windows.Forms.ColumnHeader columnHeader1;
private System.Windows.Forms.ColumnHeader columnHeader2;
private System.Windows.Forms.CheckBox SearchBothDirectionsCheckBox;
private System.Windows.Forms.CheckBox SearchCaseSensitiveCheckBox;
private System.Windows.Forms.TextBox SearchIgnoreTextBox;
private System.Windows.Forms.CheckBox SearchIgnoreCheckBox;
private System.Windows.Forms.TabPage TexturesTabPage;
private System.Windows.Forms.SplitContainer splitContainer2;
private System.Windows.Forms.Label label5;
private System.Windows.Forms.Label SelTextureDimensionsLabel;
private System.Windows.Forms.TrackBar SelTextureMipTrackBar;
private System.Windows.Forms.Label label4;
private System.Windows.Forms.TextBox SelTextureNameTextBox;
private System.Windows.Forms.PictureBox SelTexturePictureBox;
private System.Windows.Forms.ListView SelTexturesListView;
private System.Windows.Forms.ColumnHeader columnHeader5;
private System.Windows.Forms.Label SelTextureMipLabel;
private System.Windows.Forms.CheckBox ShowLargeFileContentsCheckBox;
private System.Windows.Forms.CheckBox ExportCompressCheckBox;
private System.Windows.Forms.CheckBox FlattenStructureCheckBox;
private System.Windows.Forms.Button SearchSaveResultsButton;
}
}

1288
BrowseForm.cs Normal file

File diff suppressed because it is too large Load Diff

418
BrowseForm.resx Normal file
View File

@ -0,0 +1,418 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="FolderBrowserDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="MainStatusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>182, 17</value>
</metadata>
<metadata name="SaveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>320, 17</value>
</metadata>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
6P///ysvjWVqtP///////wAAAAAAAAAAAP////D0/0hPpsDG6////////6y02d7k8////3qAx+/z/f//
/wAAAAAAAAAAAAAAAAAAAP///////////////8zT8V5ns1Rcrdzh9f///////////wAAAAAAAAAAAAAA
AAAAAP////////7+/6ix3nmBxFthtmdwu09WqbC54/v9//r8//j6//39/wAAAAAAAAAAAOjt/H6I0FJc
skpSqHF+wRMahFZhs4iT1AsNc1pgrm52v2RsuO/z/gAAAP////////L2/cLJ7rrD64+V4DY+ozU+mYmU
0X2Hy1hfss7V8urv/PP2/v///wAAAP///+Pp+d/k9////////+Pp/4uR3ysymW14xYOM0fD0/P///+Xq
+ri/6Pj6/wAAAOrv/j5DnbS75P////////////X4/+/0/ubr+/r7/////////9rh+hgZhKGo2QAAAPDz
/eLn+f////j6/2Nqttrg9////+Hn+P3+//3+/1hescLJ6/////L2/eru/AAAAAAAAAAAAP///8rR70tR
p/3+//v8/zY6jNPY7////09WqWpwu////wAAAAAAAAAAAAAAAAAAAAAAAPb4/vr7//////v8/5Wd1eHm
+P////v8//T3/wAAAAAAAAAAAAAAAP//AAD8PwAA/D8AAPwDAACAAwAAgAMAAIAHAADABwAAwAEAAMAB
AAAAAQAAAAEAAAABAAAAAQAAwAcAAOAPAAAoAAAAQAAAAIAAAAABABgAAAAAAAAwAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7//P3//P3//P3/
/f7//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/
+fv/+fv/+Pr/+fv/+vv//P3//v//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA/f7/+fr/8/b/7PL/5+3/6e/+9Pf/+vv//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA/P3/9/r/6O7/cXe1UVaet7z17fL/+Pr//f3/AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+/z/9Pj/4Oj/NzyCUlOd2dz/6O//9Pf//P3/AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8vb/2+P9X2OmREGLnqPd
4+v/8vb/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8fb/
1N35bXK1JSRtbHGz5O7/8fX/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAA+vv/8PX/3Ob/U1eaDwtXjZLT4+z/8fX/+/z/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAA+vv/8fb/2eP+MjR6AAA+c3i34Or/8fX/+/z/AAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+vv/8vb/1d/7MS91AAA1UFSS4On/8vb/+/z/AAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
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
/v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/+vz/+fv/+Pr/+Pr/+vv//f3//v//AAAAAAAAAAAAAAAA
/v//+fv/9Pf/2+L/SVGtAABsLTaZytL58fX/9/n//f7/AAAAAAAAAAAAAAAA/v7/+/z/9/n/9fj/9vn/
9fj/9vj/+vz//f7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7//f3//f3//f3//v7//v//AAAA
AAAAAAAAAAAAAAAAAAAA+/z/9vn/6e//mZ7gTVarr7bp6/H/9fj/+vv//v7/AAAAAAAAAAAAAAAAAAAA
/v7//f7/+/z/+/z/+/z//P3//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/f3/+Pr/9fj/6e7/4+n/8fb/9Pf/+Pr//f3/AAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//P3/+fv/+fv/+vv/+Pr/+vv/
/P3//v7/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/v7//f7/
/f3//P3//f7//v7//v//AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////////
///////4D/////////AH////////8Af////////wB/////////AH////////8Af////////wB///////
//AH////////8Af////////wB/////////AH////////8AfwP//////wB8Af//+Af/AHgB///wA/8AcA
H///AB/wBgAf//8AD/AGAB///wAH8AYAH///AAPwBAAf//8AA/AEAD///wAD8AQAP///AAPwBAB///+A
A/AEAP///8AD4AAA////4AcAAAH////wDgAAAf/////8AAAH//////gAAAf/////4AAAAf/////gAAAA
/f//+AAAAAAAD//AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+AAAAAAAAH/4AAAAAAAAf/gAAAAAAAB/+A
AAAAAAAP/4AAAAAAAB//wAAAAABAf/4HwAAAAYAf8APAAAADgA/gA+AAAAMAA8AD8AAABwADgAP8AAAf
AAOAA/4AAB8AA4ADAAAAAQADgAIAcA4AgAOABgBwDgBAA4AMAGAMADADwDwAYAwAOAfg+ABgBAAeH//4
AEAEAB////gAwAYAH///+ADABgAf///4AcAGAB////gBwAcAH///+APAB4A////8B+AHwH//////4A//
///////gD/////////Af//////////////8=
</value>
</data>
</root>

1
CodeWalker Explorer.cmd Normal file
View File

@ -0,0 +1 @@
start codewalker explorer

1
CodeWalker Menu.cmd Normal file
View File

@ -0,0 +1 @@
start codewalker menu

View File

@ -0,0 +1,145 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<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>{DE50D3A6-B49E-47A0-ABE6-101473A00759}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CodeWalker.Core</RootNamespace>
<AssemblyName>CodeWalker.Core</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="SharpDX, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.4.0.1\lib\net45\SharpDX.dll</HintPath>
</Reference>
<Reference Include="SharpDX.Mathematics, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\packages\SharpDX.Mathematics.4.0.1\lib\net45\SharpDX.Mathematics.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<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" />
</ItemGroup>
<ItemGroup>
<Compile Include="GameFiles\FileTypes\AwcFile.cs" />
<Compile Include="GameFiles\FileTypes\CacheDatFile.cs" />
<Compile Include="GameFiles\FileTypes\CutFile.cs" />
<Compile Include="GameFiles\FileTypes\DlcContentFile.cs" />
<Compile Include="GameFiles\FileTypes\DlcSetupFile.cs" />
<Compile Include="GameFiles\FileTypes\FxcFile.cs" />
<Compile Include="GameFiles\FileTypes\GtxdFile.cs" />
<Compile Include="GameFiles\FileTypes\Gxt2File.cs" />
<Compile Include="GameFiles\FileTypes\JPsoFile.cs" />
<Compile Include="GameFiles\FileTypes\RelFile.cs" />
<Compile Include="GameFiles\FileTypes\Stats.cs" />
<Compile Include="GameFiles\FileTypes\YbnFile.cs" />
<Compile Include="GameFiles\FileTypes\YcdFile.cs" />
<Compile Include="GameFiles\FileTypes\YddFile.cs" />
<Compile Include="GameFiles\FileTypes\YdrFile.cs" />
<Compile Include="GameFiles\FileTypes\YftFile.cs" />
<Compile Include="GameFiles\FileTypes\YmapFile.cs" />
<Compile Include="GameFiles\FileTypes\YmfFile.cs" />
<Compile Include="GameFiles\FileTypes\YmtFile.cs" />
<Compile Include="GameFiles\FileTypes\YndFile.cs" />
<Compile Include="GameFiles\FileTypes\YnvFile.cs" />
<Compile Include="GameFiles\FileTypes\YptFile.cs" />
<Compile Include="GameFiles\FileTypes\YtdFile.cs" />
<Compile Include="GameFiles\FileTypes\YtypFile.cs" />
<Compile Include="GameFiles\FileTypes\YvrFile.cs" />
<Compile Include="GameFiles\FileTypes\YwrFile.cs" />
<Compile Include="GameFiles\GameFile.cs" />
<Compile Include="GameFiles\GameFileCache.cs" />
<Compile Include="GameFiles\MetaTypes\Archetype.cs" />
<Compile Include="GameFiles\MetaTypes\Meta.cs" />
<Compile Include="GameFiles\MetaTypes\MetaBuilder.cs" />
<Compile Include="GameFiles\MetaTypes\MetaNames.cs" />
<Compile Include="GameFiles\MetaTypes\MetaTypes.cs" />
<Compile Include="GameFiles\MetaTypes\MetaXml.cs" />
<Compile Include="GameFiles\MetaTypes\Pso.cs" />
<Compile Include="GameFiles\MetaTypes\PsoTypes.cs" />
<Compile Include="GameFiles\MetaTypes\Rbf.cs" />
<Compile Include="GameFiles\MetaTypes\XmlMeta.cs" />
<Compile Include="GameFiles\Resources\Bounds.cs" />
<Compile Include="GameFiles\Resources\Clip.cs" />
<Compile Include="GameFiles\Resources\Drawable.cs" />
<Compile Include="GameFiles\Resources\Frag.cs" />
<Compile Include="GameFiles\Resources\Nav.cs" />
<Compile Include="GameFiles\Resources\Node.cs" />
<Compile Include="GameFiles\Resources\Particle.cs" />
<Compile Include="GameFiles\Resources\ResourceBaseTypes.cs" />
<Compile Include="GameFiles\Resources\ResourceBuilder.cs" />
<Compile Include="GameFiles\Resources\ResourceData.cs" />
<Compile Include="GameFiles\Resources\ResourceFile.cs" />
<Compile Include="GameFiles\Resources\Texture.cs" />
<Compile Include="GameFiles\Resources\VehicleRecord.cs" />
<Compile Include="GameFiles\Resources\VertexType.cs" />
<Compile Include="GameFiles\Resources\WaypointRecord.cs" />
<Compile Include="GameFiles\RpfFile.cs" />
<Compile Include="GameFiles\RpfManager.cs" />
<Compile Include="GameFiles\Utils\Data.cs" />
<Compile Include="GameFiles\Utils\GTACrypto.cs" />
<Compile Include="GameFiles\Utils\GTAKeys.cs" />
<Compile Include="GameFiles\Utils\Jenk.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Utils\Cache.cs" />
<Compile Include="Utils\Matrices.cs" />
<Compile Include="Utils\Quaternions.cs" />
<Compile Include="Utils\Utils.cs" />
<Compile Include="Utils\Vectors.cs" />
<Compile Include="Utils\Xml.cs" />
<Compile Include="World\AudioZones.cs" />
<Compile Include="World\Camera.cs" />
<Compile Include="World\Clouds.cs" />
<Compile Include="World\Entity.cs" />
<Compile Include="World\PopZones.cs" />
<Compile Include="World\Scenarios.cs" />
<Compile Include="World\Space.cs" />
<Compile Include="World\Timecycle.cs" />
<Compile Include="World\TimecycleMods.cs" />
<Compile Include="World\Trains.cs" />
<Compile Include="World\Water.cs" />
<Compile Include="World\Weather.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="Resources\magic.dat" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -0,0 +1,792 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TC = System.ComponentModel.TypeConverterAttribute;
using EXP = System.ComponentModel.ExpandableObjectConverter;
namespace CodeWalker.GameFiles
{
[TC(typeof(EXP))]public class AwcFile : PackedFile
{
public string Name { get; set; }
public RpfFileEntry FileEntry { get; set; }
public byte[] Data { get; set; }
public string ErrorMessage { get; set; }
public uint Magic { get; set; }
public ushort Version { get; set; }
public ushort Flags { get; set; }
public int StreamCount { get; set; }
public int InfoOffset { get; set; }
public bool MultiChannel { get; set; }
public byte[] MultiChannelData { get; set; }
public AwcStreamInfo[] StreamInfos { get; set; }
public uint[] AudioIds { get; set; }
public AwcAudio[] Audios { get; set; }
static public void Decrypt_RSXXTEA(byte[] data, uint[] key)
{
// Rockstar's modified version of XXTEA
uint[] blocks = new uint[data.Length / 4];
Buffer.BlockCopy(data, 0, blocks, 0, data.Length);
int block_count = blocks.Length;
uint a, b = blocks[0], i;
i = (uint)(0x9E3779B9 * (6 + 52 / block_count));
do
{
for (int block_index = block_count - 1; block_index >= 0; --block_index)
{
a = blocks[(block_index > 0 ? block_index : block_count) - 1];
b = blocks[block_index] -= (a >> 5 ^ b << 2) + (b >> 3 ^ a << 4) ^ (i ^ b) + (key[block_index & 3 ^ (i >> 2 & 3)] ^ a ^ 0x7B3A207F);
}
i -= 0x9E3779B9;
} while (i != 0);
Buffer.BlockCopy(blocks, 0, data, 0, data.Length);
}
public void Load(byte[] data, RpfFileEntry entry)
{
//adapted from libertyV code
//MemoryStream ms = new MemoryStream(data);
Name = entry.Name;
FileEntry = entry;
Data = data;
if ((data == null) || (data.Length < 8))
{
ErrorMessage = "Data null or too short!";
return; //nothing to do, not enough data...
}
Endianess endianess = Endianess.LittleEndian;
Magic = BitConverter.ToUInt32(data, 0);
if (Magic != 0x54414441 && Magic != 0x41444154)
{
if (data.Length % 4 == 0)
{
Decrypt_RSXXTEA(data, GTA5Keys.PC_AWC_KEY);
Magic = BitConverter.ToUInt32(data, 0);
} else
ErrorMessage = "Corrupted data!";
}
switch (Magic)
{
default:
ErrorMessage = "Unexpected Magic 0x" + Magic.ToString("X");
return;
case 0x54414441:
endianess = Endianess.LittleEndian;
break;
case 0x41444154:
endianess = Endianess.BigEndian;
break;
}
using (MemoryStream ms = new MemoryStream(data))
{
DataReader r = new DataReader(ms, endianess);
Magic = r.ReadUInt32();
Version = r.ReadUInt16();
Flags = r.ReadUInt16();
StreamCount = r.ReadInt32();
InfoOffset = r.ReadInt32();
//notes from libertyV:
// first bit - means that there are unknown word for each stream after this header
// second bit - I think that it means that not all the tags are in the start of the file, but all the tags of a stream are near the data tag
// third bit - Multi channel audio
if ((Flags >> 8) != 0xFF)
{
ErrorMessage = "Flags 0 not supported!";
return;
}
if ((Flags & 0xF8) != 0)
{
//ErrorMessage = "Flags 1 not supported!";
//return;
}
MultiChannel = ((Flags & 4) == 4);
var flag0 = ((Flags & 1) == 1);
var infoStart = 16 + (flag0 ? (StreamCount * 2) : 0);
ms.Position = infoStart;
List<AwcStreamInfo> infos = new List<AwcStreamInfo>();
Dictionary<uint, AwcStreamInfo> infoDict = new Dictionary<uint, AwcStreamInfo>();
List<uint> audioIds = new List<uint>();
List<AwcAudio> audios = new List<AwcAudio>();
for (int i = 0; i < StreamCount; i++)
{
var info = new AwcStreamInfo(r);
infos.Add(info);
infoDict[info.Id] = info;
}
for (int i = 0; i < StreamCount; i++)
{
var info = infos[i];
for (int j = 0; j < info.TagCount; j++)
{
var chunk = new AwcChunkInfo(r);
info.Chunks[chunk.Tag] = chunk;
}
}
StreamInfos = infos.ToArray();
byte hformat = 0xFA;// 250 0x6061D4FA & 0xFF; //JenkHash.GenHash("format");
byte hdata = 0x55;// 85 0x5EB5E655 & 0xFF; //JenkHash.GenHash("data");
byte hycd = 0x5C;// 92 YCD resource chunk... lip sync anims?
byte hunk = 0x36;// 54 unk chunk? small number of bytes (2+)
if (MultiChannel)
{
AwcStreamInfo stream0 = null;
if (!infoDict.TryGetValue(0, out stream0))
{
ErrorMessage = "Couldn't find MultiChannel stream0";
return;
}
AwcChunkInfo chunk72 = null;
if (!stream0.Chunks.TryGetValue(72, out chunk72))
{
ErrorMessage = "Couldn't find MultiChannel chunk72";
return;
}
ms.Position = chunk72.Offset;
AwcChannelChunkInfo chanInfo = new AwcChannelChunkInfo(r);
if (chanInfo.ChannelCount != StreamCount - 1)
{
ErrorMessage = "Channel Count did not match Stream Count";
return;
}
List<AwcChannelChunkItemInfo> chunkItems = new List<AwcChannelChunkItemInfo>();
for (int i = 0; i < chanInfo.ChannelCount; i++)
{
var itemInfo = new AwcChannelChunkItemInfo(r);
chunkItems.Add(itemInfo);
audioIds.Add(infos[i + 1].Id);
}
//AudioStreams.Add(new MultiChannelAudio(new ChunkStream(this.Stream, streamsChunks[0][Tag("data")]), channelsInfoHeader, streamsInfo, header.BigEndian));
AwcChunkInfo cdata = null;
if (!stream0.Chunks.TryGetValue(hdata, out cdata))
{
ErrorMessage = "Couldn't find Stream 0 data chunk";
return;
}
ms.Position = cdata.Offset;
var lastPos = cdata.Offset + cdata.Size;
//int chunkSize = 0x800;
uint bigChunkSize = chanInfo.ChunkSize;
var chanCount = chanInfo.ChannelCount;
MultiChannelData = r.ReadBytes(cdata.Size);
ms.Position = cdata.Offset;
//var d = data;//temporary
////this doesn't seem to work :(
//while (ms.Position < lastPos)
//{
// uint totalChunks = 0;
// var startPos = ms.Position;
// var curPos = startPos;
// //byte[] chunkdata = r.ReadBytes(chunkSize);
// //ms.Position = startPos;
// AwcChannelChunkHeader[] chanHeaders = new AwcChannelChunkHeader[chanCount];
// for (int i = 0; i < chanCount; i++)
// {
// var chanHeader = new AwcChannelChunkHeader(r);
// chanHeaders[i] = chanHeader;
// totalChunks += chanHeader.ChunkCount;
// }
// int headerSize = (int)(totalChunks * 4 + chanInfo.ChannelCount * AwcChannelChunkHeader.Size);
// headerSize += (((-headerSize) % chunkSize) + chunkSize) % chunkSize; //todo: simplify this!
// curPos += headerSize;
// AwcChannelChunk[] chanChunks = new AwcChannelChunk[chanCount];
// for (int i = 0; i < chanCount; i++)
// {
// var chanChunk = new AwcChannelChunk(r, chanHeaders[i], chunkItems[i]);
// chanChunks[i] = chanChunk;
// curPos += chanChunk.TotalDataSize;
// }
// if (curPos - startPos > chanInfo.ChunkSize)
// {
// ErrorMessage = "Chunk was bigger than the chunk size";
// break;
// }
// if ((totalChunks == 0) || ((startPos + chanInfo.ChunkSize) > lastPos))
// {
// ErrorMessage = "Unable to read chunk";
// break;
// }
// var newPos = startPos + bigChunkSize;
// if (newPos >= lastPos) break;
// ms.Position = newPos;
//}
}
else
{
for (int i = 0; i < StreamCount; i++)
{
var info = infos[i];
AwcChunkInfo cformat = null;
if (!info.Chunks.TryGetValue(hformat, out cformat))
{
ErrorMessage = "Couldn't find Stream " + i.ToString() + " format chunk";
continue;
}
AwcChunkInfo cdata = null;
if (!info.Chunks.TryGetValue(hdata, out cdata))
{
ErrorMessage = "Couldn't find Stream " + i.ToString() + " data chunk";
continue;
}
AwcChunkInfo cycd = null;
AwcAudioAnimClipDict oycd = null;
if (info.Chunks.TryGetValue(hycd, out cycd))
{
ms.Position = cycd.Offset;
oycd = new AwcAudioAnimClipDict(r, cycd);
}
AwcChunkInfo cunk = null;
AwcAudioUnk ounk = null;
if (info.Chunks.TryGetValue(hunk, out cunk))
{
ms.Position = cunk.Offset;
ounk = new AwcAudioUnk(r, cunk);
}
ms.Position = cformat.Offset;
AwcFormatChunk formatChunk = new AwcFormatChunk(r);
ms.Position = cdata.Offset;
AwcAudio audio = new AwcAudio(r, info, formatChunk, cdata);
audio.ClipDict = oycd;
audio.UnkData = ounk;
audios.Add(audio);
audioIds.Add(info.Id);
}
}
Audios = audios.ToArray();
AudioIds = audioIds.ToArray();
}
}
}
[TC(typeof(EXP))] public class AwcStreamInfo
{
public uint RawVal { get; set; }
public uint TagCount { get; set; }
public uint Id { get; set; }
public Dictionary<byte, AwcChunkInfo> Chunks { get; set; } = new Dictionary<byte, AwcChunkInfo>();
public AwcStreamInfo(DataReader r)
{
RawVal = r.ReadUInt32();
TagCount = (RawVal >> 29);
Id = (RawVal & 0x1FFFFFFF);
}
public override string ToString()
{
return Id.ToString("X") + ": " + TagCount.ToString() + " tags";
}
}
[TC(typeof(EXP))] public class AwcChunkInfo
{
public ulong RawVal { get; set; }
public byte Tag { get; set; }
public int Size { get; set; }
public int Offset { get; set; }
public AwcChunkInfo(DataReader r)
{
RawVal = r.ReadUInt64();
Tag = (byte)(RawVal >> 56);
Size = (int)((RawVal >> 28) & 0x0FFFFFFF);
Offset = (int)(RawVal & 0x0FFFFFFF);
}
public override string ToString()
{
return Tag.ToString() + ": " + Size.ToString() + ", " + Offset.ToString();
}
}
[TC(typeof(EXP))] public class AwcChannelChunkInfo
{
public uint Unk0 { get; set; }
public uint ChunkSize { get; set; }
public uint ChannelCount { get; set; }
public AwcChannelChunkInfo(DataReader r)
{
Unk0 = r.ReadUInt32();
ChunkSize = r.ReadUInt32();
ChannelCount = r.ReadUInt32();
}
public override string ToString()
{
return Unk0.ToString() + ": " + ChunkSize.ToString() + ", " + ChannelCount.ToString() + " channels";
}
}
[TC(typeof(EXP))] public class AwcChannelChunkItemInfo
{
public uint Id { get; set; }
public uint Samples { get; set; }
public ushort Unk0 { get; set; }
public ushort SamplesPerSecond { get; set; }
public byte Unk1 { get; set; }
public byte RoundSize { get; set; }
public ushort Unk2 { get; set; }
public AwcChannelChunkItemInfo(DataReader r)
{
Id = r.ReadUInt32();
Samples = r.ReadUInt32();
Unk0 = r.ReadUInt16();
SamplesPerSecond = r.ReadUInt16();
Unk1 = r.ReadByte();
RoundSize = r.ReadByte();
Unk2 = r.ReadUInt16();
}
public override string ToString()
{
return Id.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec, size: " + RoundSize.ToString();
}
}
[TC(typeof(EXP))] public class AwcFormatChunk
{
public uint Samples { get; set; }
public int LoopPoint { get; set; }
public ushort SamplesPerSecond { get; set; }
public short Headroom { get; set; }
public ushort LoopBegin { get; set; }
public ushort LoopEnd { get; set; }
public ushort PlayEnd { get; set; }
public byte PlayBegin { get; set; }
public enum CodecFormat {
PCM = 0,
ADPCM = 4
}
public CodecFormat Codec { get; set; }
public AwcFormatChunk(DataReader r)
{
Samples = r.ReadUInt32();
LoopPoint = r.ReadInt32();
SamplesPerSecond = r.ReadUInt16();
Headroom = r.ReadInt16();
LoopBegin = r.ReadUInt16();
LoopEnd = r.ReadUInt16();
PlayEnd = r.ReadUInt16();
PlayBegin = r.ReadByte();
Codec = (CodecFormat)r.ReadByte();
//Apparently sometimes this struct is longer? TODO: fix??
//r.ReadUInt16();
//r.ReadUInt16();
}
public override string ToString()
{
return Headroom.ToString() + ", " + Codec.ToString() + ": " + Samples.ToString() + " samples, " + SamplesPerSecond.ToString() + " samples/sec";
}
}
[TC(typeof(EXP))] public class AwcAudio
{
public AwcStreamInfo StreamInfo { get; set; }
public AwcFormatChunk Format { get; set; }
public AwcChunkInfo DataInfo { get; set; }
public byte[] Data { get; set; }
public AwcAudioAnimClipDict ClipDict { get; set; }
public AwcAudioUnk UnkData { get; set; }
public short Channels = 1;
public short BitsPerSample = 16;
public int SamplesPerSecond
{
get
{
return Format?.SamplesPerSecond ?? 0;
}
}
public int SampleCount
{
get
{
return (int)(Format?.Samples ?? 0);
}
}
public string Name
{
get
{
return "0x" + StreamInfo?.Id.ToString("X").PadLeft(8, '0') ?? "0";
}
}
public string Type
{
get
{
if (Format == null) return "Unknown";
string codec;
switch (Format.Codec)
{
case AwcFormatChunk.CodecFormat.PCM:
codec = "PCM";
break;
case AwcFormatChunk.CodecFormat.ADPCM:
codec = "ADPCM";
break;
default:
codec = "Unknown";
break;
}
var hz = Format.SamplesPerSecond;
return codec + ((hz > 0) ? (", " + hz.ToString() + " Hz") : "");
}
}
public float Length
{
get
{
return Format == null ? 0 : (float)Format.Samples / Format.SamplesPerSecond;
}
}
public string LengthStr
{
get
{
return TimeSpan.FromSeconds(Length).ToString("m\\:ss");
}
}
public AwcAudio(DataReader r, AwcStreamInfo s, AwcFormatChunk f, AwcChunkInfo d)
{
StreamInfo = s;
Format = f;
DataInfo = d;
Data = r.ReadBytes(d.Size);
}
public override string ToString()
{
var hash = (StreamInfo?.Id.ToString("X") ?? "0").PadLeft(8, '0');
return "0x" + hash + ": " + Format?.ToString() ?? "AwcAudio";
}
public byte[] DecodeADPCM(byte[] data, int sampleCount)
{
byte[] dataPCM = new byte[data.Length * 4];
int predictor = 0, step_index = 0, step = 0;
int readingOffset = 0, writingOffset = 0, bytesInBlock = 0;
int[] ima_index_table = {
-1, -1, -1, -1, 2, 4, 6, 8,
-1, -1, -1, -1, 2, 4, 6, 8
};
short[] ima_step_table = {
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
int clip(int value, int min, int max)
{
if (value < min)
return min;
if (value > max)
return max;
return value;
}
void parseNibble(byte nibble)
{
step_index = clip(step_index + ima_index_table[nibble], 0, 88);
int diff = step >> 3;
if ((nibble & 4) > 0) diff += step;
if ((nibble & 2) > 0) diff += step >> 1;
if ((nibble & 1) > 0) diff += step >> 2;
if ((nibble & 8) > 0) predictor -= diff;
else predictor += diff;
step = ima_step_table[step_index];
int samplePCM = clip(predictor, -32768, 32767);
dataPCM[writingOffset] = (byte)(samplePCM & 0xFF);
dataPCM[writingOffset + 1] = (byte)((samplePCM >> 8) & 0xFF);
writingOffset += 2;
}
while ((readingOffset < data.Length) && (sampleCount > 0))
{
if (bytesInBlock == 0)
{
step_index = clip(data[readingOffset], 0, 88);
predictor = BitConverter.ToInt16(data, readingOffset + 2);
step = ima_step_table[step_index];
bytesInBlock = 2044;
readingOffset += 4;
}
else
{
parseNibble((byte)(data[readingOffset] & 0x0F));
parseNibble((byte)((data[readingOffset] >> 4) & 0x0F));
bytesInBlock--;
sampleCount -= 2;
readingOffset++;
}
}
return dataPCM;
}
public Stream GetWavStream()
{
byte[] dataPCM = null;
int bitsPerSample = BitsPerSample;
switch (Format.Codec)
{
case AwcFormatChunk.CodecFormat.PCM:
dataPCM = Data;
break;
case AwcFormatChunk.CodecFormat.ADPCM:
dataPCM = new byte[Data.Length];
Buffer.BlockCopy(Data, 0, dataPCM, 0, Data.Length);
AwcFile.Decrypt_RSXXTEA(dataPCM, GTA5Keys.PC_AWC_KEY);
dataPCM = DecodeADPCM(dataPCM, SampleCount);
bitsPerSample = 16;
break;
}
int byteRate = SamplesPerSecond * Channels * bitsPerSample / 8;
short blockAlign = (short)(Channels * bitsPerSample / 8);
MemoryStream stream = new MemoryStream();
BinaryWriter w = new BinaryWriter(stream);
int wavLength = 12 + 24 + 8 + Data.Length;
// RIFF chunk
w.Write("RIFF".ToCharArray());
w.Write((int)(wavLength - 8));
w.Write("WAVE".ToCharArray());
// fmt sub-chunk
w.Write("fmt ".ToCharArray());
w.Write((int)16); // fmt size
w.Write((short)1); // 1 = WAVE_FORMAT_PCM
w.Write((short)Channels);
w.Write((int)SamplesPerSecond);
w.Write((int)byteRate);
w.Write((short)blockAlign);
w.Write((short)bitsPerSample);
// data sub-chunk
w.Write("data".ToCharArray());
w.Write((int)dataPCM.Length);
w.Write(dataPCM);
w.Flush();
stream.Position = 0;
return stream;
}
}
[TC(typeof(EXP))] public class AwcAudioAnimClipDict
{
public byte[] Data { get; set; }
public ClipDictionary ClipDict { get; set; }
public AwcAudioAnimClipDict(DataReader r, AwcChunkInfo info)
{
Data = r.ReadBytes(info.Size);
if ((Data == null) || (Data.Length < 16)) return;
var data = Data;
RpfResourceFileEntry resentry = new RpfResourceFileEntry();
uint rsc7 = BitConverter.ToUInt32(data, 0);
int version = BitConverter.ToInt32(data, 4);
resentry.SystemFlags = BitConverter.ToUInt32(data, 8);
resentry.GraphicsFlags = BitConverter.ToUInt32(data, 12);
if (rsc7 != 0x37435352)
{ } //testing..
if (version != 46) //46 is Clip Dictionary...
{ }
int newlen = data.Length - 16; //trim the header from the data passed to the next step.
int arrlen = Math.Max(newlen, resentry.SystemSize + resentry.GraphicsSize);//expand it as necessary for the reader.
byte[] newdata = new byte[arrlen];
Buffer.BlockCopy(data, 16, newdata, 0, newlen);
data = newdata;
ResourceDataReader rd = new ResourceDataReader(resentry, data);
ClipDict = rd.ReadBlock<ClipDictionary>();
}
public override string ToString()
{
return (ClipDict?.ClipsMapEntries ?? 0).ToString() + " entries";
}
}
[TC(typeof(EXP))] public class AwcAudioUnk
{
public byte[] Data { get; set; }
public AwcAudioUnk(DataReader r, AwcChunkInfo info)
{
Data = r.ReadBytes(info.Size);
}
public override string ToString()
{
if (Data == null) return "";
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Data.Length; i++)
{
if (sb.Length > 0) sb.Append(' ');
sb.Append(Data[i].ToString());
}
return sb.ToString();
}
}
[TC(typeof(EXP))] public class AwcChannelChunkHeader
{
public static uint Size = 16; //24 for ps3...
public uint StartChunk { get; set; }
public uint ChunkCount { get; set; }
public uint SamplesToSkip { get; set; } //mostly 0
public uint SamplesPerChunk { get; set; }
public uint DataSize { get; set; }
public AwcChannelChunkHeader(DataReader r)
{
StartChunk = r.ReadUInt32();
ChunkCount = r.ReadUInt32();
SamplesToSkip = r.ReadUInt32();
SamplesPerChunk = r.ReadUInt32();
DataSize = ChunkCount * 0x800;
//for ps3, two extra ints:
//uint unk0 = r.ReadUint32();
//DataSize = r.ReadUint32();
}
}
[TC(typeof(EXP))] public class AwcChannelChunk
{
public AwcChannelChunkHeader Header { get; set; }
public AwcChannelChunkItemInfo Info { get; set; }
public byte[] Data { get; set; }
public uint TotalDataSize { get; set; }
public AwcChannelChunk(DataReader r, AwcChannelChunkHeader h, AwcChannelChunkItemInfo i)
{
Header = h;
Info = i;
TotalDataSize = h.DataSize;
var rs = i?.RoundSize ?? 0;
int ds = (int)h.DataSize;
if (rs != 0)
{
TotalDataSize = (uint)(TotalDataSize + (((-ds) % rs) + rs) % rs);
}
}
}
}

View File

@ -0,0 +1,700 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class CacheDatFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public string Version { get; set; }
public CacheFileDate[] FileDates { get; set; }
public Dictionary<uint, MapDataStoreNode> MapNodeDict { get; set; }
public MapDataStoreNode[] RootMapNodes { get; set; }
//public Dictionary<MetaHash, CInteriorProxy> InteriorProxyDict { get; set; }
public Dictionary<MetaHash, BoundsStoreItem> BoundsStoreDict { get; set; }
public MapDataStoreNode[] AllMapNodes { get; set; }
public CInteriorProxy[] AllCInteriorProxies { get; set; }
public BoundsStoreItem[] AllBoundsStoreItems { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
FileEntry = entry;
MemoryStream ms = new MemoryStream(data);
BinaryReader br = new BinaryReader(ms);
StringBuilder sb = new StringBuilder();
for (int i = 0; (i < 100) && (i < data.Length); i++)
{
//read version string.
byte b = data[i];
if (b == 0) break;
sb.Append((char)b);
}
Version = sb.ToString().Replace("[VERSION]", "").Replace("\r", "").Replace("\n", "");
sb.Clear();
int lastn = 0;
int lspos = 0;
uint structcount = 0;
uint modlen;
bool indates = false;
List<string> lines = new List<string>();
var dates = new List<CacheFileDate>();
var allMapNodes = new List<MapDataStoreNode>();
var allCInteriorProxies = new List<CInteriorProxy>();
var allBoundsStoreItems = new List<BoundsStoreItem>();
for (int i = 100; i < data.Length; i++)
{
byte b = data[i];
if (b == 0)
break;
if (b == 0xA)
{
lastn = i;
string line = sb.ToString();
lines.Add(line);
switch (line)
{
case "<fileDates>":
indates = true;
break;
case "</fileDates>":
indates = false;
break;
case "<module>":
break;
case "</module>":
break;
case "fwMapDataStore":
ms.Position = i + 1;
modlen = br.ReadUInt32();
structcount = modlen / 64;
lspos = i + (int)modlen + 5;
while (ms.Position<lspos)
{
allMapNodes.Add(new MapDataStoreNode(br));
}
//if (allMapNodes.Count != structcount)
//{ }//test fail due to variable length struct
i += (int)(modlen + 4);
break;
case "CInteriorProxy":
ms.Position = i + 1;
modlen = br.ReadUInt32();
structcount = modlen / 104;
lspos = i + (int)modlen + 5;
while (ms.Position < lspos)
{
allCInteriorProxies.Add(new CInteriorProxy(br));
}
if (allCInteriorProxies.Count != structcount)
{ }//all pass here
i += (int)(modlen + 4);
break;
case "BoundsStore":
ms.Position = i + 1;
modlen = br.ReadUInt32();
structcount = modlen / 32;
lspos = i + (int)modlen + 5;
while (ms.Position < lspos)
{
allBoundsStoreItems.Add(new BoundsStoreItem(br));
}
if (allBoundsStoreItems.Count != structcount)
{ }//all pass here
i += (int)(modlen + 4);
break;
default:
if (!indates)
{ } //just testing
else
{
dates.Add(new CacheFileDate(line));//eg: 2740459947 130680580712018938 8944
}
break;
}
sb.Clear();
}
else
{
sb.Append((char)b);
}
}
FileDates = dates.ToArray();
AllMapNodes = allMapNodes.ToArray();
AllCInteriorProxies = allCInteriorProxies.ToArray();
AllBoundsStoreItems = allBoundsStoreItems.ToArray();
MapNodeDict = new Dictionary<uint, MapDataStoreNode>();
var rootMapNodes = new List<MapDataStoreNode>();
foreach (var mapnode in AllMapNodes)
{
MapNodeDict[mapnode.Name] = mapnode;
if (mapnode.ParentName == 0)
{
rootMapNodes.Add(mapnode);
}
if (mapnode.UnkExtra != null)
{ }//notsure what to do with this
}
foreach (var mapnode in AllMapNodes)
{
MapDataStoreNode pnode;
if (MapNodeDict.TryGetValue(mapnode.ParentName, out pnode))
{
pnode.AddChildToList(mapnode);
}
else if ((mapnode.ParentName != 0))
{ }
}
foreach (var mapnode in AllMapNodes)
{
mapnode.ChildrenListToArray();
}
RootMapNodes = rootMapNodes.ToArray();
BoundsStoreDict = new Dictionary<MetaHash, BoundsStoreItem>();
foreach (BoundsStoreItem item in AllBoundsStoreItems)
{
BoundsStoreItem mbsi = null;
if (BoundsStoreDict.TryGetValue(item.Name, out mbsi))
{ }
BoundsStoreDict[item.Name] = item;
}
//InteriorProxyDict = new Dictionary<MetaHash, CInteriorProxy>();
foreach (CInteriorProxy prx in AllCInteriorProxies)
{
//CInteriorProxy mprx = null;
//if (InteriorProxyDict.TryGetValue(prx.Name, out mprx))
//{ }
//InteriorProxyDict[prx.Name] = prx;//can't do this! multiples with same name different pos
MapDataStoreNode mnode = null;
if (MapNodeDict.TryGetValue(prx.Parent, out mnode))
{
mnode.AddInteriorToList(prx);
}
else
{ }
}
foreach (var mapnode in AllMapNodes)
{
mapnode.InteriorProxyListToArray();
}
br.Dispose();
ms.Dispose();
}
public void LoadXml(string xml)
{
}
public string GetXml()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(MetaXmlBase.XmlHeader);
sb.AppendLine(string.Format("<CacheDatFile version=\"{0}\">", Version));
sb.AppendLine(" <fileDates>");
if (FileDates != null)
{
foreach (var date in FileDates)
{
sb.AppendLine(string.Format(" <fileDate>{0}</fileDate>", date.ToCacheFileString()));
}
}
sb.AppendLine(" </fileDates>");
sb.AppendLine(" <module type=\"fwMapDataStore\">");
if (AllMapNodes != null)
{
foreach (var mapnode in AllMapNodes)
{
sb.AppendLine(" <Item>");
sb.AppendLine(string.Format(" <name>{0}</name>", mapnode.Name.ToCleanString()));
sb.AppendLine(string.Format(" <parent>{0}</parent>", mapnode.ParentName.ToCleanString()));
sb.AppendLine(string.Format(" <contentFlags value=\"{0}\" />", mapnode.ContentFlags.ToString()));
sb.AppendLine(string.Format(" <streamingExtentsMin {0} />", FloatUtil.GetVector3XmlString(mapnode.streamingExtentsMin)));
sb.AppendLine(string.Format(" <streamingExtentsMax {0} />", FloatUtil.GetVector3XmlString(mapnode.streamingExtentsMax)));
sb.AppendLine(string.Format(" <entitiesExtentsMin {0} />", FloatUtil.GetVector3XmlString(mapnode.entitiesExtentsMin)));
sb.AppendLine(string.Format(" <entitiesExtentsMax {0} />", FloatUtil.GetVector3XmlString(mapnode.entitiesExtentsMax)));
sb.AppendLine(string.Format(" <flags unk1=\"{0}\" unk2=\"{1}\" unk3=\"{2}\" />", mapnode.Unk1, mapnode.Unk2, mapnode.Unk3));
sb.AppendLine(" </Item>");
}
}
sb.AppendLine(" </module>");
sb.AppendLine(" <module type=\"CInteriorProxy\">");
if (AllCInteriorProxies != null)
{
foreach (var intprox in AllCInteriorProxies)
{
sb.AppendLine(" <Item>");
sb.AppendLine(string.Format(" <name>{0}</name>", intprox.Name.ToCleanString()));
sb.AppendLine(string.Format(" <parent>{0}</parent>", intprox.Parent.ToCleanString()));
sb.AppendLine(string.Format(" <position {0} />", FloatUtil.GetVector3XmlString(intprox.Position)));
sb.AppendLine(string.Format(" <rotation {0} />", FloatUtil.GetQuaternionXmlString(intprox.Orientation)));
sb.AppendLine(string.Format(" <aabbMin {0} />", FloatUtil.GetVector3XmlString(intprox.BBMin)));
sb.AppendLine(string.Format(" <aabbMax {0} />", FloatUtil.GetVector3XmlString(intprox.BBMax)));
sb.AppendLine(string.Format(" <unknowns1 unk01=\"{0}\" unk03=\"{1}\" />", intprox.Unk01, intprox.Unk03));
sb.AppendLine(string.Format(" <unknowns2 unk11=\"{0}\" unk12=\"{1}\" unk13=\"{1}\" unk14=\"{1}\" />", intprox.Unk11, intprox.Unk12, intprox.Unk13, intprox.Unk14));
sb.AppendLine(string.Format(" <unknowns3 unk15=\"{0}\" unk16=\"{1}\" unk17=\"{1}\" unk18=\"{1}\" />", intprox.Unk15, intprox.Unk16, intprox.Unk17, intprox.Unk18));
sb.AppendLine(" </Item>");
}
}
sb.AppendLine(" </module>");
sb.AppendLine(" <module type=\"BoundsStore\">");
if (AllBoundsStoreItems != null)
{
foreach (var bndstore in AllBoundsStoreItems)
{
sb.AppendLine(" <Item>");
sb.AppendLine(string.Format(" <name>{0}</name>", bndstore.Name.ToCleanString()));
sb.AppendLine(string.Format(" <aabbMin {0} />", FloatUtil.GetVector3XmlString(bndstore.Min)));
sb.AppendLine(string.Format(" <aabbMax {0} />", FloatUtil.GetVector3XmlString(bndstore.Max)));
sb.AppendLine(string.Format(" <layer value=\"{0}\" />", bndstore.Layer));
sb.AppendLine(" </Item>");
}
}
sb.AppendLine(" </module>");
sb.AppendLine("</CacheDatFile>");
return sb.ToString();
}
public override string ToString()
{
if (FileEntry != null)
{
return FileEntry.ToString();
}
return base.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class CacheFileDate
{
public MetaHash FileName { get; set; } //"resource_surrogate:/%s.rpf"
public DateTime TimeStamp { get; set; }
public uint FileID { get; set; }
public CacheFileDate(string line)
{
string[] parts = line.Split(' ');
if (parts.Length == 3)
{
FileName = new MetaHash(uint.Parse(parts[0]));
TimeStamp = DateTime.FromFileTimeUtc(long.Parse(parts[1]));
FileID = uint.Parse(parts[2]);
}
else
{ } //testing
}
public string ToCacheFileString()
{
return FileName.Hash.ToString() + " " + TimeStamp.ToFileTimeUtc().ToString() + " " + FileID.ToString();
}
public override string ToString()
{
return FileName.ToString() + ", " + TimeStamp.ToString() + ", " + FileID.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class BoundsStoreItem
{
public MetaHash Name { get; set; }
public Vector3 Min { get; set; }
public Vector3 Max { get; set; }
public uint Layer { get; set; }
public BoundsStoreItem(Bounds b)
{
Name = 0;
Min = b.BoundingBoxMin;
Max = b.BoundingBoxMax;
Layer = 0;
}
public BoundsStoreItem(BinaryReader br)
{
Name = new MetaHash(br.ReadUInt32());
Min = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Max = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Layer = br.ReadUInt32();
}
public override string ToString()
{
return Name.ToString() + ", " +
Min.ToString() + ", " +
Max.ToString() + ", " +
Layer.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class CInteriorProxy
{
public uint Unk01 { get; set; }
public uint Unk02 { get; set; }
public uint Unk03 { get; set; }
public MetaHash Name { get; set; }
public MetaHash Parent { get; set; }
public Vector3 Position { get; set; }
public Quaternion Orientation { get; set; }
public Vector3 BBMin { get; set; }
public Vector3 BBMax { get; set; }
public float Unk11 { get; set; }
public uint Unk12 { get; set; }
public float Unk13 { get; set; }
public uint Unk14 { get; set; }
public float Unk15 { get; set; }
public uint Unk16 { get; set; }
public uint Unk17 { get; set; }
public uint Unk18 { get; set; }
public CInteriorProxy(BinaryReader br)
{
Unk01 = br.ReadUInt32();
Unk02 = br.ReadUInt32();
Unk03 = br.ReadUInt32();
Name = new MetaHash(br.ReadUInt32());
Parent = new MetaHash(br.ReadUInt32());
Position = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Orientation = new Quaternion(br.ReadSingle(), br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
BBMin = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
BBMax = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Unk11 = br.ReadSingle();
Unk12 = br.ReadUInt32();
Unk13 = br.ReadSingle();
Unk14 = br.ReadUInt32();
Unk15 = br.ReadSingle();
Unk16 = br.ReadUInt32();
Unk17 = br.ReadUInt32();//could be float
Unk18 = br.ReadUInt32();
switch (Unk01)
{
case 0: //v_cashdepot
case 19: //dt1_02_carpark
case 20: //dt1_03_carpark
case 21: //dt1_05_carpark
case 4: //dt1_rd1_tun
case 14: //id1_11_tunnel1_int
case 24: //v_firedept
case 3: //id2_21_a_tun1
case 22: //po1_08_warehouseint1
case 11: //sc1_rd_inttun1
case 10: //sc1_rd_inttun2b_end
case 18: //bt1_04_carpark
case 16: //v_hanger
case 1: //ap1_03_lisapark_subway
case 13: //kt1_03_carpark_int
case 5: //sm20_tun1
case 2: //vbca_tunnel1
case 15: //cs1_12_tunnel01_int
case 6: //cs1_14brailway1
case 9: //cs2_roadsb_tunnel_01
case 7: //cs3_03railtunnel_int1
case 8: //cs4_rwayb_tunnelint
case 12: //ch1_roadsdint_tun1
case 100: //hei_int_mph_carrierhang3
case 47: //xm_x17dlc_int_base_ent
break;
default:
break;
}
if (Unk02 != 0)
{ }
switch (Unk03)
{
case 6: //v_cashdepot
case 2: //dt1_02_carpark
case 8: //v_fib01
case 4: //v_fib03
case 0: //v_fib04
case 7: //v_clotheslo
case 1: //v_gun
case 3: //v_genbank
case 11: //v_hospital
case 5: //v_shop_247
case 32: //v_abattoir
case 13: //v_franklins
case 15: //v_michael
case 18: //v_faceoffice
case 29: //v_recycle
case 9: //v_stadium
case 54: //v_farmhouse
case 12: //v_ranch
case 26: //hei_gta_milo_bar
case 17: //hei_gta_milo_bedrm
case 14: //hei_gta_milo_bridge
case 48: //apa_mpapa_yacht
break;
default:
break;
}
if ((Unk12 == 0) || (Unk12 > 0xFFFFFF))
{ }
switch (Unk14)
{
case 1:
case 0:
case 580:
case 355: //sm_smugdlc_int_01
case 579: //xm_x17dlc_int_01
break;
default:
break;
}
switch (Unk16)
{
case 1:
case 32758: //0x7FF6
break;
default:
break;
}
switch (Unk17) //could be a float..!
{
case 9:
break;
case 0x415CBC04: //13.7959f
case 0x7B81AC94:
case 0x40FE3224: //7.94362f v_gun
case 0x41515774: //13.0839f v_gun
case 0x414E7B34: //12.9051f bkr_biker_dlc_int_03
case 0x41389C14: //11.5381f imp_impexp_int_01
case 0x4177B664: //15.482f gr_grdlc_int_01
case 0xCE0404F4: // sm_smugdlc_int_01
break;
default:
//string str = JenkIndex.GetString(Unk17);
break;
}
switch(Unk18)
{
case 0:
case 1:
case 32758: //0x7FF6
break;
default:
break;
}
}
public override string ToString()
{
return Unk01.ToString() + ", " +
Unk02.ToString() + ", " +
Unk03.ToString() + ", " +
Name.ToString() + ", " +
Parent.ToString() + ", " +
Position.ToString() + ", " +
Orientation.ToString() + ", " +
BBMin.ToString() + ", " +
BBMax.ToString() + ", " +
Unk11.ToString() + ", " +
Unk12.ToString() + ", " +
Unk13.ToString() + ", " +
Unk14.ToString() + ", " +
Unk15.ToString() + ", " +
Unk16.ToString() + ", " +
Unk17.ToString() + ", " +
Unk18.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class MapDataStoreNode
{
public MetaHash Name { get; set; }
public MetaHash ParentName { get; set; }
public uint ContentFlags { get; set; }
public Vector3 streamingExtentsMin { get; set; }
public Vector3 streamingExtentsMax { get; set; }
public Vector3 entitiesExtentsMin { get; set; }
public Vector3 entitiesExtentsMax { get; set; }
public byte Unk1 { get; set; }
public byte Unk2 { get; set; }
public byte Unk3 { get; set; }
public byte Unk4 { get; set; }
public MapDataStoreNodeExtra UnkExtra { get; set; }
public MapDataStoreNode[] Children { get; set; }
private List<MapDataStoreNode> ChildrenList; //used when building the array
public CInteriorProxy[] InteriorProxies { get; set; }
private List<CInteriorProxy> InteriorProxyList;
public MapDataStoreNode(YmapFile ymap)
{
Name = ymap._CMapData.name;
ParentName = ymap._CMapData.parent;
ContentFlags = ymap._CMapData.contentFlags;
streamingExtentsMin = ymap._CMapData.streamingExtentsMin;
streamingExtentsMax = ymap._CMapData.streamingExtentsMax;
entitiesExtentsMin = ymap._CMapData.entitiesExtentsMin;
entitiesExtentsMax = ymap._CMapData.entitiesExtentsMax;
}
public MapDataStoreNode(BinaryReader br)
{
Name = new MetaHash(br.ReadUInt32());
ParentName = new MetaHash(br.ReadUInt32());
ContentFlags = br.ReadUInt32();
streamingExtentsMin = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
streamingExtentsMax = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
entitiesExtentsMin = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
entitiesExtentsMax = new Vector3(br.ReadSingle(), br.ReadSingle(), br.ReadSingle());
Unk1 = br.ReadByte(); //HD flag? (critical, long, strm)
Unk2 = br.ReadByte(); //lod flag? - primary map files
Unk3 = br.ReadByte(); //slod flag?
Unk4 = br.ReadByte();
if (Unk1 != 0)
{ }
if (Unk2 != 0)
{ }
if (Unk3 != 0)
{ }
if (Unk4 != 0)
{ } //no hits here now..
if (Unk4 == 0xFE)
{
//this seems to never be hit anymore...
UnkExtra = new MapDataStoreNodeExtra(br);
}
}
public void AddChildToList(MapDataStoreNode child)
{
if (ChildrenList == null)
{
ChildrenList = new List<MapDataStoreNode>();
}
ChildrenList.Add(child);
}
public void ChildrenListToArray()
{
if (ChildrenList != null)
{
Children = ChildrenList.ToArray();
ChildrenList = null; //plz get this GC
}
}
public void AddInteriorToList(CInteriorProxy iprx)
{
if (InteriorProxyList == null)
{
InteriorProxyList = new List<CInteriorProxy>();
}
InteriorProxyList.Add(iprx);
}
public void InteriorProxyListToArray()
{
if (InteriorProxyList != null)
{
InteriorProxies = InteriorProxyList.ToArray();
InteriorProxyList = null; //plz get this GC
}
}
public override string ToString()
{
return Name.ToString() + ", " +
ParentName.ToString() + ", " +
ContentFlags.ToString() + ", " +
streamingExtentsMin.ToString() + ", " +
streamingExtentsMax.ToString() + ", " +
entitiesExtentsMin.ToString() + ", " +
entitiesExtentsMax.ToString();// + ", " +
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class MapDataStoreNodeExtra
{
public uint Unk01; //0
public byte[] Unk02; //1 - 16 (60 bytes)
public uint Unk03;//16
public uint Unk04;
public uint Unk05;
public uint Unk06;
public uint Unk07;
public uint Unk08;
public uint Unk09;
public uint Unk10;
public string Unk02str
{
get
{
StringBuilder sb = new StringBuilder();
if (Unk02 != null)
{
for (int i = 0; i < Unk02.Length; i++)
{
if (Unk02[i] == 0) break;
sb.Append((char)Unk02[i]);
}
}
return sb.ToString();
}
}
public MapDataStoreNodeExtra(BinaryReader br)
{
Unk01 = br.ReadUInt32();
Unk02 = new byte[60];
for (int i = 0; i < 60; i++)
{
Unk02[i] = br.ReadByte();
}
Unk03 = br.ReadUInt32();
Unk04 = br.ReadUInt32();
Unk05 = br.ReadUInt32();
Unk06 = br.ReadUInt32();
Unk07 = br.ReadUInt32();
Unk08 = br.ReadUInt32();
Unk09 = br.ReadUInt32();
Unk10 = br.ReadUInt32();
}
public override string ToString()
{
return Unk01.ToString() + ", " + Unk02str;
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class CutFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public PsoFile Pso { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
//MemoryStream ms = new MemoryStream(data);
FileEntry = entry;
MemoryStream ms = new MemoryStream(data);
if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
var root = PsoTypes.GetRootEntry(Pso);
if (root != null)
{
}
return;
}
else
{
}
}
}
}

View File

@ -0,0 +1,431 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.GameFiles
{
public class DlcContentFile
{
public List<DlcContentDataFile> dataFiles { get; set; } = new List<DlcContentDataFile>();
public List<DlcContentChangeSet> contentChangeSets { get; set; } = new List<DlcContentChangeSet>();
public RpfFile DlcFile { get; set; } //used by GameFileCache
public Dictionary<string, DlcExtraFolderMountFile> ExtraMounts { get; set; } = new Dictionary<string, DlcExtraFolderMountFile>();
public Dictionary<string, DlcContentDataFile> RpfDataFiles { get; set; } = new Dictionary<string, DlcContentDataFile>();
public DlcExtraTitleUpdateFile ExtraTitleUpdates { get; set; }
public void Load(XmlDocument doc)
{
var root = doc.DocumentElement;
dataFiles.Clear();
contentChangeSets.Clear();
foreach (XmlNode node in root.ChildNodes)
{
switch (node.Name)
{
case "disabledFiles":
foreach (XmlNode disabledFile in node.ChildNodes)
{ } //nothing to see here..
break;
case "includedXmlFiles":
foreach (XmlNode includedXmlFile in node.ChildNodes)
{ } //nothing to see here..
break;
case "includedDataFiles":
foreach (XmlNode includedDataFile in node.ChildNodes)
{ } //nothing to see here..
break;
case "dataFiles":
foreach (XmlNode dataFile in node.ChildNodes)
{
if (dataFile.NodeType == XmlNodeType.Element)
{
dataFiles.Add(new DlcContentDataFile(dataFile));
}
}
break;
case "contentChangeSets":
foreach (XmlNode contentChangeSet in node.ChildNodes)
{
if (contentChangeSet.NodeType == XmlNodeType.Element)
{
contentChangeSets.Add(new DlcContentChangeSet(contentChangeSet));
}
}
break;
case "patchFiles":
foreach (XmlNode patchFile in node.ChildNodes)
{ } //nothing to see here..
break;
default:
break;
}
}
}
public void LoadDicts(DlcSetupFile setupfile, RpfManager rpfman, GameFileCache gfc)
{
ExtraMounts.Clear();
RpfDataFiles.Clear();
foreach (var datafile in dataFiles)
{
string dfn = GameFileCache.GetDlcPlatformPath(datafile.filename).ToLowerInvariant();
if (datafile.fileType == "EXTRA_FOLDER_MOUNT_DATA")
{
string efmdxmlpath = datafile.filename.Replace(setupfile.deviceName + ":", DlcFile.Path).Replace('/', '\\');
efmdxmlpath = gfc.GetDlcPatchedPath(efmdxmlpath);
XmlDocument efmdxml = rpfman.GetFileXml(efmdxmlpath);
DlcExtraFolderMountFile efmf = new DlcExtraFolderMountFile();
efmf.Load(efmdxml);
ExtraMounts[dfn] = efmf;
}
if (datafile.fileType == "EXTRA_TITLE_UPDATE_DATA")
{
string etudxmlpath = datafile.filename.Replace(setupfile.deviceName + ":", DlcFile.Path).Replace('/', '\\');
etudxmlpath = gfc.GetDlcPatchedPath(etudxmlpath);
XmlDocument etudxml = rpfman.GetFileXml(etudxmlpath);
DlcExtraTitleUpdateFile etuf = new DlcExtraTitleUpdateFile();
etuf.Load(etudxml);
ExtraTitleUpdates = etuf;
}
if (datafile.fileType == "RPF_FILE")
{
RpfDataFiles[dfn] = datafile;
}
}
}
public override string ToString()
{
return dataFiles.Count.ToString() + " dataFiles, " + contentChangeSets.Count.ToString() + " contentChangeSets";
}
}
public class DlcContentDataFile
{
public string filename { get; set; }
public string fileType { get; set; }
public string contents { get; set; }
public string installPartition { get; set; }
public bool overlay { get; set; }
public bool disabled { get; set; }
public bool persistent { get; set; }
public bool loadCompletely { get; set; }
public bool locked { get; set; }
public DlcContentDataFile(XmlNode node)
{
Load(node);
}
public void Load(XmlNode node)
{
foreach (XmlNode child in node.ChildNodes)
{
switch (child.Name)
{
case "filename":
filename = child.InnerText;
break;
case "fileType":
fileType = child.InnerText;
break;
case "contents":
contents = child.InnerText;
break;
case "installPartition":
installPartition = child.InnerText;
break;
case "overlay":
overlay = Xml.GetBoolAttribute(child, "value");
break;
case "disabled":
disabled = Xml.GetBoolAttribute(child, "value");
break;
case "persistent":
persistent = Xml.GetBoolAttribute(child, "value");
break;
case "loadCompletely":
loadCompletely = Xml.GetBoolAttribute(child, "value");
break;
case "locked":
locked = Xml.GetBoolAttribute(child, "value");
break;
default:
break;
}
}
}
public override string ToString()
{
return filename + ": " + fileType + ": " + contents + ": " + installPartition +
(overlay ? ", overlay" : "") +
(disabled ? ", disabled" : "") +
(persistent ? ", persistent" : "") +
(loadCompletely ? ", loadCompletely" : "") +
(locked ? ", locked" : "");
}
}
public class DlcContentChangeSet
{
public string changeSetName { get; set; }
public List<string> filesToInvalidate { get; set; }
public List<string> filesToDisable { get; set; }
public List<string> filesToEnable { get; set; }
public List<string> txdToLoad { get; set; }
public List<string> txdToUnload { get; set; }
public List<string> residentResources { get; set; }
public List<string> unregisterResources { get; set; }
public List<DlcContentChangeSet> mapChangeSetData { get; set; }
public string associatedMap { get; set; }
public bool requiresLoadingScreen { get; set; }
public string loadingScreenContext { get; set; }
public bool useCacheLoader { get; set; }
public DlcContentChangeSetExecutionConditions executionConditions { get; set; }
public DlcContentChangeSet(XmlNode node)
{
Load(node);
}
public void Load(XmlNode node)
{
foreach (XmlNode child in node.ChildNodes)
{
switch (child.Name)
{
case "changeSetName":
changeSetName = child.InnerText;
break;
case "filesToInvalidate":
filesToInvalidate = GetChildStringArray(child);
if (filesToInvalidate != null)
{ }
break;
case "filesToDisable":
filesToDisable = GetChildStringArray(child);
if (filesToDisable != null)
{ }
break;
case "filesToEnable":
filesToEnable = GetChildStringArray(child);
if (filesToEnable != null)
{ }
break;
case "txdToLoad":
txdToLoad = GetChildStringArray(child);
if (txdToLoad != null)
{ }
break;
case "txdToUnload":
txdToUnload = GetChildStringArray(child);
if (txdToUnload != null)
{ }
break;
case "residentResources":
residentResources = GetChildStringArray(child);
if (residentResources != null)
{ }
break;
case "unregisterResources":
unregisterResources = GetChildStringArray(child);
if (unregisterResources != null)
{ }
break;
case "mapChangeSetData":
mapChangeSetData = new List<DlcContentChangeSet>();
foreach (XmlNode mapChangeSetDataItem in child.ChildNodes)
{
mapChangeSetData.Add(new DlcContentChangeSet(mapChangeSetDataItem));
}
break;
case "associatedMap":
associatedMap = child.InnerText;
break;
case "requiresLoadingScreen":
requiresLoadingScreen = Xml.GetBoolAttribute(child, "value");
break;
case "loadingScreenContext":
loadingScreenContext = child.InnerText;
break;
case "useCacheLoader":
useCacheLoader = Xml.GetBoolAttribute(child, "value");
break;
case "executionConditions":
executionConditions = new DlcContentChangeSetExecutionConditions(child);
break;
default:
break;
}
}
}
private List<string> GetChildStringArray(XmlNode node)
{
if (!node.HasChildNodes) return null;
var result = new List<string>();
foreach (XmlNode child in node.ChildNodes)
{
if (child.NodeType == XmlNodeType.Element)
{
result.Add(child.InnerText);
}
}
return result;
}
public override string ToString()
{
return (changeSetName != null) ? changeSetName : (associatedMap != null) ? associatedMap : null;
}
}
public class DlcContentChangeSetExecutionConditions
{
public string activeChangesetConditions { get; set; }
public string genericConditions { get; set; }
public DlcContentChangeSetExecutionConditions(XmlNode node)
{
Load(node);
}
public void Load(XmlNode node)
{
foreach (XmlNode child in node.ChildNodes)
{
if (child.NodeType != XmlNodeType.Element) continue;
switch (child.Name)
{
case "activeChangesetConditions":
activeChangesetConditions = child.InnerText;
break;
case "genericConditions":
genericConditions = child.InnerText;
break;
default:
break;
}
}
}
public override string ToString()
{
return (string.IsNullOrEmpty(activeChangesetConditions) ? "" : activeChangesetConditions + ", ") + (string.IsNullOrEmpty(genericConditions) ? "" : genericConditions);
}
}
public class DlcExtraFolderMountFile
{
public List<DlcExtraFolderMount> FolderMounts { get; set; } = new List<DlcExtraFolderMount>();
public void Load(XmlDocument doc)
{
var root = doc.DocumentElement;
XmlNodeList mountitems = doc.SelectNodes("SExtraFolderMountData/FolderMounts/Item");
FolderMounts.Clear();
for (int i = 0; i < mountitems.Count; i++)
{
var mount = new DlcExtraFolderMount();
mount.Init(mountitems[i]);
FolderMounts.Add(mount);
}
}
public override string ToString()
{
return "(" + FolderMounts.Count.ToString() + " FolderMounts)";
}
}
public class DlcExtraFolderMount
{
public string type { get; set; }
public string platform { get; set; }
public string path { get; set; }
public string mountAs { get; set; }
public void Init(XmlNode node)
{
type = Xml.GetStringAttribute(node, "type");
platform = Xml.GetStringAttribute(node, "platform");
path = Xml.GetChildInnerText(node, "path");
mountAs = Xml.GetChildInnerText(node, "mountAs");
}
public override string ToString()
{
return type + ": " + path + " - " + mountAs + ((platform != null) ? (" (" + platform + ")") : "");
}
}
public class DlcExtraTitleUpdateFile
{
public List<DlcExtraTitleUpdateMount> Mounts { get; set; } = new List<DlcExtraTitleUpdateMount>();
public void Load(XmlDocument doc)
{
var root = doc.DocumentElement;
XmlNodeList mountitems = doc.SelectNodes("SExtraTitleUpdateData/Mounts/Item");
Mounts.Clear();
for (int i = 0; i < mountitems.Count; i++)
{
var mount = new DlcExtraTitleUpdateMount();
mount.Init(mountitems[i]);
Mounts.Add(mount);
}
}
public override string ToString()
{
return "(" + Mounts.Count.ToString() + " Mounts)";
}
}
public class DlcExtraTitleUpdateMount
{
public string type { get; set; }
public string deviceName { get; set; }
public string path { get; set; }
public void Init(XmlNode node)
{
type = Xml.GetStringAttribute(node, "type");
deviceName = Xml.GetChildInnerText(node, "deviceName");
path = Xml.GetChildInnerText(node, "path");
}
public override string ToString()
{
return type + ": " + deviceName + " - " + path;
}
}
}

View File

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.GameFiles
{
public class DlcSetupFile
{
public string deviceName { get; set; }
public string datFile { get; set; }
public string nameHash { get; set; }
public List<DlcSetupContentChangesetGroup> contentChangeSetGroups { get; set; }
public string type { get; set; }
public string timeStamp { get; set; }
public int order { get; set; }
public int minorOrder { get; set; }
public int subPackCount { get; set; }
public bool isLevelPack { get; set; }
public RpfFile DlcFile { get; set; } //used by GameFileCache
public DlcContentFile ContentFile { get; set; }
public void Load(XmlDocument doc)
{
var root = doc.DocumentElement;
deviceName = Xml.GetChildInnerText(root, "deviceName");
datFile = Xml.GetChildInnerText(root, "datFile");
nameHash = Xml.GetChildInnerText(root, "nameHash");
type = Xml.GetChildInnerText(root, "type");
timeStamp = Xml.GetChildInnerText(root, "timeStamp");
order = Xml.GetIntAttribute(root.SelectSingleNode("order"), "value");
minorOrder = Xml.GetIntAttribute(root.SelectSingleNode("minorOrder"), "value");
subPackCount = Xml.GetIntAttribute(root.SelectSingleNode("subPackCount"), "value");
isLevelPack = Xml.GetBoolAttribute(root.SelectSingleNode("isLevelPack"), "value");
contentChangeSetGroups = new List<DlcSetupContentChangesetGroup>();
var groups = root.SelectNodes("contentChangeSetGroups/Item");
foreach (XmlNode node in groups)
{
var group = new DlcSetupContentChangesetGroup();
group.Load(node);
contentChangeSetGroups.Add(group);
}
if (root.ChildNodes.Count > 15)
{ }
}
public override string ToString()
{
return deviceName + ", " + datFile + ", " + nameHash + ", " + type + ", " + order.ToString() + ", " + ((contentChangeSetGroups != null) ? contentChangeSetGroups.Count.ToString() : "0") + " groups, " + timeStamp;
}
}
public class DlcSetupContentChangesetGroup
{
public string NameHash { get; set; }
public List<string> ContentChangeSets { get; set; }
public void Load(XmlNode node)
{
if (node.ChildNodes.Count != 2)
{ }
NameHash = Xml.GetChildInnerText(node, "NameHash");
ContentChangeSets = new List<string>();
var changesets = node.SelectNodes("ContentChangeSets/Item");
foreach (XmlNode changeset in changesets)
{
ContentChangeSets.Add(changeset.InnerText);
}
}
public override string ToString()
{
return NameHash + " (" + ((ContentChangeSets != null) ? ContentChangeSets.Count.ToString() : "0") + " changesets)";
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class GtxdFile : GameFile, PackedFile
{
public RbfFile Rbf { get; set; }
public Dictionary<string, string> CMapParentTxds { get; set; }
public GtxdFile() : base(null, GameFileType.Gtxd)
{
}
public GtxdFile(RpfFileEntry entry) : base(entry, GameFileType.Gtxd)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
RpfFileEntry = entry;
Name = entry.Name;
FilePath = Name;
if (entry.NameLower.EndsWith(".ymt"))
{
MemoryStream ms = new MemoryStream(data);
if (RbfFile.IsRBF(ms))
{
Rbf = new RbfFile();
var rbfstruct = Rbf.Load(ms);
if (rbfstruct.Name == "CMapParentTxds")
{
LoadMapParentTxds(rbfstruct);
}
Loaded = true;
return;
}
else
{
//not an RBF file...
}
}
else if (entry.NameLower.EndsWith(".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 bom = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
string xml = Encoding.UTF8.GetString(data);
if (xml.StartsWith(bom, StringComparison.Ordinal))
{
xml = xml.Remove(0, bom.Length);
}
LoadMapParentTxds(xml);
Loaded = true;
}
}
private void LoadMapParentTxds(RbfStructure rbfstruct)
{
CMapParentTxds = new Dictionary<string, string>();
//StringBuilder sblist = new StringBuilder();
foreach (var child in rbfstruct.Children)
{
var childstruct = child as RbfStructure;
if ((childstruct != null) && (childstruct.Name == "txdRelationships"))
{
foreach (var txdrel in childstruct.Children)
{
var txdrelstruct = txdrel as RbfStructure;
if ((txdrelstruct != null) && (txdrelstruct.Name == "item"))
{
string parentstr = string.Empty;
string childstr = string.Empty;
foreach (var item in txdrelstruct.Children)
{
var itemstruct = item as RbfStructure;
if ((itemstruct != null))
{
var strbytes = itemstruct.Children[0] as RbfBytes;
string thisstr = string.Empty;
if (strbytes != null)
{
thisstr = Encoding.ASCII.GetString(strbytes.Value).Replace("\0", "");
}
switch (item.Name)
{
case "parent":
parentstr = thisstr;
break;
case "child":
childstr = thisstr;
break;
}
}
}
if ((!string.IsNullOrEmpty(parentstr)) && (!string.IsNullOrEmpty(childstr)))
{
if (!CMapParentTxds.ContainsKey(childstr))
{
CMapParentTxds.Add(childstr, parentstr);
}
else
{
}
//sblist.AppendLine(childstr + ": " + parentstr);
}
}
}
}
}
//string alltxdmap = sblist.ToString();
//if (!string.IsNullOrEmpty(alltxdmap))
//{
//}
}
private void LoadMapParentTxds(string xml)
{
XmlDocument xmldoc = new XmlDocument();
xmldoc.LoadXml(xml); //maybe better load xml.ToLower() and use "cmapparenttxds/txdrelationships/item" as xpath?
XmlNodeList items = xmldoc.SelectNodes("CMapParentTxds/txdRelationships/Item | CMapParentTxds/txdRelationships/item");
CMapParentTxds = new Dictionary<string, string>();
for (int i = 0; i < items.Count; i++)
{
string parentstr = Xml.GetChildInnerText(items[i], "parent");
string childstr = Xml.GetChildInnerText(items[i], "child");
if ((!string.IsNullOrEmpty(parentstr)) && (!string.IsNullOrEmpty(childstr)))
{
if (!CMapParentTxds.ContainsKey(childstr))
{
CMapParentTxds.Add(childstr, parentstr);
}
}
}
}
}
}

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class Gxt2File : PackedFile
{
public string Name { get; set; }
public RpfFileEntry FileEntry { get; set; }
public uint EntryCount { get; set; }
public Gxt2Entry[] TextEntries { get; set; }
//public Dictionary<uint, string> Dict { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
FileEntry = entry;
//Dict = new Dictionary<uint, string>();
using (BinaryReader br = new BinaryReader(new MemoryStream(data)))
{
uint gxt2 = br.ReadUInt32(); //"GXT2" - 1196971058
if (gxt2 != 1196971058)
{ return; }
EntryCount = br.ReadUInt32();
TextEntries = new Gxt2Entry[EntryCount];
for (uint i = 0; i < EntryCount; i++)
{
var e = new Gxt2Entry();
e.Hash = br.ReadUInt32();
e.Offset = br.ReadUInt32();
TextEntries[i] = e;
}
gxt2 = br.ReadUInt32(); //another "GXT2"
if (gxt2 != 1196971058)
{ return; }
uint endpos = br.ReadUInt32();
List<byte> buf = new List<byte>();
for (uint i = 0; i < EntryCount; i++)
{
var e = TextEntries[i];
br.BaseStream.Position = e.Offset;
buf.Clear();
byte b = br.ReadByte();
while ((b != 0) && (br.BaseStream.Position<endpos))
{
buf.Add(b);
b = br.ReadByte();
}
e.Text = Encoding.UTF8.GetString(buf.ToArray());
//Dict[e.Hash] = e.Text;
}
}
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class Gxt2Entry
{
public uint Hash { get; set; }
public uint Offset { get; set; }
public string Text { get; set; }
public override string ToString()
{
return Convert.ToString(Hash, 16).ToUpper().PadLeft(8, '0') + ": " + Text;
}
}
public static class GlobalText
{
public static Dictionary<uint, string> Index = new Dictionary<uint, string>();
private static object syncRoot = new object();
public static volatile bool FullIndexBuilt = false;
public static void Clear()
{
lock (syncRoot)
{
Index.Clear();
}
}
public static bool Ensure(string str)
{
uint hash = JenkHash.GenHash(str);
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static bool Ensure(string str, uint hash)
{
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static string GetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = hash.ToString();
}
}
return res;
}
public static string TryGetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = string.Empty;
}
}
return res;
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class JPsoFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public PsoFile Pso { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
//MemoryStream ms = new MemoryStream(data);
FileEntry = entry;
MemoryStream ms = new MemoryStream(data);
if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
var root = PsoTypes.GetRootEntry(Pso);
if (root != null)
{
}
return;
}
else
{
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public static class StatsNames
{
public static Dictionary<uint, string> Index = new Dictionary<uint, string>();
private static object syncRoot = new object();
public static volatile bool FullIndexBuilt = false;
public static void Clear()
{
lock (syncRoot)
{
Index.Clear();
}
}
public static bool Ensure(string str)
{
uint hash = JenkHash.GenHash(str);
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static bool Ensure(string str, uint hash)
{
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static string GetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = hash.ToString();
}
}
return res;
}
public static string TryGetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = string.Empty;
}
}
return res;
}
}
}

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YbnFile : GameFile, PackedFile
{
public Bounds Bounds { get; set; }
public YbnFile() : base(null, GameFileType.Ybn)
{
}
public YbnFile(RpfFileEntry entry) : base(entry, GameFileType.Ybn)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Bounds = rd.ReadBlock<Bounds>();
Bounds.OwnerName = entry.Name;
Loaded = true;
}
}
}

View File

@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))]
public class YcdFile : GameFile, PackedFile
{
public ClipDictionary ClipDictionary { get; set; }
public Dictionary<MetaHash, ClipMapEntry> ClipMap { get; set; }
public Dictionary<MetaHash, AnimationMapEntry> AnimMap { get; set; }
public ClipMapEntry[] ClipMapEntries { get; set; }
public AnimationMapEntry[] AnimMapEntries { get; set; }
public YcdFile() : base(null, GameFileType.Ycd)
{
}
public YcdFile(RpfFileEntry entry) : base(entry, GameFileType.Ycd)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
//Hash = entry.ShortNameHash;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
ClipDictionary = rd.ReadBlock<ClipDictionary>();
ClipMap = new Dictionary<MetaHash, ClipMapEntry>();
AnimMap = new Dictionary<MetaHash, AnimationMapEntry>();
if (ClipDictionary != null)
{
if ((ClipDictionary.Clips != null) && (ClipDictionary.Clips.data_items != null))
{
foreach (var cme in ClipDictionary.Clips.data_items)
{
if (cme != null)
{
ClipMap[cme.Hash] = cme;
var nxt = cme.Next;
while (nxt != null)
{
ClipMap[nxt.Hash] = nxt;
nxt = nxt.Next;
}
}
}
}
if ((ClipDictionary.Animations != null) && (ClipDictionary.Animations.Animations != null) && (ClipDictionary.Animations.Animations.data_items != null))
{
foreach (var ame in ClipDictionary.Animations.Animations.data_items)
{
if (ame != null)
{
AnimMap[ame.Hash] = ame;
var nxt = ame.NextEntry;
while (nxt != null)
{
AnimMap[nxt.Hash] = nxt;
nxt = nxt.NextEntry;
}
}
}
}
}
foreach (var cme in ClipMap.Values)
{
var clip = cme.Clip;
if (clip == null) continue;
clip.Ycd = this;
if (string.IsNullOrEmpty(clip.Name)) continue;
string name = clip.Name.Replace('\\', '/');
var slidx = name.LastIndexOf('/');
if ((slidx >= 0) && (slidx < name.Length - 1))
{
name = name.Substring(slidx + 1);
}
var didx = name.LastIndexOf('.');
if ((didx > 0) && (didx < name.Length))
{
name = name.Substring(0, didx);
}
clip.ShortName = name;
name = name.ToLowerInvariant();
JenkIndex.Ensure(name);
//if (name.EndsWith("_uv_0")) //hash for these entries match string with this removed, +1
//{
//}
//if (name.EndsWith("_uv_1")) //same as above, but +2
//{
//}
}
foreach (var ame in AnimMap.Values)
{
var anim = ame.Animation;
if (anim == null) continue;
anim.Ycd = this;
}
ClipMapEntries = ClipMap.Values.ToArray();
AnimMapEntries = AnimMap.Values.ToArray();
}
}
}

View File

@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class YddFile : GameFile, PackedFile
{
public DrawableDictionary DrawableDict { get; set; }
public Dictionary<uint, Drawable> Dict { get; set; }
public Drawable[] Drawables { get; set; }
public YddFile() : base(null, GameFileType.Ydd)
{
}
public YddFile(RpfFileEntry entry) : base(entry, GameFileType.Ydd)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
DrawableDict = rd.ReadBlock<DrawableDictionary>();
//MemoryUsage = 0; //uses decompressed filesize now...
//if (DrawableDict != null)
//{
// MemoryUsage += DrawableDict.MemoryUsage;
//}
if ((DrawableDict != null) &&
(DrawableDict.Drawables != null) &&
(DrawableDict.Drawables.data_items != null) &&
(DrawableDict.Hashes != null))
{
Dict = new Dictionary<uint, Drawable>();
var drawables = DrawableDict.Drawables.data_items;
var hashes = DrawableDict.Hashes;
for (int i = 0; (i < drawables.Length) && (i < hashes.Length); i++)
{
var drawable = drawables[i];
var hash = hashes[i];
Dict[hash] = drawable;
drawable.Owner = this;
}
for (int i = 0; (i < drawables.Length) && (i < hashes.Length); i++)
{
var drawable = drawables[i];
var hash = hashes[i];
if ((drawable.Name == null) || (drawable.Name.EndsWith("#dd")))
{
string hstr = JenkIndex.TryGetString(hash);
if (!string.IsNullOrEmpty(hstr))
{
drawable.Name = hstr;
}
else
{ }
}
}
Drawables = Dict.Values.ToArray();
}
Loaded = true;
}
}
}

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YdrFile : GameFile, PackedFile
{
public Drawable Drawable { get; set; }
public YdrFile() : base(null, GameFileType.Ydr)
{
}
public YdrFile(RpfFileEntry entry) : base(entry, GameFileType.Ydr)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
//MemoryUsage = 0;
try
{
Drawable = rd.ReadBlock<Drawable>();
Drawable.Owner = this;
//MemoryUsage += Drawable.MemoryUsage; //uses decompressed filesize now...
}
catch (Exception ex)
{
string err = ex.ToString();
}
Loaded = true;
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YftFile : GameFile, PackedFile
{
public FragType Fragment { get; set; }
public YftFile() : base(null, GameFileType.Yft)
{
}
public YftFile(RpfFileEntry entry) : base(entry, GameFileType.Yft)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Fragment = rd.ReadBlock<FragType>();
if (Fragment.Drawable != null)
{
Fragment.Drawable.Owner = this;
}
if (Fragment.Unknown_F8h_Data != null)
{
Fragment.Unknown_F8h_Data.Owner = this;
}
Loaded = true;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YmfFile : PackedFile
{
public RpfFileEntry FileEntry { get; set; }
public Meta Meta { get; set; }
public PsoFile Pso { get; set; }
public RbfFile Rbf { get; set; }
public YmfMapDataGroup[] MapDataGroups { get; set; }
public CImapDependency[] imapDependencies { get; set; }
public YmfImapDependency2[] imapDependencies2 { get; set; }
public YmfItypDependency2[] itypDependencies2 { get; set; }
public CHDTxdAssetBinding[] HDTxdAssetBindings { get; set; }
public YmfInterior[] Interiors { get; set; }
public void Load(byte[] data, RpfFileEntry entry)
{
FileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
MemoryStream ms = new MemoryStream(data);
if (RbfFile.IsRBF(ms))
{
Rbf = new RbfFile();
Rbf.Load(ms);
//x64j.rpf\\levels\\gta5\\_citye\\indust_01\\id1_props.rpf\\_manifest.ymf
//x64j.rpf\\levels\\gta5\\_citye\\indust_02\\id2_props.rpf\\_manifest.ymf
//x64q.rpf\\levels\\gta5\\_hills\\country_01\\cs1_railwyc.rpf\\_manifest.ymf
//all just HDTxd bindings
return;
}
if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
ProcessPSO();
return;
}
else
{
}
return;
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Meta = rd.ReadBlock<Meta>();
}
private void ProcessPSO()
{
//See x64m.rpf\levels\gta5\_cityw\venice_01\venice_metadata.rpf\_manifest.ymf
//for TIMED YMAP stuff!!!!
//check CMapDataGroup.HoursOnOff
var d = PsoTypes.GetRootItem<CPackFileMetaData>(Pso);
MapDataGroups = PsoTypes.GetObjectArray<YmfMapDataGroup, CMapDataGroup>(Pso, d.MapDataGroups);
imapDependencies = PsoTypes.GetItemArray<CImapDependency>(Pso, d.imapDependencies);
imapDependencies2 = PsoTypes.GetObjectArray<YmfImapDependency2, CImapDependencies>(Pso, d.imapDependencies_2);
itypDependencies2 = PsoTypes.GetObjectArray<YmfItypDependency2, CItypDependencies>(Pso, d.itypDependencies_2);
HDTxdAssetBindings = PsoTypes.GetItemArray<CHDTxdAssetBinding>(Pso, d.HDTxdBindingArray);
Interiors = PsoTypes.GetObjectArray<YmfInterior, Unk_741495440>(Pso, d.Interiors);
}
public override string ToString()
{
return (FileEntry != null) ? FileEntry.Path : string.Empty;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmfMapDataGroup : PsoClass<CMapDataGroup>
{
public CMapDataGroup DataGroup { get; set; } //ymap name
public MetaHash[] Bounds { get; set; }
public MetaHash[] WeatherTypes { get; set; }
public MetaHash Name { get; set; }
public ushort Flags { get; set; }
public uint HoursOnOff { get; set; }
public override string ToString()
{
return DataGroup.ToString();
}
public override void Init(PsoFile pso, ref CMapDataGroup v)
{
DataGroup = v;
Bounds = PsoTypes.GetHashArray(pso, v.Bounds);
WeatherTypes = PsoTypes.GetHashArray(pso, v.WeatherTypes);
Name = v.Name;
Flags = v.Flags;
HoursOnOff = v.HoursOnOff;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmfImapDependency2 : PsoClass<CImapDependencies>
{
public CImapDependencies Dep { get; set; }
public MetaHash[] itypDepArray { get; set; }//ybn hashes?
public override void Init(PsoFile pso, ref CImapDependencies v)
{
Dep = v;
itypDepArray = PsoTypes.GetHashArray(pso, v.itypDepArray);
}
public override string ToString()
{
return Dep.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmfItypDependency2 : PsoClass<CItypDependencies>
{
public CItypDependencies Dep { get; set; }
public MetaHash[] itypDepArray { get; set; }//ytyp hashes?
public override void Init(PsoFile pso, ref CItypDependencies v)
{
Dep = v;
itypDepArray = PsoTypes.GetHashArray(pso, v.itypDepArray);
}
public override string ToString()
{
return Dep.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmfInterior : PsoClass<Unk_741495440>
{
public Unk_741495440 Interior { get; set; }
public MetaHash[] Bounds { get; set; }//ybn hashes?
public override string ToString()
{
return Interior.ToString();
}
public override void Init(PsoFile pso, ref Unk_741495440 v)
{
Interior = v;
Bounds = PsoTypes.GetHashArray(pso, v.Bounds);
}
}
}

View File

@ -0,0 +1,324 @@
using CodeWalker.World;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmtFile : GameFile, PackedFile
{
public Meta Meta { get; set; }
public PsoFile Pso { get; set; }
public RbfFile Rbf { get; set; }
public YmtFileFormat FileFormat { get; set; } = YmtFileFormat.Unknown;
public YmtFileContentType ContentType { get; set; } = YmtFileContentType.None;
public Dictionary<string,string> CMapParentTxds { get; set; }
public YmtScenarioPointManifest CScenarioPointManifest { get; set; }
public MCScenarioPointRegion CScenarioPointRegion { get; set; }
public ScenarioRegion ScenarioRegion { get; set; }
//fields used by the editor:
public bool HasChanged { get; set; } = false;
public List<string> SaveWarnings = null;
public YmtFile() : base(null, GameFileType.Ymt)
{
}
public YmtFile(RpfFileEntry entry) : base(entry, GameFileType.Ymt)
{
}
public void Load(byte[] data)
{
//direct load from a raw, compressed ymt resource file (openIV-compatible format)
RpfFile.LoadResourceFile(this, data, 2);
Loaded = true;
}
public void Load(byte[] data, RpfFileEntry entry)
{
RpfFileEntry = entry;
Name = entry.Name;
FilePath = Name;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry != null)
{
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Meta = rd.ReadBlock<Meta>();
var rootblock = Meta.GetRootBlock();
if (rootblock != null)
{
if (rootblock.StructureNameHash == MetaName.CScenarioPointRegion)
{
LoadScenarioPointRegion(Meta, rootblock);
}
}
Loaded = true;
return;
}
MemoryStream ms = new MemoryStream(data);
if (RbfFile.IsRBF(ms))
{
Rbf = new RbfFile();
var rbfstruct = Rbf.Load(ms);
if (rbfstruct.Name == "CMapParentTxds")
{
LoadMapParentTxds(rbfstruct);
}
Loaded = true;
return;
}
if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
var root = PsoTypes.GetRootEntry(Pso);
if (root != null)
{
if (root.NameHash == MetaName.CScenarioPointManifest)
{
LoadScenarioPointManifest(Pso);
}
}
Loaded = true;
return;
}
else
{
}
}
private void LoadMapParentTxds(RbfStructure rbfstruct)
{
FileFormat = YmtFileFormat.RBF;
ContentType = YmtFileContentType.MapParentTxds;
CMapParentTxds = new Dictionary<string, string>();
//StringBuilder sblist = new StringBuilder();
foreach(var child in rbfstruct.Children)
{
var childstruct = child as RbfStructure;
if ((childstruct != null) && (childstruct.Name == "txdRelationships"))
{
foreach (var txdrel in childstruct.Children)
{
var txdrelstruct = txdrel as RbfStructure;
if ((txdrelstruct != null) && (txdrelstruct.Name == "item"))
{
string parentstr = string.Empty;
string childstr = string.Empty;
foreach(var item in txdrelstruct.Children)
{
var itemstruct = item as RbfStructure;
if ((itemstruct != null))
{
var strbytes = itemstruct.Children[0] as RbfBytes;
string thisstr = string.Empty;
if (strbytes != null)
{
thisstr = Encoding.ASCII.GetString(strbytes.Value).Replace("\0", "");
}
switch (item.Name)
{
case "parent":
parentstr = thisstr;
break;
case "child":
childstr = thisstr;
break;
}
}
}
if((!string.IsNullOrEmpty(parentstr)) && (!string.IsNullOrEmpty(childstr)))
{
if (!CMapParentTxds.ContainsKey(childstr))
{
CMapParentTxds.Add(childstr, parentstr);
}
else
{
}
//sblist.AppendLine(childstr + ": " + parentstr);
}
}
}
}
}
//string alltxdmap = sblist.ToString();
//if (!string.IsNullOrEmpty(alltxdmap))
//{
//}
}
private void LoadScenarioPointManifest(PsoFile pso)
{
FileFormat = YmtFileFormat.PSO;
ContentType = YmtFileContentType.ScenarioPointManifest;
CScenarioPointManifest = new YmtScenarioPointManifest();
CScenarioPointManifest.Load(pso);
}
private void LoadScenarioPointRegion(Meta meta, MetaDataBlock rootblock)
{
FileFormat = YmtFileFormat.RSC;
ContentType = YmtFileContentType.ScenarioPointRegion;
var cdata = MetaTypes.ConvertData<CScenarioPointRegion>(rootblock.Data);
CScenarioPointRegion = new MCScenarioPointRegion();
CScenarioPointRegion.Ymt = this;
CScenarioPointRegion.Load(meta, cdata);
ScenarioRegion = new ScenarioRegion();
ScenarioRegion.Load(this);
//string stypes = MetaTypes.GetTypesInitString(meta);
//if (!string.IsNullOrEmpty(stypes))
//{ }
}
public byte[] Save()
{
switch (ContentType)
{
case YmtFileContentType.MapParentTxds: return SaveMapParentTxds();
case YmtFileContentType.ScenarioPointManifest: return SaveScenarioPointManifest();
case YmtFileContentType.ScenarioPointRegion: return SaveScenarioPointRegion();
}
return null;
}
private byte[] SaveMapParentTxds()
{
return null;
}
private byte[] SaveScenarioPointManifest()
{
return null;
}
private byte[] SaveScenarioPointRegion()
{
if (ScenarioRegion != null)
{
return ScenarioRegion.Save();
}
return null;
}
private void LogSaveWarning(string w)
{
if (SaveWarnings == null) SaveWarnings = new List<string>();
SaveWarnings.Add(w);
}
public override string ToString()
{
return RpfFileEntry.ToString();
}
}
public enum YmtFileFormat
{
Unknown = 0,
RSC = 1,
PSO = 2,
RBF = 3,
}
public enum YmtFileContentType
{
None = 0,
MapParentTxds = 1,
ScenarioPointManifest = 2,
ScenarioPointRegion = 3,
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YmtScenarioPointManifest
{
public CScenarioPointManifest _Data;
public CScenarioPointManifest Data { get { return _Data; } set { _Data = value; } }
public CScenarioPointRegionDef[] RegionDefs { get; set; }
public CScenarioPointGroup[] Groups { get; set; }
public MetaHash[] InteriorNames { get; set; }
public void Load(PsoFile pso)
{
Data = PsoTypes.GetRootItem<CScenarioPointManifest>(pso);
RegionDefs = PsoTypes.ConvertDataArray<CScenarioPointRegionDef>(pso, _Data.RegionDefs);
Groups = PsoTypes.ConvertDataArray<CScenarioPointGroup>(pso, _Data.Groups);
InteriorNames = PsoTypes.GetHashArray(pso, _Data.InteriorNames);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,689 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvFile : GameFile, PackedFile, BasePathData
{
public NavMesh Nav { get; set; }
public List<Vector3> Vertices { get; set; }
public List<ushort> Indices { get; set; }
public List<NavMeshAdjPoly> AdjPolys { get; set; }
public List<YnvPoly> Polys { get; set; }
public List<YnvPortal> Portals { get; set; }
public List<YnvPoint> Points { get; set; }
public EditorVertex[] PathVertices { get; set; }
public EditorVertex[] TriangleVerts { get; set; }
public Vector4[] NodePositions { get; set; }
//fields used by the editor:
public bool HasChanged { get; set; } = false;
public List<string> SaveWarnings = null;
public PathBVH BVH { get; set; }
public int AreaID
{
get
{
return (int)(Nav?.AreaID ?? 0);
}
set
{
if (Nav != null) Nav.AreaID = (uint)value;
}
}
public int CellX { get { return AreaID % 100; } set { AreaID = (CellY * 100) + value; } }
public int CellY { get { return AreaID / 100; } set { AreaID = (value * 100) + CellX; } }
public YnvFile() : base(null, GameFileType.Ynv)
{
}
public YnvFile(RpfFileEntry entry) : base(entry, GameFileType.Ynv)
{
}
public void Load(byte[] data)
{
//direct load from a raw, compressed ynv file (openIV-compatible format)
RpfFile.LoadResourceFile(this, data, 2);
Loaded = true;
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Nav = rd.ReadBlock<NavMesh>();
if (Nav != null)
{
Vector3 posoffset = Nav.SectorTree?.AABBMin.XYZ() ?? Vector3.Zero;
Vector3 aabbsize = Nav.AABBSize;
if (Nav.Vertices != null)
{
var verts = Nav.Vertices.GetFullList();
Vertices = new List<Vector3>(verts.Count);
for (int i = 0; i < verts.Count; i++)
{
var ov = verts[i].ToVector3();
Vertices.Add(posoffset + ov * aabbsize);
}
}
if (Nav.Indices != null)
{
Indices = Nav.Indices.GetFullList();
}
if (Nav.AdjPolys != null)
{
AdjPolys = Nav.AdjPolys.GetFullList();
}
if (Nav.Polys != null)
{
var polys = Nav.Polys.GetFullList();
Polys = new List<YnvPoly>(polys.Count);
for (int i = 0; i < polys.Count; i++)
{
YnvPoly poly = new YnvPoly();
poly.Init(this, polys[i]);
poly.Index = i;
poly.CalculatePosition(); //calc poly center for display purposes..
Polys.Add(poly);
}
}
if (Nav.Portals != null)
{
var portals = Nav.Portals;
Portals = new List<YnvPortal>(portals.Length);
for (int i = 0; i < portals.Length; i++)
{
YnvPortal portal = new YnvPortal();
portal.Init(this, portals[i]);
portal.Index = i;
portal.Position1 = posoffset + portal._RawData.Position1.ToVector3() * aabbsize;
portal.Position2 = posoffset + portal._RawData.Position2.ToVector3() * aabbsize;
Portals.Add(portal);
}
}
////### add points to the list and calculate positions...
var treestack = new Stack<NavMeshSector>();
var pointi = 0;
if (Nav.SectorTree != null)
{
treestack.Push(Nav.SectorTree);
}
while (treestack.Count > 0)
{
var sector = treestack.Pop();
if (sector.Data != null)
{
var points = sector.Data.Points;
if (points != null)
{
if (Points == null)
{
Points = new List<YnvPoint>();
}
for (int i = 0; i < points.Length; i++)
{
YnvPoint point = new YnvPoint();
point.Init(this, points[i]);
point.Index = pointi; pointi++;
point.Position = posoffset + point._RawData.Position * aabbsize;
Points.Add(point);
}
}
}
if (sector.SubTree1 != null) treestack.Push(sector.SubTree1);
if (sector.SubTree2 != null) treestack.Push(sector.SubTree2);
if (sector.SubTree3 != null) treestack.Push(sector.SubTree3);
if (sector.SubTree4 != null) treestack.Push(sector.SubTree4);
}
}
UpdateAllNodePositions();
UpdateTriangleVertices();
BuildBVH();
Loaded = true;
LoadQueued = true;
}
public byte[] Save()
{
BuildStructs();
byte[] data = ResourceBuilder.Build(Nav, 2); //ynv is version 2...
return data;
}
public void BuildStructs()
{
Vector3 posoffset = Nav.SectorTree?.AABBMin.XYZ() ?? Vector3.Zero;
Vector3 aabbsize = Nav.AABBSize;
Vector3 aabbsizeinv = 1.0f / aabbsize;
var vertlist = new List<NavMeshVertex>();
if (Vertices != null)
{
for (int i = 0; i < Vertices.Count; i++)
{
vertlist.Add(NavMeshVertex.Create((Vertices[i] - posoffset) * aabbsizeinv));
}
}
var polylist = new List<NavMeshPoly>();
if (Polys != null)
{
for (int i = 0; i < Polys.Count; i++)
{
polylist.Add(Polys[i].RawData);
}
}
if (Nav.Vertices == null)
{
Nav.Vertices = new NavMeshList<NavMeshVertex>();
Nav.Vertices.VFT = 1080158456;
}
if (Nav.Indices == null)
{
Nav.Indices = new NavMeshList<ushort>();
Nav.Indices.VFT = 1080158424;
}
if (Nav.AdjPolys == null)
{
Nav.AdjPolys = new NavMeshList<NavMeshAdjPoly>();
Nav.AdjPolys.VFT = 1080158440;
}
if (Nav.Polys == null)
{
Nav.Polys = new NavMeshList<NavMeshPoly>();
Nav.Polys.VFT = 1080158408;
}
Nav.Vertices.RebuildList(vertlist);
Nav.Indices.RebuildList(Indices);
Nav.AdjPolys.RebuildList(AdjPolys);
Nav.Polys.RebuildList(polylist);
for (int i = 0; i < Nav.Polys.ListParts.Count; i++) //reassign part id's on all the polys...
{
var listpart = Nav.Polys.ListParts[i];
var partitems = listpart?.Items;
if (partitems == null) continue;
ushort iu = (ushort)i;
for (int j = 0; j < partitems.Length; j++)
{
partitems[j].PartID = iu;
}
}
}
public bool RemovePoly(YnvPoly poly)
{
return false;
}
public void UpdateAllNodePositions()
{
if (Nav == null) return;
Vector3 posoffset = Nav.SectorTree.AABBMin.XYZ();
Vector3 aabbsize = Nav.AABBSize;
EditorVertex v = new EditorVertex();
v.Colour = 0xFF0000FF;
var lv = new List<EditorVertex>();
var nv = new List<Vector4>();
////### add portal positions to the node list, also add links to the link vertex array
int cnt = Portals?.Count ?? 0;
if (cnt > 0)
{
for (int i = 0; i < cnt; i++)
{
var portal = Portals[i];
nv.Add(new Vector4(portal.Position1, 1.0f));
v.Position = portal.Position1; lv.Add(v);
v.Position = portal.Position2; lv.Add(v);
}
}
////### add point positions to the node list
cnt = Points?.Count ?? 0;
if (cnt >= 0)
{
for (int i = 0; i < cnt; i++)
{
var point = Points[i];
nv.Add(new Vector4(point.Position, 1.0f));
}
}
NodePositions = (nv.Count > 0) ? nv.ToArray() : null;
PathVertices = (lv.Count > 0) ? lv.ToArray() : null;
}
public void UpdateTriangleVertices()
{
//need position and colour for each vertex.
//render as a triangle list... (no indices needed)
//go through the nav mesh polys and generate verts to render...
if ((Vertices == null) || (Vertices.Count == 0)) return;
if ((Indices == null) || (Indices.Count == 0)) return;
if ((Polys == null) || (Polys.Count == 0)) return;
int vc = Vertices.Count;
List<EditorVertex> rverts = new List<EditorVertex>();
foreach (var ypoly in Polys)
{
var poly = ypoly.RawData;
var colour = ypoly.GetColour();
var colourval = (uint)colour.ToRgba();
var ic = poly.IndexCount;
var startid = poly.IndexID;
var endid = startid + ic;
if (startid >= Indices.Count)
{ continue; }
if (endid > Indices.Count)
{ continue; }
if(ic<3)
{ continue; }//not enough verts to make a triangle...
if (ic > 15)
{ }
EditorVertex p0 = new EditorVertex();
EditorVertex p1 = new EditorVertex();
EditorVertex p2 = new EditorVertex();
p0.Colour = colourval;
p1.Colour = colourval;
p2.Colour = colourval;
var startind = Indices[startid];
if (startind >= vc)
{ continue; }
p0.Position = Vertices[startind];
//build triangles for the poly.
int tricount = ic - 2;
for (int t = 0; t < tricount; t++)
{
int tid = startid + t;
int ind1 = Indices[tid + 1];
int ind2 = Indices[tid + 2];
if ((ind1 >= vc) || (ind2 >= vc))
{ continue; }
p1.Position = Vertices[ind1];
p2.Position = Vertices[ind2];
rverts.Add(p0);
rverts.Add(p1);
rverts.Add(p2);
}
}
TriangleVerts = rverts.ToArray();
}
public void BuildBVH()
{
var nodes = new List<BasePathNode>();
if (Portals != null) nodes.AddRange(Portals);
if (Points != null) nodes.AddRange(Points);
BVH = new PathBVH(nodes, 10, 10);
}
public EditorVertex[] GetPathVertices()
{
return PathVertices;
}
public EditorVertex[] GetTriangleVertices()
{
return TriangleVerts;
}
public Vector4[] GetNodePositions()
{
return NodePositions;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPoly
{
public NavMeshPoly _RawData;
public YnvFile Ynv { get; set; }
public NavMeshPoly RawData { get { return _RawData; } set { _RawData = value; } }
public ushort AreaID { get { return _RawData.AreaID; } set { _RawData.AreaID = value; } }
public ushort PartID { get { return _RawData.PartID; } set { _RawData.PartID = value; } }
public ushort PortalID { get { return _RawData.PortalID; } set { _RawData.PortalID = value; } }
public byte PortalUnk { get { return _RawData.PortalUnk; } set { _RawData.PortalUnk = value; } }
public byte Flags1 { get { return (byte)(_RawData.Unknown_00h & 0xFF); } set { _RawData.Unknown_00h = (ushort)((_RawData.Unknown_00h & 0xFF00) | (value & 0xFF)); } }
public byte Flags2 { get { return (byte)((_RawData.Unknown_24h.Value >> 0) & 0xFF); } set { _RawData.Unknown_24h = ((_RawData.Unknown_24h.Value & 0xFFFFFF00u) | ((value & 0xFFu) << 0)); } }
public byte Flags3 { get { return (byte)((_RawData.Unknown_24h.Value >> 9) & 0xFF); } set { _RawData.Unknown_24h = ((_RawData.Unknown_24h.Value & 0xFFFE01FFu) | ((value & 0xFFu) << 9)); } }
public byte Flags4 { get { return (byte)((_RawData.Unknown_28h.Value >> 16) & 0xFF); } set { _RawData.Unknown_28h = ((_RawData.Unknown_28h.Value & 0x0000FFFFu) | ((value & 0xFFu) << 16)); } }
public bool B00_AvoidUnk { get { return (_RawData.Unknown_00h & 1) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 0, value); } }
public bool B01_AvoidUnk { get { return (_RawData.Unknown_00h & 2) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 1, value); } }
public bool B02_IsFootpath { get { return (_RawData.Unknown_00h & 4) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 2, value); } }
public bool B03_IsUnderground { get { return (_RawData.Unknown_00h & 8) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 3, value); } }
//public bool B04_Unused { get { return (_RawData.Unknown_00h & 16) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 4, value); } }
//public bool B05_Unused { get { return (_RawData.Unknown_00h & 32) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 5, value); } }
public bool B06_SteepSlope { get { return (_RawData.Unknown_00h & 64) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 6, value); } }
public bool B07_IsWater { get { return (_RawData.Unknown_00h & 128) > 0; } set { _RawData.Unknown_00h = (ushort)BitUtil.UpdateBit(_RawData.Unknown_00h, 7, value); } }
public bool B08_UndergroundUnk0 { get { return (_RawData.Unknown_24h.Value & 1) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 0, value); } }
public bool B09_UndergroundUnk1 { get { return (_RawData.Unknown_24h.Value & 2) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 1, value); } }
public bool B10_UndergroundUnk2 { get { return (_RawData.Unknown_24h.Value & 4) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 2, value); } }
public bool B11_UndergroundUnk3 { get { return (_RawData.Unknown_24h.Value & 8) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 3, value); } }
//public bool B12_Unused { get { return (_RawData.Unknown_24h.Value & 16) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 4, value); } }
public bool B13_HasPathNode { get { return (_RawData.Unknown_24h.Value & 32) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 5, value); } }
public bool B14_IsInterior { get { return (_RawData.Unknown_24h.Value & 64) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 6, value); } }
public bool B15_InteractionUnk { get { return (_RawData.Unknown_24h.Value & 128) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 7, value); } }
//public bool B16_Unused { get { return (_RawData.Unknown_24h.Value & 256) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 8, value); } }
public bool B17_IsFlatGround { get { return (_RawData.Unknown_24h.Value & 512) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 9, value); } }
public bool B18_IsRoad { get { return (_RawData.Unknown_24h.Value & 1024) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 10, value); } }
public bool B19_IsCellEdge { get { return (_RawData.Unknown_24h.Value & 2048) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 11, value); } }
public bool B20_IsTrainTrack { get { return (_RawData.Unknown_24h.Value & 4096) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 12, value); } }
public bool B21_IsShallowWater { get { return (_RawData.Unknown_24h.Value & 8192) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 13, value); } }
public bool B22_FootpathUnk1 { get { return (_RawData.Unknown_24h.Value & 16384) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 14, value); } }
public bool B23_FootpathUnk2 { get { return (_RawData.Unknown_24h.Value & 32768) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 15, value); } }
public bool B24_FootpathMall { get { return (_RawData.Unknown_24h.Value & 65536) > 0; } set { _RawData.Unknown_24h = BitUtil.UpdateBit(_RawData.Unknown_24h.Value, 16, value); } }
public bool B25_SlopeSouth { get { return (_RawData.Unknown_28h.Value & 65536) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 16, value); } }
public bool B26_SlopeSouthEast { get { return (_RawData.Unknown_28h.Value & 131072) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 17, value); } }
public bool B27_SlopeEast { get { return (_RawData.Unknown_28h.Value & 262144) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 18, value); } }
public bool B28_SlopeNorthEast { get { return (_RawData.Unknown_28h.Value & 524288) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 19, value); } }
public bool B29_SlopeNorth { get { return (_RawData.Unknown_28h.Value & 1048576) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 20, value); } }
public bool B30_SlopeNorthWest { get { return (_RawData.Unknown_28h.Value & 2097152) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 21, value); } }
public bool B31_SlopeWest { get { return (_RawData.Unknown_28h.Value & 4194304) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 22, value); } }
public bool B32_SlopeSouthWest { get { return (_RawData.Unknown_28h.Value & 8388608) > 0; } set { _RawData.Unknown_28h = BitUtil.UpdateBit(_RawData.Unknown_28h.Value, 23, value); } }
//public bool B33_PortalUnk1 { get { return (_RawData.PortalUnk & 1) > 0; } }
//public bool B34_PortalUnk2 { get { return (_RawData.PortalUnk & 2) > 0; } }
//public bool B35_PortalUnk3 { get { return (_RawData.PortalUnk & 4) > 0; } }
//public bool B36_PortalUnk4 { get { return (_RawData.PortalUnk & 8) > 0; } }
public byte UnkX { get { return _RawData.Unknown_28h_8a; } set { _RawData.Unknown_28h_8a = value; } }
public byte UnkY { get { return _RawData.Unknown_28h_8b; } set { _RawData.Unknown_28h_8b = value; } }
public Vector3 Position { get; set; }
public int Index { get; set; }
public void Init(YnvFile ynv, NavMeshPoly poly)
{
Ynv = ynv;
RawData = poly;
}
public void SetPosition(Vector3 pos)
{
Vector3 delta = pos - Position;
Position = pos;
//TODO: update vertex positions!!!
}
public Color4 GetColour()
{
var colour = new Color4();
var u0 = _RawData.Unknown_00h;
if ((u0 & 1) > 0) colour.Red += 0.01f;//avoid? loiter?
if ((u0 & 2) > 0) colour.Red += 0.01f; //avoid?
if ((u0 & 4) > 0) colour.Green += 0.25f; //ped/footpath
if ((u0 & 8) > 0) colour.Green += 0.02f; //underground?
////if ((u0 & 16) > 0) colour.Red += 1.0f; //not used?
////if ((u0 & 32) > 0) colour.Green += 1.0f;//not used?
if ((u0 & 64) > 0) colour.Red += 0.25f; //steep slope
if ((u0 & 128) > 0) colour.Blue += 0.25f; //water
//if (u0 >= 256) colour.Green += 1.0f;//other bits unused...
var u2 = _RawData.Unknown_24h.Value;
//colour.Green = (u2 & 15) / 15.0f; //maybe underground amount..?
//if ((u2 & 1) > 0) colour.Blue += 1.0f; //peds interact with something? underground?
//if ((u2 & 2) > 0) colour.Green += 1.0f;//underneath something?
//if ((u2 & 4) > 0) colour.Red += 0.5f;//peds interact with something..? underground?
//if ((u2 & 8) > 0) colour.Red += 0.5f; //underground?
//if ((u2 & 16) > 0) colour.Red += 1.0f; //not used..
//if ((u2 & 32) > 0) colour.Green += 1.0f;//use path node?
if ((u2 & 64) > 0) colour.Blue += 0.1f; //is interior?
//if ((u2 & 128) > 0) colour.Red += 1.0f; //interacting areas? veg branches, roofs, vents, worker areas?
//if ((u2 & 256) > 0) colour.Green += 1.0f; //not used?
if ((u2 & 512) > 0) colour.Green += 0.1f;//is flat ground? ped-navigable?
if ((u2 & 1024) > 0) colour.Blue += 0.03f;//is a road
//if ((u2 & 2048) > 0) colour.Green += 1.0f; //poly is on a cell edge
if ((u2 & 4096) > 0) colour.Green += 0.75f; //is a train track
if ((u2 & 8192) > 0) colour.Blue += 0.75f;//shallow water/moving water
if ((u2 & 16384) > 0) colour.Red += 0.2f; //footpaths/beach - peds walking?
if ((u2 & 32768) > 0) colour.Blue += 0.2f; //footpaths - special?
if ((u2 & 65536) > 0) colour.Green = 0.2f;//footpaths - mall areas? eg mall, vinewood blvd
//if (u2 >= 131072) { }//other bits unused
var u5 = _RawData.Unknown_28h.Value; //32 bits
//colour.Red = poly.Unknown_28h_8a / 255.0f; //heuristic vals..?
//colour.Green = poly.Unknown_28h_8b / 255.0f; //heuristic vals..?
//if ((u5 & 65536) > 0) colour.Red += 1.0f; //slope facing -Y (south)
//if ((u5 & 131072) > 0) colour.Blue += 1.0f; //slope facing +X,-Y (southeast)
//if ((u5 & 262144) > 0) colour.Green += 1.0f; //slope facing +X (east)
//if ((u5 & 524288) > 0) colour.Red += 1.0f; //slope facing +X,+Y (northeast)
//if ((u5 & 1048576) > 0) colour.Green += 1.0f; //slope facing +Y (north)
//if ((u5 & 2097152) > 0) colour.Blue += 1.0f; //slope facing -X,+Y (northwest)
//if ((u5 & 4194304) > 0) colour.Green += 1.0f; //slope facing -X (west)
//if ((u5 & 8388608) > 0) colour.Red += 1.0f; //slope facing -X,-Y (southwest)
//if (u5 >= 16777216) { } //other bits unused
var u1 = _RawData.PortalUnk;
//if ((u1 & 1) > 0) colour.Red += 1.0f; //portal - don't interact?
//if ((u1 & 2) > 0) colour.Green += 1.0f; //portal - ladder/fence interaction?
//if ((u1 & 4) > 0) colour.Blue += 1.0f; //portal - fence interaction / go away from?
//if ((u1 & 8) > 0) colour.Red += 1.0f;//something file-specific? portal index related?
colour.Alpha = 0.75f;
return colour;
}
public void CalculatePosition()
{
//calc poly center for display purposes.
var indices = Ynv.Indices;
var vertices = Ynv.Vertices;
if ((indices == null) || (vertices == null))
{ return; }
var vc = vertices.Count;
var ic = _RawData.IndexCount;
var startid = _RawData.IndexID;
var endid = startid + ic;
if (startid >= indices.Count)
{ return; }
if (endid > indices.Count)
{ return; }
Vector3 pcenter = Vector3.Zero;
float pcount = 0.0f;
for (int id = startid; id < endid; id++)
{
var ind = indices[id];
if (ind >= vc)
{ continue; }
pcenter += vertices[ind];
pcount += 1.0f;
}
Position = pcenter * (1.0f / pcount);
}
public override string ToString()
{
return AreaID.ToString() + ", " + Index.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPortal : BasePathNode
{
public NavMeshPortal _RawData;
public YnvFile Ynv { get; set; }
public NavMeshPortal RawData { get { return _RawData; } set { _RawData = value; } }
public Vector3 Position { get { return Position1; } set { Position1 = value; } }
public Vector3 Position1 { get; set; }
public Vector3 Position2 { get; set; }
public int Index { get; set; }
public void Init(YnvFile ynv, NavMeshPortal portal)
{
Ynv = ynv;
RawData = portal;
}
public void SetPosition(Vector3 pos)
{
Position = pos;
//TODO: update _RawData positions!
}
public override string ToString()
{
return Index.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class YnvPoint : BasePathNode
{
public NavMeshPoint _RawData;
public YnvFile Ynv { get; set; }
public NavMeshPoint RawData { get { return _RawData; } set { _RawData = value; } }
public Vector3 Position { get; set; }
public float Direction
{
get
{
return (float)Math.PI * 2.0f * _RawData.Angle / 255.0f;
}
set
{
_RawData.Angle = (byte)(value * 255.0f / ((float)Math.PI * 2.0f));
}
}
public Quaternion Orientation
{
get { return Quaternion.RotationAxis(Vector3.UnitZ, Direction); }
set
{
Vector3 dir = value.Multiply(Vector3.UnitX);
float dira = (float)Math.Atan2(dir.Y, dir.X);
Direction = dira;
}
}
public int Index { get; set; }
public byte Flags { get { return _RawData.Flags; } set { _RawData.Flags = value; } }
public void Init(YnvFile ynv, NavMeshPoint point)
{
Ynv = ynv;
RawData = point;
}
public void SetPosition(Vector3 pos)
{
Position = pos;
//TODO! update _RawData.Position!!!
}
public void SetOrientation(Quaternion orientation)
{
Orientation = orientation;
}
public override string ToString()
{
return Index.ToString() + ": " + Flags.ToString();
}
}
}

View File

@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YptFile : GameFile, PackedFile
{
public ParticleEffectsList PtfxList { get; set; }
public Dictionary<uint, Drawable> DrawableDict { get; set; }
public string ErrorMessage { get; set; }
public YptFile() : base(null, GameFileType.Ypt)
{
}
public YptFile(RpfFileEntry entry) : base(entry, GameFileType.Ypt)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
//MemoryUsage = 0;
try
{
PtfxList = rd.ReadBlock<ParticleEffectsList>();
//Drawable.Owner = this;
//MemoryUsage += Drawable.MemoryUsage; //uses decompressed filesize now...
}
catch (Exception ex)
{
ErrorMessage = ex.ToString();
}
var dDict = PtfxList?.DrawableDictionary;
if ((dDict != null) &&
(dDict.Drawables != null) &&
(dDict.Drawables.data_items != null) &&
(dDict.Hashes != null))
{
DrawableDict = new Dictionary<uint, Drawable>();
var drawables = dDict.Drawables.data_items;
var hashes = dDict.Hashes;
for (int i = 0; (i < drawables.Length) && (i < hashes.Length); i++)
{
var drawable = drawables[i];
var hash = hashes[i];
DrawableDict[hash] = drawable;
drawable.Owner = this;
}
for (int i = 0; (i < drawables.Length) && (i < hashes.Length); i++)
{
var drawable = drawables[i];
var hash = hashes[i];
if ((drawable.Name == null) || (drawable.Name.EndsWith("#dd")))
{
string hstr = JenkIndex.TryGetString(hash);
if (!string.IsNullOrEmpty(hstr))
{
drawable.Name = hstr;
}
else
{
drawable.Name = "0x" + hash.ToString("X").PadLeft(8, '0');
}
}
}
}
Loaded = true;
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YtdFile : GameFile, PackedFile
{
public TextureDictionary TextureDict { get; set; }
public YtdFile() : base(null, GameFileType.Ytd)
{
}
public YtdFile(RpfFileEntry entry) : base(entry, GameFileType.Ytd)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
TextureDict = rd.ReadBlock<TextureDictionary>();
//MemoryUsage = 0; //uses decompressed file size now..
//if (TextureDict != null)
//{
// MemoryUsage += TextureDict.MemoryUsage;
//}
}
}
}

View File

@ -0,0 +1,253 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))]
public class YtypFile : GameFile, PackedFile
{
public Meta Meta { get; set; }
public PsoFile Pso { get; set; }
public RbfFile Rbf { get; set; }
public uint NameHash { get; set; }
public string[] Strings { get; set; }
public CMapTypes CMapTypes { get; set; }
public Archetype[] AllArchetypes { get; set; }
public MetaWrapper[] Extensions { get; set; }
public CCompositeEntityType[] CompositeEntityTypes { get; set; }
//fields used by the editor:
public bool HasChanged { get; set; } = false;
public List<string> SaveWarnings = null;
public YtypFile() : base(null, GameFileType.Ytyp)
{
}
public YtypFile(RpfFileEntry entry) : base(entry, GameFileType.Ytyp)
{
}
public override string ToString()
{
return (RpfFileEntry != null) ? RpfFileEntry.Name : string.Empty;
}
public void Load(byte[] data)
{
//direct load from a raw, compressed ytyp file (openIV-compatible format)
RpfFile.LoadResourceFile(this, data, 2);
Loaded = true;
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
MemoryStream ms = new MemoryStream(data);
if (RbfFile.IsRBF(ms))
{
Rbf = new RbfFile();
Rbf.Load(ms);
}
else if (PsoFile.IsPSO(ms))
{
Pso = new PsoFile();
Pso.Load(ms);
//PsoTypes.EnsurePsoTypes(Pso);
}
else
{
}
return;
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
Meta = rd.ReadBlock<Meta>();
CMapTypes = MetaTypes.GetTypedData<CMapTypes>(Meta, MetaName.CMapTypes);
List<Archetype> allarchs = new List<Archetype>();
var ptrs = MetaTypes.GetPointerArray(Meta, CMapTypes.archetypes);
if (ptrs != null)
{
for (int i = 0; i < ptrs.Length; i++)
{
var ptr = ptrs[i];
var offset = ptr.Offset;
var block = Meta.GetBlock(ptr.BlockID);
if (block == null)
{ continue; }
if ((offset < 0) || (block.Data == null) || (offset >= block.Data.Length))
{ continue; }
Archetype a = null;
switch (block.StructureNameHash)
{
case MetaName.CBaseArchetypeDef:
var basearch = PsoTypes.ConvertDataRaw<CBaseArchetypeDef>(block.Data, offset);
a = new Archetype();
a.Init(this, ref basearch);
a.Extensions = MetaTypes.GetExtensions(Meta, basearch.extensions);
break;
case MetaName.CTimeArchetypeDef:
var timearch = PsoTypes.ConvertDataRaw<CTimeArchetypeDef>(block.Data, offset);
var ta = new TimeArchetype();
ta.Init(this, ref timearch);
ta.Extensions = MetaTypes.GetExtensions(Meta, timearch._BaseArchetypeDef.extensions);
a = ta;
break;
case MetaName.CMloArchetypeDef:
var mloarch = PsoTypes.ConvertDataRaw<CMloArchetypeDef>(block.Data, offset);
var ma = new MloArchetype();
ma.Init(this, ref mloarch);
ma.Extensions = MetaTypes.GetExtensions(Meta, mloarch._BaseArchetypeDef.extensions);
ma.LoadChildren(Meta);
a = ma;
break;
default:
continue;
}
if (a != null)
{
allarchs.Add(a);
}
}
}
AllArchetypes = allarchs.ToArray();
Extensions = MetaTypes.GetExtensions(Meta, CMapTypes.extensions);
if (Extensions != null)
{ }
//AudioEmitters = MetaTypes.GetTypedDataArray<CExtensionDefAudioEmitter>(Meta, MetaName.CExtensionDefAudioEmitter);
//if (AudioEmitters != null)
//{ }
//CEntityDefs = MetaTypes.GetTypedDataArray<CEntityDef>(Meta, MetaName.CEntityDef);
CompositeEntityTypes = MetaTypes.ConvertDataArray<CCompositeEntityType>(Meta, MetaName.CCompositeEntityType, CMapTypes.compositeEntityTypes);
if (CompositeEntityTypes != null)
{ }
NameHash = CMapTypes.name;
if (NameHash == 0)
{
int ind = entry.NameLower.LastIndexOf('.');
if (ind > 0)
{
NameHash = JenkHash.GenHash(entry.NameLower.Substring(0, ind));
}
else
{
NameHash = JenkHash.GenHash(entry.NameLower);
}
}
Strings = MetaTypes.GetStrings(Meta);
if (Strings != null)
{
foreach (string str in Strings)
{
JenkIndex.Ensure(str); //just shove them in there
}
}
//foreach (var block in Meta.DataBlocks)
//{
// switch(block.StructureNameHash)
// {
// case MetaName.CMapTypes:
// case MetaName.CTimeArchetypeDef:
// case MetaName.CBaseArchetypeDef:
// case MetaName.CMloArchetypeDef:
// case MetaName.CMloTimeCycleModifier:
// case MetaName.CMloRoomDef:
// case MetaName.CMloPortalDef:
// case MetaName.CMloEntitySet:
// case MetaName.CEntityDef:
// case MetaName.CExtensionDefParticleEffect:
// case MetaName.CExtensionDefAudioCollisionSettings:
// case MetaName.CExtensionDefSpawnPoint:
// case MetaName.CExtensionDefSpawnPointOverride:
// case MetaName.CExtensionDefExplosionEffect:
// case MetaName.CExtensionDefAudioEmitter:
// case MetaName.CExtensionDefLadder:
// case MetaName.CExtensionDefBuoyancy:
// case MetaName.CExtensionDefExpression:
// case MetaName.CExtensionDefLightShaft:
// case MetaName.CExtensionDefLightEffect:
// case MetaName.CExtensionDefDoor:
// case MetaName.CExtensionDefWindDisturbance:
// case MetaName.CExtensionDefProcObject:
// case MetaName.CLightAttrDef:
// case MetaName.STRING:
// case MetaName.POINTER:
// case MetaName.UINT:
// case MetaName.VECTOR4:
// break;
// default:
// break;
// }
//}
//MetaTypes.ParseMetaData(Meta);
}
}
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YvrFile : GameFile, PackedFile
{
public VehicleRecordList Records { get; set; }
public YvrFile() : base(null, GameFileType.Yvr)
{
}
public YvrFile(RpfFileEntry entry) : base(entry, GameFileType.Yvr)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
//MemoryUsage = 0;
try
{
Records = rd.ReadBlock<VehicleRecordList>();
}
catch (Exception ex)
{
string err = ex.ToString();
}
Loaded = true;
}
}
}

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class YwrFile : GameFile, PackedFile
{
public WaypointRecordList Waypoints { get; set; }
public YwrFile() : base(null, GameFileType.Ywr)
{
}
public YwrFile(RpfFileEntry entry) : base(entry, GameFileType.Ywr)
{
}
public void Load(byte[] data, RpfFileEntry entry)
{
Name = entry.Name;
RpfFileEntry = entry;
RpfResourceFileEntry resentry = entry as RpfResourceFileEntry;
if (resentry == null)
{
throw new Exception("File entry wasn't a resource! (is it binary data?)");
}
ResourceDataReader rd = new ResourceDataReader(resentry, data);
//MemoryUsage = 0;
try
{
Waypoints = rd.ReadBlock<WaypointRecordList>();
}
catch (Exception ex)
{
string err = ex.ToString();
}
Loaded = true;
}
}
}

View File

@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public abstract class GameFile : Cacheable<GameFileCacheKey>
{
public volatile bool Loaded = false;
public volatile bool LoadQueued = false;
public RpfFileEntry RpfFileEntry { get; set; }
public string Name { get; set; }
public string FilePath { get; set; } //used by the project form.
public GameFileType Type { get; set; }
public GameFile(RpfFileEntry entry, GameFileType type)
{
RpfFileEntry = entry;
Type = type;
MemoryUsage = (entry != null) ? entry.GetFileSize() : 0;
if (entry is RpfResourceFileEntry)
{
var resent = entry as RpfResourceFileEntry;
var newuse = resent.SystemSize + resent.GraphicsSize;
MemoryUsage = newuse;
}
else if (entry is RpfBinaryFileEntry)
{
var binent = entry as RpfBinaryFileEntry;
var newuse = binent.FileUncompressedSize;
if (newuse > MemoryUsage)
{
MemoryUsage = newuse;
}
}
else
{
}
}
public override string ToString()
{
return (string.IsNullOrEmpty(Name)) ? JenkIndex.GetString(Key.Hash) : Name;
}
}
public enum GameFileType : int
{
Ydd = 0,
Ydr = 1,
Yft = 2,
Ymap = 3,
Ymf = 4,
Ymt = 5,
Ytd = 6,
Ytyp = 7,
Ybn = 8,
Ycd = 9,
Ypt = 10,
Ynd = 11,
Ynv = 12,
Rel = 13,
Ywr = 14,
Yvr = 15,
Gtxd = 16,
}
public struct GameFileCacheKey
{
public uint Hash { get; set; }
public GameFileType Type { get; set; }
public GameFileCacheKey(uint hash, GameFileType type)
{
Hash = hash;
Type = type;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,301 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))]
public class Archetype
{
public virtual MetaName Type => MetaName.CBaseArchetypeDef;
public CBaseArchetypeDef _BaseArchetypeDef;
public CBaseArchetypeDef BaseArchetypeDef { get { return _BaseArchetypeDef; } set { _BaseArchetypeDef = value; } }
public MetaHash Hash { get; set; }
public YtypFile Ytyp { get; set; }
public MetaHash DrawableDict { get; set; }
public MetaHash TextureDict { get; set; }
public MetaHash ClipDict { get; set; }
public Vector3 BBMin { get; set; }
public Vector3 BBMax { get; set; }
public Vector3 BSCenter { get; set; }
public float BSRadius { get; set; }
public float LodDist { get; set; }
public MetaWrapper[] Extensions { get; set; }
public string Name
{
get
{
return _BaseArchetypeDef.name.ToString();
}
}
public string AssetName
{
get
{
return _BaseArchetypeDef.assetName.ToString();
}
}
protected void InitVars(ref CBaseArchetypeDef arch)
{
BaseArchetypeDef = arch;
Hash = arch.assetName;
if (Hash.Hash == 0) Hash = arch.name;
DrawableDict = arch.drawableDictionary;
TextureDict = arch.textureDictionary;
ClipDict = arch.clipDictionary;
BBMin = arch.bbMin;
BBMax = arch.bbMax;
BSCenter = arch.bsCentre;
BSRadius = arch.bsRadius;
LodDist = arch.lodDist;
}
public void Init(YtypFile ytyp, ref CBaseArchetypeDef arch)
{
Ytyp = ytyp;
InitVars(ref arch);
}
public virtual bool IsActive(float hour)
{
return true;
}
public override string ToString()
{
return _BaseArchetypeDef.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class TimeArchetype : Archetype
{
public override MetaName Type => MetaName.CTimeArchetypeDef;
public CTimeArchetypeDefData _TimeArchetypeDef;
public CTimeArchetypeDefData TimeArchetypeDef { get { return _TimeArchetypeDef; } set { _TimeArchetypeDef = value; } }
public uint TimeFlags { get; set; }
public bool[] ActiveHours { get; set; }
public string[] ActiveHoursText { get; set; }
public bool ExtraFlag { get; set; }
public void Init(YtypFile ytyp, ref CTimeArchetypeDef arch)
{
Ytyp = ytyp;
InitVars(ref arch._BaseArchetypeDef);
TimeArchetypeDef = arch.TimeArchetypeDef;
TimeFlags = _TimeArchetypeDef.timeFlags;
ActiveHours = new bool[24];
ActiveHoursText = new string[24];
for (int i = 0; i < 24; i++)
{
bool v = ((TimeFlags >> i) & 1) == 1;
ActiveHours[i] = v;
int nxth = (i < 23) ? (i + 1) : 0;
string hrs = string.Format("{0:00}:00 - {1:00}:00", i, nxth);
ActiveHoursText[i] = (hrs + (v ? " - On" : " - Off"));
}
ExtraFlag = ((TimeFlags >> 24) & 1) == 1;
}
public override bool IsActive(float hour)
{
if (ActiveHours == null) return true;
int h = ((int)hour) % 24;
if ((h < 0) || (h > 23)) return true;
return ActiveHours[h];
}
}
public class MloArchetype : Archetype
{
public override MetaName Type => MetaName.CMloArchetypeDef;
public CMloArchetypeDefData _MloArchetypeDef;
public CMloArchetypeDefData MloArchetypeDef { get { return _MloArchetypeDef; } set { _MloArchetypeDef = value; } }
public MCEntityDef[] entities { get; set; }
public MCMloRoomDef[] rooms { get; set; }
public MCMloPortalDef[] portals { get; set; }
public MCMloEntitySet[] entitySets { get; set; }
public CMloTimeCycleModifier[] timeCycleModifiers { get; set; }
public void Init(YtypFile ytyp, ref CMloArchetypeDef arch)
{
Ytyp = ytyp;
InitVars(ref arch._BaseArchetypeDef);
MloArchetypeDef = arch.MloArchetypeDef;
}
public void LoadChildren(Meta meta)
{
var centities = MetaTypes.ConvertDataArray<CEntityDef>(meta, MetaName.CEntityDef, _MloArchetypeDef.entities);
if (centities != null)
{
entities = new MCEntityDef[centities.Length];
for (int i = 0; i < centities.Length; i++)
{
entities[i] = new MCEntityDef(meta, centities[i]);
}
}
var crooms = MetaTypes.ConvertDataArray<CMloRoomDef>(meta, MetaName.CMloRoomDef, _MloArchetypeDef.rooms);
if (crooms != null)
{
rooms = new MCMloRoomDef[crooms.Length];
for (int i = 0; i < crooms.Length; i++)
{
rooms[i] = new MCMloRoomDef(meta, crooms[i]);
}
}
var cportals = MetaTypes.ConvertDataArray<CMloPortalDef>(meta, MetaName.CMloPortalDef, _MloArchetypeDef.portals);
if (cportals != null)
{
portals = new MCMloPortalDef[cportals.Length];
for (int i = 0; i < cportals.Length; i++)
{
portals[i] = new MCMloPortalDef(meta, cportals[i]);
}
}
var centitySets = MetaTypes.ConvertDataArray<CMloEntitySet>(meta, MetaName.CMloEntitySet, _MloArchetypeDef.entitySets);
if (centitySets != null)
{
entitySets = new MCMloEntitySet[centitySets.Length];
for (int i = 0; i < centitySets.Length; i++)
{
entitySets[i] = new MCMloEntitySet(meta, centitySets[i]);
}
}
timeCycleModifiers = MetaTypes.ConvertDataArray<CMloTimeCycleModifier>(meta, MetaName.CMloTimeCycleModifier, _MloArchetypeDef.timeCycleModifiers);
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class MloInstanceData
{
public YmapEntityDef Owner { get; set; }
public CMloInstanceDef _Instance;
public CMloInstanceDef Instance { get { return _Instance; } set { _Instance = value; } }
public uint[] defaultEntitySets { get; set; }
public YmapEntityDef[] Entities { get; set; }
public void CreateYmapEntities(YmapEntityDef owner, MloArchetype mloa)
{
Owner = owner;
if (owner == null) return;
if (mloa.entities == null) return;
var ec = mloa.entities.Length;
var entlist = new List<YmapEntityDef>();
for (int i = 0; i < ec; i++)
{
YmapEntityDef e = CreateYmapEntity(owner, mloa.entities[i], i);
entlist.Add(e);
}
int lasti = ec;
var entitySets = mloa.entitySets;
if (entitySets != null)
{
for (int i = 0; i < entitySets.Length; i++)
{
var entitySet = entitySets[i];
if (entitySet.Entities != null)
{
for (int j = 0; j < entitySet.Entities.Length; j++)
{
YmapEntityDef e = CreateYmapEntity(owner, entitySet.Entities[j], lasti);
e.MloEntitySet = entitySet;
entlist.Add(e);
lasti++;
}
}
}
}
if (defaultEntitySets != null)
{
}
Entities = entlist.ToArray();
}
private YmapEntityDef CreateYmapEntity(YmapEntityDef owner, MCEntityDef ment, int i)
{
YmapEntityDef e = new YmapEntityDef(null, i, ref ment._Data);
e.Extensions = ment.Extensions;
e.MloRefPosition = e.Position;
e.MloRefOrientation = e.Orientation;
e.MloParent = owner;
e.Position = owner.Position + owner.Orientation.Multiply(e.MloRefPosition);
e.Orientation = Quaternion.Multiply(owner.Orientation, e.MloRefOrientation);
e.UpdateWidgetPosition();
e.UpdateWidgetOrientation();
return e;
}
public void SetPosition(Vector3 pos)
{
var cent = _Instance.CEntityDef;
cent.position = pos;
_Instance.CEntityDef = cent; //TODO: maybe find a better way of doing this...
}
public void SetOrientation(Quaternion ori)
{
var cent = _Instance.CEntityDef;
cent.rotation = new Vector4(ori.X, ori.Y, ori.Z, ori.W); //mlo instances have oppposite orientations to normal entities...
_Instance.CEntityDef = cent; //TODO: maybe find a better way of doing this...
}
public void UpdateEntities()
{
if (Entities == null) return;
if (Owner == null) return;
for (int i = 0; i < Entities.Length; i++)
{
YmapEntityDef e = Entities[i];
e.Position = Owner.Position + Owner.Orientation.Multiply(e.MloRefPosition);
e.Orientation = Quaternion.Multiply(Owner.Orientation, e.MloRefOrientation);
e.UpdateWidgetPosition();
e.UpdateWidgetOrientation();
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,447 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SharpDX;
namespace CodeWalker.GameFiles
{
public class MetaBuilder
{
List<MetaBuilderBlock> Blocks = new List<MetaBuilderBlock>();
int MaxBlockLength = 0x4000; //TODO: figure what this should be!
public MetaBuilderBlock EnsureBlock(MetaName type)
{
foreach (var block in Blocks)
{
if (block.StructureNameHash == type)
{
if (block.TotalSize < MaxBlockLength)
{
return block;
}
}
}
MetaBuilderBlock b = new MetaBuilderBlock();
b.StructureNameHash = type;
b.Index = Blocks.Count;
Blocks.Add(b);
return b;
}
public MetaBuilderPointer AddItem<T>(MetaName type, T item) where T : struct
{
byte[] data = MetaTypes.ConvertToBytes(item);
return AddItem(type, data);
}
public MetaBuilderPointer AddItem(MetaName type, byte[] data)
{
MetaBuilderBlock block = EnsureBlock(type);
int brem = data.Length % 16;
if (brem > 0)
{
int newlen = data.Length - brem + 16;
byte[] newdata = new byte[newlen];
Buffer.BlockCopy(data, 0, newdata, 0, data.Length);
data = newdata; //make sure item size is multiple of 16... so pointers don't need sub offsets!
}
int idx = block.AddItem(data);
MetaBuilderPointer r = new MetaBuilderPointer();
r.BlockID = block.Index + 1;
r.Offset = (idx * data.Length);
r.Length = data.Length;
return r;
}
public MetaBuilderPointer AddItemArray<T>(MetaName type, T[] items) where T : struct
{
byte[] data = MetaTypes.ConvertArrayToBytes(items);
return AddItemArray(type, data, items.Length);
}
public MetaBuilderPointer AddItemArray(MetaName type, byte[] data, int length)
{
MetaBuilderBlock block = EnsureBlock(type);
int datalen = data.Length;
int newlen = datalen;
int lenrem = newlen % 16;
if (lenrem != 0)
{
newlen += (16 - lenrem);
}
byte[] newdata = new byte[newlen];
Buffer.BlockCopy(data, 0, newdata, 0, datalen);
int offs = block.TotalSize;
int idx = block.AddItem(newdata);
MetaBuilderPointer r = new MetaBuilderPointer();
r.BlockID = block.Index + 1;
r.Offset = offs; //(idx * data.Length);;
r.Length = length;
return r;
}
public MetaBuilderPointer AddString(string str)
{
MetaBuilderBlock block = EnsureBlock(MetaName.STRING);
byte[] data = Encoding.ASCII.GetBytes(str);
int datalen = data.Length;
int newlen = datalen;
int lenrem = newlen % 16;
if (lenrem != 0) //need to pad the data length up to multiple of 16.
{
newlen += (16 - lenrem);
}
byte[] newdata = new byte[newlen];
Buffer.BlockCopy(data, 0, newdata, 0, datalen);
int offs = block.TotalSize;
int idx = block.AddItem(newdata);
MetaBuilderPointer r = new MetaBuilderPointer();
r.BlockID = block.Index + 1;
r.Offset = offs;// (idx * data.Length);
r.Length = datalen; //actual length of string.
return r;
}
public MetaPOINTER AddItemPtr<T>(MetaName type, T item) where T : struct //helper method for AddItem<T>
{
var ptr = AddItem(type, item);
return new MetaPOINTER(ptr.BlockID, ptr.Offset, 0);
}
public MetaPOINTER AddItemPtr(MetaName type, byte[] data)//helper method for AddItem<T>
{
var ptr = AddItem(type, data);
return new MetaPOINTER(ptr.BlockID, ptr.Offset, 0);
}
public Array_Structure AddItemArrayPtr<T>(MetaName type, T[] items) where T : struct //helper method for AddItemArray<T>
{
if ((items == null) || (items.Length == 0)) return new Array_Structure();
var ptr = AddItemArray(type, items);
return new Array_Structure(ptr);
}
public Array_Structure AddItemArrayPtr(MetaName type, byte[][] data) //helper method for AddItemArray<T>
{
if ((data == null) || (data.Length == 0)) return new Array_Structure();
int len = 0;
for (int i = 0; i < data.Length; i++)
{
len += data[i].Length;
}
var newdata = new byte[len];
int offset = 0;
for (int i = 0; i < data.Length; i++)
{
Buffer.BlockCopy(data[i], 0, newdata, offset, data[i].Length);
offset += data[i].Length;
}
var ptr = AddItemArray(type, newdata, data.Length);
return new Array_Structure(ptr);
}
public Array_Vector3 AddPaddedVector3ArrayPtr(Vector4[] items)
{
if ((items == null) || (items.Length == 0)) return new Array_Vector3();
var ptr = AddItemArray(MetaName.VECTOR4, items); //padded to vec4...
return new Array_Vector3(ptr);
}
public Array_uint AddHashArrayPtr(MetaHash[] items)
{
if ((items == null) || (items.Length == 0)) return new Array_uint();
var ptr = AddItemArray(MetaName.HASH, items);
return new Array_uint(ptr);
}
public Array_uint AddUintArrayPtr(uint[] items)
{
if ((items == null) || (items.Length == 0)) return new Array_uint();
var ptr = AddItemArray(MetaName.UINT, items);
return new Array_uint(ptr);
}
public Array_ushort AddUshortArrayPtr(ushort[] items)
{
if ((items == null) || (items.Length == 0)) return new Array_ushort();
var ptr = AddItemArray(MetaName.USHORT, items);
return new Array_ushort(ptr);
}
public Array_byte AddByteArrayPtr(byte[] items)
{
if ((items == null) || (items.Length == 0)) return new Array_byte();
var ptr = AddItemArray(MetaName.BYTE, items);
return new Array_byte(ptr);
}
public Array_float AddFloatArrayPtr(float[] items)
{
if ((items == null) || (items.Length == 0)) return new Array_float();
var ptr = AddItemArray(MetaName.FLOAT, items);
return new Array_float(ptr);
}
public CharPointer AddStringPtr(string str) //helper method for AddString
{
var ptr = AddString(str);
return new CharPointer(ptr);
}
public Array_StructurePointer AddPointerArray(MetaPOINTER[] arr)
{
if ((arr == null) || (arr.Length == 0)) return new Array_StructurePointer();
var ptr = AddItemArray(MetaName.POINTER, arr);
Array_StructurePointer sp = new Array_StructurePointer();
sp.Count1 = (ushort)arr.Length;
sp.Count2 = sp.Count1;
sp.Pointer = ptr.Pointer;
return sp;
}
public Array_StructurePointer AddItemPointerArrayPtr<T>(MetaName type, T[] items) where T : struct
{
//helper method for creating a pointer array
if ((items == null) || (items.Length == 0)) return new Array_StructurePointer();
MetaPOINTER[] ptrs = new MetaPOINTER[items.Length];
for (int i = 0; i < items.Length; i++)
{
ptrs[i] = AddItemPtr(type, items[i]);
}
return AddPointerArray(ptrs);
//Array_StructurePointer sp = new Array_StructurePointer();
//sp.Count1 = (ushort)items.Length;
//sp.Count2 = sp.Count1;
//for (int i = 0; i < items.Length; i++)
//{
// var item = items[i];
// var meptr = AddItemPtr(type, item);
// var mptr = AddItem(MetaName.POINTER, meptr);
// if (i == 0)
// {
// sp.Pointer = mptr.Pointer; //main pointer points to the first item.
// }
//}
//return sp;
}
public Array_StructurePointer AddWrapperArrayPtr(MetaWrapper[] items)
{
if ((items == null) || (items.Length == 0)) return new Array_StructurePointer();
MetaPOINTER[] ptrs = new MetaPOINTER[items.Length];
for (int i = 0; i < items.Length; i++)
{
ptrs[i] = items[i].Save(this);
}
return AddPointerArray(ptrs);
//Array_StructurePointer sp = new Array_StructurePointer();
//sp.Count1 = (ushort)items.Length;
//sp.Count2 = sp.Count1;
//for (int i = 0; i < items.Length; i++)
//{
// var item = items[i];
// var meptr = item.Save(this);
// var mptr = AddItem(MetaName.POINTER, meptr);
// if (i == 0)
// {
// sp.Pointer = mptr.Pointer; //main pointer points to the first item.
// }
//}
//return sp;
}
public Array_Structure AddWrapperArray(MetaWrapper[] items)
{
if ((items == null) || (items.Length == 0)) return new Array_Structure();
var sa = new Array_Structure();
sa.Count1 = (ushort)items.Length;
sa.Count2 = sa.Count1;
for (int i = 0; i < items.Length; i++)
{
var item = items[i];
var meptr = item.Save(this);
if (i == 0)
{
MetaBuilderPointer mbp = new MetaBuilderPointer();
mbp.BlockID = meptr.BlockID;
mbp.Offset = meptr.Offset;
sa.Pointer = mbp.Pointer;
}
}
return sa;
}
public byte[] GetData()
{
int totlen = 0;
for (int i = 0; i < Blocks.Count; i++)
{
totlen += Blocks[i].TotalSize;
}
byte[] data = new byte[totlen];
int offset = 0;
for (int i = 0; i < Blocks.Count; i++)
{
var block = Blocks[i];
for (int j = 0; j < block.Items.Count; j++)
{
var bdata = block.Items[j];
Buffer.BlockCopy(bdata, 0, data, offset, bdata.Length);
offset += bdata.Length;
}
}
if (offset != data.Length)
{ }
return data;
}
Dictionary<MetaName, MetaStructureInfo> StructureInfos = new Dictionary<MetaName, MetaStructureInfo>();
Dictionary<MetaName, MetaEnumInfo> EnumInfos = new Dictionary<MetaName, MetaEnumInfo>();
public void AddStructureInfo(MetaName name)
{
if (!StructureInfos.ContainsKey(name))
{
MetaStructureInfo si = MetaTypes.GetStructureInfo(name);
if (si != null)
{
StructureInfos[name] = si;
}
}
}
public void AddEnumInfo(MetaName name)
{
if (!EnumInfos.ContainsKey(name))
{
MetaEnumInfo ei = MetaTypes.GetEnumInfo(name);
if (ei != null)
{
EnumInfos[name] = ei;
}
}
}
public Meta GetMeta()
{
Meta m = new Meta();
m.FileVFT = 0x405bc808;
m.FileUnknown = 1;
m.Unknown_10h = 0x50524430;
m.Unknown_14h = 0x0079;
m.RootBlockIndex = 1; //assume first block is root. todo: make adjustable?
m.StructureInfos = new ResourceSimpleArray<MetaStructureInfo>();
foreach (var si in StructureInfos.Values)
{
m.StructureInfos.Add(si);
}
m.StructureInfosCount = (short)m.StructureInfos.Count;
m.EnumInfos = new ResourceSimpleArray<MetaEnumInfo>();
foreach (var ei in EnumInfos.Values)
{
m.EnumInfos.Add(ei);
}
m.EnumInfosCount = (short)m.EnumInfos.Count;
m.DataBlocks = new ResourceSimpleArray<MetaDataBlock>();
foreach (var bb in Blocks)
{
m.DataBlocks.Add(bb.GetMetaDataBlock());
}
m.DataBlocksCount = (short)m.DataBlocks.Count;
return m;
}
}
public class MetaBuilderBlock
{
public MetaName StructureNameHash { get; set; }
public List<byte[]> Items { get; set; } = new List<byte[]>();
public int TotalSize { get; set; } = 0;
public int Index { get; set; } = 0;
public int AddItem(byte[] item)
{
int idx = Items.Count;
Items.Add(item);
TotalSize += item.Length;
return idx;
}
public uint BasePointer
{
get
{
return (((uint)Index + 1) & 0xFFF);
}
}
public MetaDataBlock GetMetaDataBlock()
{
if (TotalSize <= 0) return null;
byte[] data = new byte[TotalSize];
int offset = 0;
for (int j = 0; j < Items.Count; j++)
{
var bdata = Items[j];
Buffer.BlockCopy(bdata, 0, data, offset, bdata.Length);
offset += bdata.Length;
}
MetaDataBlock db = new MetaDataBlock();
db.StructureNameHash = StructureNameHash;
db.DataLength = TotalSize;
db.Data = data;
return db;
}
}
public struct MetaBuilderPointer
{
public int BlockID { get; set; } //1-based id
public int Offset { get; set; } //byte offset
public int Length { get; set; } //for temp use...
public uint Pointer
{
get
{
uint bidx = (((uint)BlockID) & 0xFFF);
uint offs = (((uint)Offset) & 0xFFFFF) << 12;
return bidx + offs;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,858 @@
/*
Copyright(c) 2015 Neodymium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
//shamelessly stolen and mangled
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public enum PsoSection : uint
{
PSIN = 0x5053494E,
PMAP = 0x504D4150,
PSCH = 0x50534348,
PSIG = 0x50534947,
STRF = 0x53545246,
STRS = 0x53545253,
STRE = 0x53545245,
CHKS = 0x43484B53,
}
public enum PsoDataType : byte
{
Bool = 0x00,
SByte = 0x01,
UByte = 0x02,
SShort = 0x03,
UShort = 0x04,
SInt = 0x05,
UInt = 0x06,
Float = 0x07,
Float2 = 0x08,
Float3 = 0x09,
Float4 = 0x0a,
String = 0x0b,
Structure = 0x0c,
Array = 0x0d,
Enum = 0x0e,
Flags = 0x0f,
Map = 0x10,
Float3a = 0x14,
Float4a = 0x15,
HFloat = 0x1e,
Long = 0x20,
}
public static class PsoDataTypes
{
public static string GetCSharpTypeName(PsoDataType t)
{
switch (t)
{
case PsoDataType.Bool: return "bool";
case PsoDataType.SByte: return "sbyte";
case PsoDataType.UByte: return "byte";
case PsoDataType.SShort: return "short";
case PsoDataType.UShort: return "ushort";
case PsoDataType.SInt: return "int";
case PsoDataType.UInt: return "int";
case PsoDataType.Float: return "float";
case PsoDataType.Float2: return "long";
case PsoDataType.String: return "uint"; //hash? NEEDS WORK?
case PsoDataType.Enum: return "byte";
case PsoDataType.Flags: return "short";
case PsoDataType.HFloat: return "short";
case PsoDataType.Long: return "long";
case PsoDataType.Float3:
case PsoDataType.Float4:
case PsoDataType.Map:
case PsoDataType.Float3a:
case PsoDataType.Float4a:
case PsoDataType.Structure:
case PsoDataType.Array:
default:
return t.ToString();
}
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoFile
{
public PsoDataSection DataSection { get; set; }
public PsoDataMapSection DataMapSection { get; set; }
public PsoSchemaSection SchemaSection { get; set; }
public PsoSTRFSection STRFSection { get; set; }
public PsoSTRSSection STRSSection { get; set; }
public PsoPSIGSection PSIGSection { get; set; }
public PsoSTRESection STRESection { get; set; }
public PsoCHKSSection CHKSSection { get; set; }
public void Load(string fileName)
{
using (var stream = new FileStream(fileName, FileMode.Open))
Load(stream);
}
public virtual void Load(Stream stream)
{
stream.Position = 0;
var reader = new DataReader(stream, Endianess.BigEndian);
while (reader.Position < reader.Length)
{
var identInt = reader.ReadUInt32();
var ident = (PsoSection)identInt;
var length = reader.ReadInt32();
reader.Position -= 8;
var sectionData = reader.ReadBytes(length);
var sectionStream = new MemoryStream(sectionData);
var sectionReader = new DataReader(sectionStream, Endianess.BigEndian);
switch (ident)
{
case PsoSection.PSIN: //0x5053494E "PSIN" - ID / data section
DataSection = new PsoDataSection();
DataSection.Read(sectionReader);
break;
case PsoSection.PMAP: //0x504D4150 "PMAP" //data mapping
DataMapSection = new PsoDataMapSection();
DataMapSection.Read(sectionReader);
break;
case PsoSection.PSCH: //0x50534348 "PSCH" //schema
SchemaSection = new PsoSchemaSection();
SchemaSection.Read(sectionReader);
break;
case PsoSection.STRF: //0x53545246 "STRF" //paths/STRINGS (folder strings?)
STRFSection = new PsoSTRFSection();
STRFSection.Read(sectionReader);
break;
case PsoSection.STRS: //0x53545253 "STRS" //names/strings (DES_)
STRSSection = new PsoSTRSSection();
STRSSection.Read(sectionReader);
break;
case PsoSection.STRE: //0x53545245 "STRE" //probably encrypted strings.....
STRESection = new PsoSTRESection();
STRESection.Read(sectionReader);
break;
case PsoSection.PSIG: //0x50534947 "PSIG" //signature?
PSIGSection = new PsoPSIGSection();
PSIGSection.Read(sectionReader);
break;
case PsoSection.CHKS: //0x43484B53 "CHKS" //checksum?
CHKSSection = new PsoCHKSSection();
CHKSSection.Read(sectionReader);
break;
default:
break;
}
}
}
public void Save(string fileName)
{
using (var stream = new FileStream(fileName, FileMode.Create))
Save(stream);
}
public virtual void Save(Stream stream)
{
var writer = new DataWriter(stream, Endianess.BigEndian);
if (DataSection != null) DataSection.Write(writer);
if (DataMapSection != null) DataMapSection.Write(writer);
if (SchemaSection != null) SchemaSection.Write(writer);
}
public PsoDataMappingEntry GetBlock(int id)
{
if (DataMapSection == null) return null;
if (DataMapSection.Entries == null) return null;
PsoDataMappingEntry block = null;
var ind = id - 1;
var blocks = DataMapSection.Entries;
if ((ind >= 0) && (ind < blocks.Length))
{
block = blocks[ind];
}
return block;
}
public static bool IsPSO(Stream stream)
{
//return !IsRBF(stream);
//1347635534
var reader = new DataReader(stream, Endianess.BigEndian);
var identInt = reader.ReadUInt32();
stream.Position = 0;
return ((identInt ) == 1347635534); //"PSIN"
}
public static bool IsRBF(Stream stream)
{
var reader = new DataReader(stream, Endianess.BigEndian);
var identInt = reader.ReadUInt32();
stream.Position = 0;
return ((identInt & 0xFFFFFF00) == 0x52424600);
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoDataSection
{
public uint Ident { get; set; } = 0x5053494E;
public int Length { get; private set; }
public byte[] Data { get; set; }
public void Read(DataReader reader)
{
Ident = reader.ReadUInt32();
Length = reader.ReadInt32();
reader.Position -= 8;
Data = reader.ReadBytes(Length);
}
public void Write(DataWriter writer)
{
writer.Write(Data);
writer.Position -= Data.Length;
writer.Write((uint)0x5053494E);
writer.Write((uint)(Data.Length));
writer.Position += Data.Length - 8;
}
public override string ToString()
{
return Ident.ToString() + ": " + Length.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoDataMapSection
{
public int Ident { get; set; } = 0x504D4150;
public int Length { get; private set; }
public int RootId { get; set; }
public short EntriesCount { get; private set; }
public short Unknown_Eh { get; set; } = 0x7070;
public PsoDataMappingEntry[] Entries { get; set; }
public void Read(DataReader reader)
{
Ident = reader.ReadInt32();
Length = reader.ReadInt32();
RootId = reader.ReadInt32();
EntriesCount = reader.ReadInt16();
Unknown_Eh = reader.ReadInt16();
Entries = new PsoDataMappingEntry[EntriesCount];
for (int i = 0; i < EntriesCount; i++)
{
var entry = new PsoDataMappingEntry();
entry.Read(reader);
Entries[i] = entry;
}
}
public void Write(DataWriter writer)
{
// update...
EntriesCount = (short)Entries.Length;
Length = 16 + EntriesCount * 16;
writer.Write(Ident);
writer.Write(Length);
writer.Write(RootId);
writer.Write(EntriesCount);
writer.Write(Unknown_Eh);
foreach (var entry in Entries)
{
entry.Write(writer);
}
}
public override string ToString()
{
return Ident.ToString() + ": " + EntriesCount.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoDataMappingEntry
{
public MetaName NameHash { get; set; }
public int Offset { get; set; }
public int Unknown_8h { get; set; } = 0x00000000;
public int Length { get; set; }
public void Read(DataReader reader)
{
this.NameHash = (MetaName)reader.ReadUInt32();
this.Offset = reader.ReadInt32();
this.Unknown_8h = reader.ReadInt32();
this.Length = reader.ReadInt32();
}
public void Write(DataWriter writer)
{
writer.Write((uint)NameHash);
writer.Write(Offset);
writer.Write(Unknown_8h);
writer.Write(Length);
}
public override string ToString()
{
return NameHash.ToString() + ": " + Offset.ToString() + ": " + Length.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoSchemaSection
{
public int Ident { get; private set; } = 0x50534348;
public int Length { get; set; }
public uint Count { get; set; }
public PsoElementIndexInfo[] EntriesIdx { get; set; }
public PsoElementInfo[] Entries { get; set; }
public void Read(DataReader reader)
{
Ident = reader.ReadInt32();
Length = reader.ReadInt32();
Count = reader.ReadUInt32();
this.EntriesIdx = new PsoElementIndexInfo[Count];
for (int i = 0; i < Count; i++)
{
var entry = new PsoElementIndexInfo();
entry.Read(reader);
EntriesIdx[i] = entry;
}
this.Entries = new PsoElementInfo[Count];
for (int i = 0; i < Count; i++)
{
reader.Position = EntriesIdx[i].Offset;
var type = reader.ReadByte();
reader.Position = EntriesIdx[i].Offset;
if (type == 0)
{
var entry = new PsoStructureInfo();
entry.Read(reader);
entry.IndexInfo = EntriesIdx[i];
Entries[i] = entry;
}
else if (type == 1)
{
var entry = new PsoEnumInfo();
entry.Read(reader);
entry.IndexInfo = EntriesIdx[i];
Entries[i] = entry;
}
else
throw new Exception("unknown type!");
}
}
public void Write(DataWriter writer)
{
var entriesStream = new MemoryStream();
var entriesWriter = new DataWriter(entriesStream, Endianess.BigEndian);
for (int i = 0; i < Entries.Length; i++)
{
EntriesIdx[i].Offset = 12 + 8 * Entries.Length + (int)entriesWriter.Position;
Entries[i].Write(entriesWriter);
}
var indexStream = new MemoryStream();
var indexWriter = new DataWriter(indexStream, Endianess.BigEndian);
foreach (var entry in EntriesIdx)
entry.Write(indexWriter);
writer.Write(Ident);
writer.Write((int)(12 + entriesStream.Length + indexStream.Length));
writer.Write((int)(Entries.Length));
// write entries index data
var buf1 = new byte[indexStream.Length];
indexStream.Position = 0;
indexStream.Read(buf1, 0, buf1.Length);
writer.Write(buf1);
// write entries data
var buf2 = new byte[entriesStream.Length];
entriesStream.Position = 0;
entriesStream.Read(buf2, 0, buf2.Length);
writer.Write(buf2);
}
public override string ToString()
{
return Ident.ToString() + ": " + Count.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoElementIndexInfo
{
public MetaName NameHash { get; set; }
public int Offset { get; set; }
public void Read(DataReader reader)
{
this.NameHash = (MetaName)reader.ReadUInt32();
this.Offset = reader.ReadInt32();
}
public void Write(DataWriter writer)
{
writer.Write((uint)NameHash);
writer.Write(Offset);
}
public override string ToString()
{
return NameHash.ToString() + ": " + Offset.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public abstract class PsoElementInfo
{
public PsoElementIndexInfo IndexInfo { get; set; }
public abstract void Read(DataReader reader);
public abstract void Write(DataWriter writer);
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoStructureInfo : PsoElementInfo
{
public byte Type { get; set; } = 0;
public short EntriesCount { get; private set; }
public byte Unk { get; set; }
public int StructureLength { get; set; }
public uint Unk_Ch { get; set; } = 0x00000000;
public PsoStructureEntryInfo[] Entries { get; set; }
public override void Read(DataReader reader)
{
uint x = reader.ReadUInt32();
this.Type = (byte)((x & 0xFF000000) >> 24);
this.EntriesCount = (short)(x & 0xFFFF);
this.Unk = (byte)((x & 0x00FF0000) >> 16);
this.StructureLength = reader.ReadInt32();
this.Unk_Ch = reader.ReadUInt32();
Entries = new PsoStructureEntryInfo[EntriesCount];
for (int i = 0; i < EntriesCount; i++)
{
var entry = new PsoStructureEntryInfo();
entry.Read(reader);
Entries[i] = entry;
}
}
public override void Write(DataWriter writer)
{
Type = 0;
EntriesCount = (short)Entries.Length;
uint typeAndEntriesCount = (uint)(Type << 24) | (uint)(Unk << 16) | (ushort)EntriesCount;
writer.Write(typeAndEntriesCount);
writer.Write(StructureLength);
writer.Write(Unk_Ch);
foreach (var entry in Entries)
{
entry.Write(writer);
}
}
public override string ToString()
{
return IndexInfo.ToString() + " - " + Type.ToString() + ": " + EntriesCount.ToString();
}
public PsoStructureEntryInfo FindEntry(MetaName name)
{
if (Entries != null)
{
foreach (var entry in Entries)
{
if (entry.EntryNameHash == name) return entry;
}
}
return null;
}
public PsoStructureEntryInfo GetEntry(int id)
{
if ((Entries != null) && (id >= 0) && (id < Entries.Length))
{
return Entries[id];
}
return null;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoStructureEntryInfo
{
public MetaName EntryNameHash { get; set; }
public PsoDataType Type { get; set; }
public byte Unk_5h { get; set; }
public ushort DataOffset { get; set; }
public uint ReferenceKey { get; set; } // when array -> entry index with type
public void Read(DataReader reader)
{
this.EntryNameHash = (MetaName)reader.ReadUInt32();
this.Type = (PsoDataType)reader.ReadByte();
this.Unk_5h = reader.ReadByte();
this.DataOffset = reader.ReadUInt16();
this.ReferenceKey = reader.ReadUInt32();
}
public void Write(DataWriter writer)
{
writer.Write((uint)EntryNameHash);
writer.Write((byte)Type);
writer.Write(Unk_5h);
writer.Write(DataOffset);
writer.Write(ReferenceKey);
}
public override string ToString()
{
if(ReferenceKey!=0)
{
return EntryNameHash.ToString() + ": " + Type.ToString() + ": " + DataOffset.ToString() + ": " + ((MetaName)ReferenceKey).ToString();
}
return EntryNameHash.ToString() + ": " + Type.ToString() + ": " + DataOffset.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoEnumInfo : PsoElementInfo
{
public byte Type { get; private set; } = 1;
public int EntriesCount { get; private set; }
public PsoEnumEntryInfo[] Entries { get; set; }
public override void Read(DataReader reader)
{
uint x = reader.ReadUInt32();
this.Type = (byte)((x & 0xFF000000) >> 24);
this.EntriesCount = (int)(x & 0x00FFFFFF);
Entries = new PsoEnumEntryInfo[EntriesCount];
for (int i = 0; i < EntriesCount; i++)
{
var entry = new PsoEnumEntryInfo();
entry.Read(reader);
Entries[i] = entry;
}
}
public override void Write(DataWriter writer)
{
// update...
Type = 1;
EntriesCount = Entries.Length;
uint typeAndEntriesCount = (uint)(Type << 24) | (uint)EntriesCount;
writer.Write(typeAndEntriesCount);
foreach (var entry in Entries)
{
entry.Write(writer);
}
}
public PsoEnumEntryInfo FindEntry(int val)
{
if (Entries == null) return null;
for (int i = 0; i < Entries.Length; i++)
{
var entry = Entries[i];
if (entry.EntryKey == val)
{
return entry;
}
}
return null;
}
public override string ToString()
{
return IndexInfo.ToString() + " - " + Type.ToString() + ": " + EntriesCount.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoEnumEntryInfo
{
public MetaName EntryNameHash { get; set; }
public int EntryKey { get; set; }
public void Read(DataReader reader)
{
this.EntryNameHash = (MetaName)reader.ReadUInt32();
this.EntryKey = reader.ReadInt32();
}
public void Write(DataWriter writer)
{
writer.Write((uint)EntryNameHash);
writer.Write(EntryKey);
}
public override string ToString()
{
return EntryNameHash.ToString() + ": " + EntryKey.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoSTRFSection
{
public int Ident { get; private set; } = 0x53545246;
public int Length { get; set; }
public string[] Strings { get; set; }
public void Read(DataReader reader)
{
Ident = reader.ReadInt32();
Length = reader.ReadInt32();
List<string> strs = new List<string>();
while (reader.Position < reader.Length)
{
strs.Add(reader.ReadString());
}
foreach (var str in strs)
{
JenkIndex.Ensure(str);
JenkIndex.Ensure(str.ToLowerInvariant());
}
Strings = strs.ToArray();
}
public void Write(DataWriter writer)
{
writer.Write(Ident);
writer.Write(Length);
}
public override string ToString()
{
return Ident.ToString() + ": " + Length.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoSTRSSection
{
public int Ident { get; private set; } = 0x53545253;
public int Length { get; set; }
public string[] Strings { get; set; }
public void Read(DataReader reader)
{
Ident = reader.ReadInt32();
Length = reader.ReadInt32();
List<string> strs = new List<string>();
while (reader.Position < reader.Length)
{
strs.Add(reader.ReadString());
}
foreach (var str in strs)
{
JenkIndex.Ensure(str);
JenkIndex.Ensure(str.ToLowerInvariant());
}
Strings = strs.ToArray();
}
public void Write(DataWriter writer)
{
writer.Write(Ident);
writer.Write(Length);
}
public override string ToString()
{
return Ident.ToString() + ": " + Length.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoSTRESection
{
public int Ident { get; private set; } = 0x53545245;
public int Length { get; set; }
public byte[] Data { get; set; }
//public MetaHash[] Hashes { get; set; }
//public byte[] Decr1 { get; set; }
//public byte[] Decr2 { get; set; }
public void Read(DataReader reader)
{
Ident = reader.ReadInt32();
Length = reader.ReadInt32();
if (Length > 8)
{
Data = reader.ReadBytes(Length - 8);
//reader.Position = 8;
//List<MetaHash> hashes = new List<MetaHash>();
//while (reader.Position < reader.Length)
//{
// hashes.Add(reader.ReadUInt32());
//}
//Hashes = hashes.ToArray();
//Decr1 = GTACrypto.DecryptAES(Data);
//Decr2 = GTACrypto.DecryptNG(Data, )
}
}
public void Write(DataWriter writer)
{
writer.Write(Ident);
writer.Write(Length);
}
public override string ToString()
{
return Ident.ToString() + ": " + Length.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoPSIGSection
{
public int Ident { get; private set; } = 0x50534947;
public int Length { get; set; }
public byte[] Data { get; set; }
public void Read(DataReader reader)
{
Ident = reader.ReadInt32();
Length = reader.ReadInt32();
if (Length > 8)
{
Data = reader.ReadBytes(Length - 8);
}
}
public void Write(DataWriter writer)
{
writer.Write(Ident);
writer.Write(Length);
}
public override string ToString()
{
return Ident.ToString() + ": " + Length.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class PsoCHKSSection
{
public int Ident { get; private set; } = 0x43484B53;
public int Length { get; set; }
public uint FileSize { get; set; }
public uint Checksum { get; set; }
public uint Unk0 { get; set; } = 0x79707070; // "yppp"
public void Read(DataReader reader)
{
Ident = reader.ReadInt32();
Length = reader.ReadInt32();
if (Length != 20)
{ return; }
FileSize = reader.ReadUInt32();
Checksum = reader.ReadUInt32();
Unk0 = reader.ReadUInt32();
}
public void Write(DataWriter writer)
{
writer.Write(Ident);
writer.Write(Length);
}
public override string ToString()
{
return Ident.ToString() + ": " + Length.ToString();
}
}
}

View File

@ -0,0 +1,856 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using TC = System.ComponentModel.TypeConverterAttribute;
using EXP = System.ComponentModel.ExpandableObjectConverter;
namespace CodeWalker.GameFiles
{
public static class PsoTypes
{
//for parsing schema info in PSO files to generate structs for PSO parsing.
//equivalent of MetaTypes but for PSO.
public static Dictionary<MetaName, PsoEnumInfo> EnumDict = new Dictionary<MetaName, PsoEnumInfo>();
public static Dictionary<MetaName, PsoStructureInfo> StructDict = new Dictionary<MetaName, PsoStructureInfo>();
public static void Clear()
{
StructDict.Clear();
}
public static void EnsurePsoTypes(PsoFile pso)
{
if ((pso.SchemaSection == null) || (pso.SchemaSection.Entries == null) || (pso.SchemaSection.EntriesIdx == null))
{
return;
}
for (int i = 0; i < pso.SchemaSection.Entries.Length; i++)
{
var entry = pso.SchemaSection.Entries[i];
var enuminfo = entry as PsoEnumInfo;
var structinfo = entry as PsoStructureInfo;
if (enuminfo != null)
{
if (!EnumDict.ContainsKey(enuminfo.IndexInfo.NameHash))
{
EnumDict.Add(enuminfo.IndexInfo.NameHash, enuminfo);
}
else
{
PsoEnumInfo oldei = EnumDict[enuminfo.IndexInfo.NameHash];
if (!ComparePsoEnumInfos(oldei, enuminfo))
{
}
}
}
else if (structinfo != null)
{
if (!StructDict.ContainsKey(structinfo.IndexInfo.NameHash))
{
StructDict.Add(structinfo.IndexInfo.NameHash, structinfo);
}
else
{
PsoStructureInfo oldsi = StructDict[structinfo.IndexInfo.NameHash];
if (!ComparePsoStructureInfos(oldsi, structinfo))
{
}
}
}
}
}
public static bool ComparePsoEnumInfos(PsoEnumInfo a, PsoEnumInfo b)
{
//returns true if they are the same.
if (a.Entries.Length != b.Entries.Length)
{
return false;
}
for (int i = 0; i < a.Entries.Length; i++)
{
if ((a.Entries[i].EntryNameHash != b.Entries[i].EntryNameHash) ||
(a.Entries[i].EntryKey != b.Entries[i].EntryKey))
{
return false;
}
}
return true;
}
public static bool ComparePsoStructureInfos(PsoStructureInfo a, PsoStructureInfo b)
{
//returns true if they are the same.
if (a.Entries.Length != b.Entries.Length)
{
return false;
}
for (int i = 0; i < a.Entries.Length; i++)
{
if ((a.Entries[i].EntryNameHash != b.Entries[i].EntryNameHash) ||
(a.Entries[i].DataOffset != b.Entries[i].DataOffset) ||
(a.Entries[i].Type != b.Entries[i].Type))
{
return false;
}
}
return true;
}
public static string GetTypesString()
{
StringBuilder sbe = new StringBuilder();
StringBuilder sbs = new StringBuilder();
sbe.AppendLine("//Enum infos");
sbs.AppendLine("//Struct infos");
foreach (var kvp in EnumDict)
{
var ei = kvp.Value;
string name = GetSafeName(ei.IndexInfo.NameHash, ei.Type);
sbe.AppendLine("public enum " + name + " //Type:" + ei.Type.ToString());
sbe.AppendLine("{");
foreach (var entry in ei.Entries)
{
string eename = GetSafeName(entry.EntryNameHash, (uint)entry.EntryKey);
sbe.AppendFormat(" {0} = {1},", eename, entry.EntryKey);
sbe.AppendLine();
}
sbe.AppendLine("}");
sbe.AppendLine();
}
foreach (var kvp in StructDict)
{
var si = kvp.Value;
string name = GetSafeName(si.IndexInfo.NameHash, si.Type);
sbs.AppendLine("public struct " + name + " //" + si.StructureLength.ToString() + " bytes, Type:" + si.Type.ToString());
sbs.AppendLine("{");
for (int i = 0; i < si.Entries.Length; i++)
{
var entry = si.Entries[i];
if ((entry.DataOffset == 0) && (entry.EntryNameHash == MetaName.ARRAYINFO)) //referred to by array
{
}
else
{
string sename = GetSafeName(entry.EntryNameHash, entry.ReferenceKey);
string fmt = " public {0} {1}; //{2} {3}";
if (entry.Type == PsoDataType.Array)
{
if (entry.ReferenceKey >= si.Entries.Length)
{
sbs.AppendFormat(fmt, entry.Type.ToString(), sename, entry.DataOffset, entry.ToString() + " { unexpected key! " + entry.ReferenceKey.ToString() + "}");
sbs.AppendLine();
}
else
{
var structentry = si.Entries[(int)entry.ReferenceKey];
var typename = "Array_" + PsoDataTypes.GetCSharpTypeName(structentry.Type);
sbs.AppendFormat(fmt, typename, sename, entry.DataOffset, entry.ToString() + " {" + structentry.ToString() + "}");
sbs.AppendLine();
}
}
else if (entry.Type == PsoDataType.Structure)
{
var typename = GetSafeName((MetaName)entry.ReferenceKey, entry.ReferenceKey);
sbs.AppendFormat(fmt, typename, sename, entry.DataOffset, entry.ToString());
sbs.AppendLine();
}
else
{
var typename = PsoDataTypes.GetCSharpTypeName(entry.Type);
sbs.AppendFormat(fmt, typename, sename, entry.DataOffset, entry);
sbs.AppendLine();
}
}
}
sbs.AppendLine("}");
sbs.AppendLine();
}
sbe.AppendLine();
sbe.AppendLine();
sbe.AppendLine();
sbe.AppendLine();
sbe.AppendLine();
sbe.Append(sbs.ToString());
string result = sbe.ToString();
return result;
}
private static string GetSafeName(MetaName namehash, uint key)
{
string name = namehash.ToString();
if (string.IsNullOrEmpty(name))
{
name = "Unk_" + key;
}
if (!char.IsLetter(name[0]))
{
name = "Unk_" + name;
}
return name;
}
public static T ConvertDataRaw<T>(byte[] data) where T : struct
{
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
var h = handle.AddrOfPinnedObject();
var r = Marshal.PtrToStructure<T>(h);
handle.Free();
return r;
}
public static T ConvertDataRaw<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 ConvertData<T>(byte[] data, int offset) where T : struct, IPsoSwapEnd
{
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
var h = handle.AddrOfPinnedObject();
var r = Marshal.PtrToStructure<T>(h + offset);
handle.Free();
r.SwapEnd();
return r;
}
public static T[] ConvertDataArrayRaw<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] = ConvertDataRaw<T>(data, off);
}
return items;
}
public static T GetItem<T>(PsoFile pso, int offset) where T : struct, IPsoSwapEnd
{
return ConvertData<T>(pso.DataSection.Data, offset);
}
public static T GetRootItem<T>(PsoFile pso) where T : struct, IPsoSwapEnd
{
var i = pso.DataMapSection.RootId - 1;
var e = pso.DataMapSection.Entries[i];
return GetItem<T>(pso, e.Offset);
}
public static PsoDataMappingEntry GetRootEntry(PsoFile pso)
{
var i = pso.DataMapSection.RootId - 1;
var e = pso.DataMapSection.Entries[i];
return e;
}
public static T[] GetItemArrayRaw<T>(PsoFile pso, Array_Structure arr) where T : struct
{
if ((arr.Count1 > 0) && (arr.Pointer > 0))
{
var entry = pso.DataMapSection.Entries[(int)arr.PointerDataIndex];
return ConvertDataArrayRaw<T>(pso.DataSection.Data, entry.Offset, arr.Count1);
}
return null;
}
public static T[] GetItemArray<T>(PsoFile pso, Array_Structure arr) where T : struct, IPsoSwapEnd
{
if ((arr.Count1 > 0) && (arr.Pointer > 0))
{
var entry = pso.DataMapSection.Entries[(int)arr.PointerDataIndex];
var res = ConvertDataArrayRaw<T>(pso.DataSection.Data, entry.Offset, arr.Count1);
if (res != null)
{
for (int i = 0; i < res.Length; i++)
{
res[i].SwapEnd();
}
}
return res;
}
return null;
}
public static uint[] GetUintArrayRaw(PsoFile pso, Array_uint arr)
{
byte[] data = pso.DataSection.Data;
var entryid = arr.Pointer & 0xFFF;
if ((entryid == 0) || (entryid > pso.DataMapSection.EntriesCount))
{
return null;
}
var entryoffset = (arr.Pointer & 0xFFFFFF) >> 12;
var arrentry = pso.DataMapSection.Entries[(int)entryid - 1];
int totoffset = arrentry.Offset + (int)entryoffset;
uint[] readdata = ConvertDataArrayRaw<uint>(data, totoffset, arr.Count1);
return readdata;
}
public static uint[] GetUintArray(PsoFile pso, Array_uint arr)
{
uint[] uints = GetUintArrayRaw(pso, arr);
if (uints == null) return null;
for (int i = 0; i < uints.Length; i++)
{
uints[i] = MetaTypes.SwapBytes(uints[i]);
}
return uints;
}
public static MetaHash[] GetHashArray(PsoFile pso, Array_uint arr)
{
uint[] uints = GetUintArrayRaw(pso, arr);
if (uints == null) return null;
MetaHash[] hashes = new MetaHash[uints.Length];
for (int n = 0; n < uints.Length; n++)
{
hashes[n].Hash = MetaTypes.SwapBytes(uints[n]);
}
return hashes;
}
public static float[] GetFloatArrayRaw(PsoFile pso, Array_float arr)
{
byte[] data = pso.DataSection.Data;
var entryid = arr.Pointer & 0xFFF;
if ((entryid == 0) || (entryid > pso.DataMapSection.EntriesCount))
{
return null;
}
var entryoffset = (arr.Pointer & 0xFFFFFF) >> 12;
var arrentry = pso.DataMapSection.Entries[(int)entryid - 1];
int totoffset = arrentry.Offset + (int)entryoffset;
float[] readdata = ConvertDataArrayRaw<float>(data, totoffset, arr.Count1);
return readdata;
}
public static float[] GetFloatArray(PsoFile pso, Array_float arr)
{
float[] floats = GetFloatArrayRaw(pso, arr);
if (floats == null) return null;
for (int i = 0; i < floats.Length; i++)
{
floats[i] = MetaTypes.SwapBytes(floats[i]);
}
return floats;
}
public static ushort[] GetUShortArrayRaw(PsoFile pso, Array_Structure arr)
{
byte[] data = pso.DataSection.Data;
var entryid = arr.Pointer & 0xFFF;
if ((entryid == 0) || (entryid > pso.DataMapSection.EntriesCount))
{
return null;
}
var entryoffset = (arr.Pointer & 0xFFFFFF) >> 12;
var arrentry = pso.DataMapSection.Entries[(int)entryid - 1];
int totoffset = arrentry.Offset + (int)entryoffset;
ushort[] readdata = ConvertDataArrayRaw<ushort>(data, totoffset, arr.Count1);
return readdata;
}
public static ushort[] GetUShortArray(PsoFile pso, Array_Structure arr)
{
ushort[] ushorts = GetUShortArrayRaw(pso, arr);
if (ushorts == null) return null;
for (int i = 0; i < ushorts.Length; i++)
{
ushorts[i] = MetaTypes.SwapBytes(ushorts[i]);
}
return ushorts;
}
public static T[] GetObjectArray<T, U>(PsoFile pso, Array_Structure arr) where U : struct, IPsoSwapEnd where T : PsoClass<U>, new()
{
U[] items = GetItemArray<U>(pso, arr);
if (items == null) return null;
if (items.Length == 0) return null;
T[] result = new T[items.Length];
for (int i = 0; i < items.Length; i++)
{
T newitem = new T();
newitem.Init(pso, ref items[i]);
result[i] = newitem;
}
return result;
}
public static byte[] GetByteArray(PsoFile pso, PsoStructureEntryInfo entry, int offset)
{
var aCount = (entry.ReferenceKey >> 16) & 0x0000FFFF;
var aBlockId = (int)entry.ReferenceKey & 0x0000FFFF;
var block = pso.GetBlock(aBlockId);
if (block == null) return null;
//block.Offset
return null;
}
public static PsoPOINTER[] GetPointerArray(PsoFile pso, Array_StructurePointer array)
{
uint count = array.Count1;
if (count == 0) return null;
int ptrsize = Marshal.SizeOf(typeof(MetaPOINTER));
int itemsleft = (int)count; //large arrays get split into chunks...
uint ptr = array.Pointer;
int ptrindex = (int)(ptr & 0xFFF) - 1;
int ptroffset = (int)((ptr >> 12) & 0xFFFFF);
var ptrblock = (ptrindex < pso.DataMapSection.EntriesCount) ? pso.DataMapSection.Entries[ptrindex] : null;
if ((ptrblock == null) || (ptrblock.NameHash != MetaName.PsoPOINTER))
{ return null; }
var offset = ptrblock.Offset;
int boffset = offset + ptroffset;
var ptrs = ConvertDataArrayRaw<PsoPOINTER>(pso.DataSection.Data, boffset, (int)count);
if (ptrs != null)
{
for (int i = 0; i < ptrs.Length; i++)
{
ptrs[i].SwapEnd();
}
}
return ptrs;
}
public static T[] ConvertDataArray<T>(PsoFile pso, Array_StructurePointer array) where T : struct, IPsoSwapEnd
{
uint count = array.Count1;
if (count == 0) return null;
PsoPOINTER[] ptrs = GetPointerArray(pso, array);
if (ptrs == null) return null;
if (ptrs.Length < count)
{ return null; }
T[] items = new T[count];
int itemsize = Marshal.SizeOf(typeof(T));
for (int i = 0; i < count; i++)
{
var sptr = ptrs[i];
int blocki = sptr.BlockID - 1;
int offset = (int)sptr.ItemOffset;// * 16;//block data size...
if (blocki >= pso.DataMapSection.EntriesCount)
{ continue; }
var block = pso.DataMapSection.Entries[blocki];
if ((offset < 0) || (offset >= block.Length))
{ continue; }
int boffset = block.Offset + offset;
items[i] = ConvertData<T>(pso.DataSection.Data, boffset);
}
return items;
}
public static string GetString(PsoFile pso, CharPointer ptr)
{
if (ptr.Count1 == 0) return null;
var blocki = (int)ptr.PointerDataId;// (ptr.Pointer & 0xFFF) - 1;
var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF;
var block = pso.GetBlock(blocki);
if (block == null)
{ return null; }
var length = ptr.Count1;
var lastbyte = offset + length;
if (lastbyte >= block.Length)
{ return null; }
var data = pso.DataSection?.Data;
if (data == null)
{ return null; }
var doffset = block.Offset + offset;
string s = Encoding.ASCII.GetString(data, doffset, length);
//if (meta.Strings == null) return null;
//if (offset < 0) return null;
//if (offset >= meta.Strings.Length) return null;
//string s = meta.Strings[offset];
return s;
}
public static string GetString(PsoFile pso, DataBlockPointer ptr)
{
var blocki = (int)ptr.PointerDataId;// (ptr.Pointer & 0xFFF) - 1;
var offset = (int)ptr.PointerDataOffset;// (ptr.Pointer >> 12) & 0xFFFFF;
var block = pso.GetBlock(blocki);
if (block == null)
{ return null; }
//var length = ptr.Count1;
//var lastbyte = offset + length;
//if (lastbyte >= block.Length)
//{ return null; }
var data = pso.DataSection?.Data;
if (data == null)
{ return null; }
//var doffset = block.Offset + offset;
//string s = Encoding.ASCII.GetString(data, doffset, length);
StringBuilder sb = new StringBuilder();
var o = block.Offset + offset;
char c = (char)data[o];
while (c != 0)
{
sb.Append(c);
o++;
c = (char)data[o];
}
var s = sb.ToString();
return s;
}
}
public interface IPsoSwapEnd
{
void SwapEnd();
}
public abstract class PsoClass<T> where T : struct, IPsoSwapEnd
{
public abstract void Init(PsoFile pso, ref T v);
}
public struct PsoChar64
{
public byte b00, b01, b02, b03, b04, b05, b06, b07, b08, b09,
b10, b11, b12, b13, b14, b15, b16, b17, b18, b19,
b20, b21, b22, b23, b24, b25, b26, b27, b28, b29,
b30, b31, b32, b33, b34, b35, b36, b37, b38, b39,
b40, b41, b42, b43, b44, b45, b46, b47, b48, b49,
b50, b51, b52, b53, b54, b55, b56, b57, b58, b59,
b60, b61, b62, b63;
public override string ToString()
{
byte[] bytes = new byte[]
{
b00, b01, b02, b03, b04, b05, b06, b07, b08, b09,
b10, b11, b12, b13, b14, b15, b16, b17, b18, b19,
b20, b21, b22, b23, b24, b25, b26, b27, b28, b29,
b30, b31, b32, b33, b34, b35, b36, b37, b38, b39,
b40, b41, b42, b43, b44, b45, b46, b47, b48, b49,
b50, b51, b52, b53, b54, b55, b56, b57, b58, b59,
b60, b61, b62, b63
};
return Encoding.ASCII.GetString(bytes).Replace("\0", string.Empty);
}
}
[TC(typeof(EXP))] public struct PsoPOINTER : IPsoSwapEnd //8 bytes - pointer to data item
{
public uint Pointer { get; set; }
public uint Unk2 { get; set; }
public ushort BlockID { get { return (ushort)(Pointer & 0xFFF); } } //1-based ID
public uint ItemOffset { get { return ((Pointer>>12) & 0xFFFFF); } } //byte offset
public override string ToString()
{
return BlockID.ToString() + ", " + ItemOffset.ToString() + ", " + Unk2.ToString();
}
public void SwapEnd()
{
Pointer = MetaTypes.SwapBytes(Pointer);
Unk2 = MetaTypes.SwapBytes(Unk2);
}
}
//Struct infos
[TC(typeof(EXP))] public struct CPackFileMetaData : IPsoSwapEnd //96 bytes, Type:0
{
public Array_Structure MapDataGroups; //0 MapDataGroups: Array: 0 {256: Structure: 0: 3260758307}
public Array_Structure HDTxdBindingArray; //16 HDTxdBindingArray: Array: 16: 2 {256: Structure: 0: CHDTxdAssetBinding}
public Array_Structure imapDependencies; //32 imapDependencies: Array: 32: 4 {256: Structure: 0: 3501026914}
public Array_Structure imapDependencies_2; //48 imapDependencies_2: Array: 48: 6 {256: Structure: 0: 3240050401}
public Array_Structure itypDependencies_2; //64 itypDependencies_2: Array: 64: 8 {256: Structure: 0: 1515605584}
public Array_Structure Interiors; //80 Interiors: Array: 80: 10 {256: Structure: 0: 741495440}
public void SwapEnd()
{
MapDataGroups.SwapEnd();
HDTxdBindingArray.SwapEnd();
imapDependencies.SwapEnd();
imapDependencies_2.SwapEnd();
itypDependencies_2.SwapEnd();
Interiors.SwapEnd();
}
}
[TC(typeof(EXP))] public struct CMapDataGroup : IPsoSwapEnd //56 bytes, Type:0
{
public MetaHash Name { get; set; } //0 Name: INT_0Bh: 0
public uint Unused0 { get; set; } //4
public Array_uint Bounds { get; set; } //8 Bounds//3298223272: Array: 8: 1 {256: INT_0Bh: 0}
public ushort Flags { get; set; } //24 Flags: SHORT_0Fh: 24: 2097155
public ushort Unused1 { get; set; }//26
public uint Unused2 { get; set; }//28
public Array_uint WeatherTypes { get; set; } //32 WeatherTypes: Array: 32: 5 {256: INT_0Bh: 0}
public uint HoursOnOff { get; set; } //48 HoursOnOff//4190815249: INT_06h: 48
public uint Unused3 { get; set; }//52
public override string ToString()
{
return Name.ToString() + ": ybn:" + Bounds.Count1.ToString() + ", wt:" + WeatherTypes.Count1.ToString() + ", flags:" + Flags.ToString() + ", hours:" + HoursOnOff.ToString();
}
public void SwapEnd()
{
Name = new MetaHash(MetaTypes.SwapBytes(Name.Hash));
var b = Bounds; b.SwapEnd(); Bounds = b;
var w = WeatherTypes; w.SwapEnd(); WeatherTypes = w;
HoursOnOff = MetaTypes.SwapBytes(HoursOnOff);
Flags = MetaTypes.SwapBytes(Flags);
}
}
[TC(typeof(EXP))] public struct CHDTxdAssetBinding : IPsoSwapEnd //132 bytes, Type:0
{
public byte assetType { get; set; } //0 assetType: BYTE_ENUM_VALUE: 0: 3387532954
public byte Unused01 { get; set; }//1
public ushort Unused02 { get; set; }//2
public PsoChar64 targetAsset { get; set; } //4 targetAsset: INT_0Bh: 4: 4194304
public PsoChar64 HDTxd { get; set; } //68 HDTxd: INT_0Bh: 68: 4194304
public override string ToString()
{
return assetType.ToString() + ": " + targetAsset.ToString() + ": " + HDTxd.ToString();
}
public void SwapEnd()
{
//targetAsset.Hash = MetaTypes.SwapBytes(targetAsset.Hash);
//HDTxd.Hash = MetaTypes.SwapBytes(HDTxd.Hash);
}
}
[TC(typeof(EXP))] public struct CImapDependency : IPsoSwapEnd //12 bytes, Type:0 // CImapDependency//3501026914
{
public MetaHash imapName { get; set; } //0 imapName: INT_0Bh: 0
public MetaHash itypName { get; set; } //4 itypName//2890158180: INT_0Bh: 4
public MetaHash packFileName { get; set; } //8 packFileName//4216494073: INT_0Bh: 8
public override string ToString()
{
return imapName.ToString() + ", " + itypName.ToString() + ", " + packFileName.ToString();
}
public void SwapEnd()
{
imapName = new MetaHash(MetaTypes.SwapBytes(imapName.Hash));
itypName = new MetaHash(MetaTypes.SwapBytes(itypName.Hash));
packFileName = new MetaHash(MetaTypes.SwapBytes(packFileName.Hash));
}
}
[TC(typeof(EXP))] public struct CImapDependencies : IPsoSwapEnd //24 bytes, Type:0 // CImapDependencies//3240050401 imapDependencies_2
{
public MetaHash imapName { get; set; } //0 imapName: INT_0Bh: 0 //name hash
public ushort manifestFlags { get; set; } //4 manifestFlags//1683136603: SHORT_0Fh: 4: 2097153
public ushort Unused0 { get; set; } //6
public Array_uint itypDepArray { get; set; } //8 itypDepArray//2410949350: Array: 8: 3 {256: INT_0Bh: 0} //children...
public override string ToString()
{
return imapName.ToString() + ": " + manifestFlags.ToString() + ": " + itypDepArray.ToString();
}
public void SwapEnd()
{
imapName = new MetaHash(MetaTypes.SwapBytes(imapName.Hash));
manifestFlags = MetaTypes.SwapBytes(manifestFlags);
var d = itypDepArray; d.SwapEnd(); itypDepArray = d;
}
}
[TC(typeof(EXP))] public struct CItypDependencies : IPsoSwapEnd //24 bytes, Type:0 // CItypDependencies//1515605584 itypDependencies_2
{
public MetaHash itypName { get; set; } //0 itypName//2890158180: INT_0Bh: 0
public ushort manifestFlags { get; set; } //4 manifestFlags//1683136603: SHORT_0Fh: 4: 2097153
public ushort Unused0 { get; set; } //6
public Array_uint itypDepArray { get; set; } //8 itypDepArray//2410949350: Array: 8: 3 {256: INT_0Bh: 0}
public override string ToString()
{
return itypName.ToString() + ": " + manifestFlags.ToString() + ": " + itypDepArray.ToString();
}
public void SwapEnd()
{
itypName = new MetaHash(MetaTypes.SwapBytes(itypName.Hash));
manifestFlags = MetaTypes.SwapBytes(manifestFlags);
var d = itypDepArray; d.SwapEnd(); itypDepArray = d;
}
}
[TC(typeof(EXP))] public struct Unk_741495440 : IPsoSwapEnd //24 bytes, Type:0 // Interiors
{
public MetaHash Name { get; set; } //0 Name: INT_0Bh: 0
public uint Unused0 { get; set; } //4
public Array_uint Bounds { get; set; } //8 Bounds//3298223272: Array: 8: 1 {256: INT_0Bh: 0}
public override string ToString()
{
return JenkIndex.GetString(Name);
}
public void SwapEnd()
{
Name = new MetaHash(MetaTypes.SwapBytes(Name.Hash));
var b = Bounds; b.SwapEnd(); Bounds = b;
}
}
[TC(typeof(EXP))] public struct CScenarioPointManifest : IPsoSwapEnd //56 bytes, Type:0
{
public int VersionNumber { get; set; } //0 VersionNumber: INT_05h: 0
public uint Unused0 { get; set; } //4
public Array_StructurePointer RegionDefs { get; set; } //8 RegionDefs: Array: 8: 1 {ARRAYINFO: Structure: 0}
public Array_StructurePointer Groups { get; set; } //24 Groups: Array: 24: 3 {ARRAYINFO: Structure: 0}
public Array_uint InteriorNames { get; set; } //40 InteriorNames: Array: 40: 5 {ARRAYINFO: INT_0Bh: 0}
public override string ToString()
{
return VersionNumber.ToString();
}
public void SwapEnd()
{
VersionNumber = MetaTypes.SwapBytes(VersionNumber);
var r = RegionDefs; r.SwapEnd(); RegionDefs = r;
var g = Groups; g.SwapEnd(); Groups = g;
var i = InteriorNames; i.SwapEnd(); InteriorNames = i;
}
}
[TC(typeof(EXP))] public struct CScenarioPointRegionDef : IPsoSwapEnd //64 bytes, Type:0
{
public MetaHash Name { get; set; } //0 Name: INT_0Bh: 0
public uint Unused0 { get; set; } //4
public uint Unused1 { get; set; } //8
public uint Unused2 { get; set; } //12
public rage__spdAABB AABB { get; set; } //16 AABB: Structure: 16: rage__spdAABB
public uint Unused3 { get; set; } //48
public uint Unused4 { get; set; } //52
public uint Unused5 { get; set; } //56
public uint Unused6 { get; set; } //60
public override string ToString()
{
return Name.ToString() + ", " + AABB.ToString();
}
public void SwapEnd()
{
Name = new MetaHash(MetaTypes.SwapBytes(Name.Hash));
var aabb = AABB; aabb.SwapEnd(); AABB = aabb;
}
}
[TC(typeof(EXP))] public struct CScenarioPointGroup : IPsoSwapEnd //8 bytes, Type:0
{
public MetaHash Name { get; set; } //0 Name: INT_0Bh: 0
public byte EnabledByDefault { get; set; } //4 EnabledByDefault: BYTE_00h: 4
public byte Unused0 { get; set; } //5
public ushort Unused1 { get; set; } //6
public override string ToString()
{
return Name.ToString();
}
public void SwapEnd()
{
Name = new MetaHash(MetaTypes.SwapBytes(Name.Hash));
}
}
}

View File

@ -0,0 +1,295 @@
/*
Copyright(c) 2015 Neodymium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
//shamelessly stolen and mangled
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfFile
{
private const int RBF_IDENT = 0x30464252;
public RbfStructure current { get; set; }
public Stack<RbfStructure> stack { get; set; }
public List<RbfEntryDescription> descriptors { get; set; }
public RbfStructure Load(string fileName)
{
using (var fileStream = new FileStream(fileName, FileMode.Open))
{
return Load(fileStream);
}
}
public RbfStructure Load(Stream stream)
{
stack = new Stack<RbfStructure>();
descriptors = new List<RbfEntryDescription>();
var reader = new DataReader(stream);
var ident = reader.ReadInt32();
if (ident != RBF_IDENT)
throw new Exception("The file identifier does not match.");
while (reader.Position < reader.Length)
{
var descriptorIndex = reader.ReadByte();
if (descriptorIndex == 0xFF) // close tag
{
var b = reader.ReadByte();
if (b != 0xFF)
throw new Exception("Expected 0xFF but was " + b.ToString("X2"));
if (stack.Count > 0)
{
current = stack.Pop();
}
else
{
if (reader.Position != reader.Length)
throw new Exception("Expected end of stream but was not.");
return current;
}
}
else if (descriptorIndex == 0xFD) // bytes
{
var b = reader.ReadByte();
if (b != 0xFF)
throw new Exception("Expected 0xFF but was " + b.ToString("X2"));
var dataLength = reader.ReadInt32();
var data = reader.ReadBytes(dataLength);
var bytesValue = new RbfBytes();
bytesValue.Value = data;
current.Children.Add(bytesValue);
}
else
{
var dataType = reader.ReadByte();
if (descriptorIndex == descriptors.Count) // new descriptor + data
{
var nameLength = reader.ReadInt16();
var nameBytes = reader.ReadBytes(nameLength);
var name = Encoding.ASCII.GetString(nameBytes);
var descriptor = new RbfEntryDescription();
descriptor.Name = name;
descriptor.Type = dataType;
descriptors.Add(descriptor);
ParseElement(reader, descriptors.Count - 1, dataType);
}
else // existing descriptor + data
{
if (dataType != descriptors[descriptorIndex].Type)
{
//throw new Exception("Data type does not match. Expected "
// + descriptors[descriptorIndex].Type.ToString() + " but found "
// + dataType.ToString() + ". Descriptor: " + descriptors[descriptorIndex].Name);
}
ParseElement(reader, descriptorIndex, dataType);
}
}
}
throw new Exception("Unexpected end of stream.");
}
private void ParseElement(DataReader reader, int descriptorIndex, byte dataType)
{
var descriptor = descriptors[descriptorIndex];
switch (dataType) //(descriptor.Type)
{
case 0: // open element...
{
var structureValue = new RbfStructure();
structureValue.Name = descriptor.Name;
if (current != null)
{
current.Children.Add(structureValue);
stack.Push(current);
}
current = structureValue;
// 6 bytes
var x1 = reader.ReadInt16();
var x2 = reader.ReadInt16();
var x3 = reader.ReadInt16();
//if (x1 != 0)
// throw new Exception("unexpected");
//if (x2 != 0)
// throw new Exception("unexpected");
//if (x3 != 0)
// throw new Exception("unexpected");
break;
}
case 0x10:
{
var intValue = new RbfUint32();
intValue.Name = descriptor.Name;
intValue.Value = reader.ReadUInt32();
current.Children.Add(intValue);
break;
}
case 0x20:
{
var booleanValue = new RbfBoolean();
booleanValue.Name = descriptor.Name;
booleanValue.Value = true;
current.Children.Add(booleanValue);
break;
}
case 0x30:
{
var booleanValue = new RbfBoolean();
booleanValue.Name = descriptor.Name;
booleanValue.Value = false;
current.Children.Add(booleanValue);
break;
}
case 0x40:
{
var floatValue = new RbfFloat();
floatValue.Name = descriptor.Name;
floatValue.Value = reader.ReadSingle();
current.Children.Add(floatValue);
break;
}
case 0x50:
{
var floatVectorValue = new RbfFloat3();
floatVectorValue.Name = descriptor.Name;
floatVectorValue.X = reader.ReadSingle();
floatVectorValue.Y = reader.ReadSingle();
floatVectorValue.Z = reader.ReadSingle();
current.Children.Add(floatVectorValue);
break;
}
case 0x60:
{
var valueLength = reader.ReadInt16();
var valueBytes = reader.ReadBytes(valueLength);
var value = Encoding.ASCII.GetString(valueBytes);
var stringValue = new RbfString();
stringValue.Name = descriptor.Name;
stringValue.Value = value;
current.Children.Add(stringValue);
break;
}
default:
throw new Exception("Unsupported data type.");
}
}
public static bool IsRBF(Stream stream)
{
var reader = new DataReader(stream);
var origpos = stream.Position;
var ident = reader.ReadInt32();
var isrbf = (ident == RBF_IDENT);
stream.Position = origpos;
return isrbf;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfEntryDescription
{
public string Name { get; set; }
public int Type { get; set; }
public override string ToString() { return Name + ": " + Type.ToString(); }
}
[TypeConverter(typeof(ExpandableObjectConverter))] public interface IRbfType
{
string Name { get; set; }
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfBoolean : IRbfType
{
public string Name { get; set; }
public bool Value { get; set; }
public override string ToString() { return Name + ": " + Value.ToString(); }
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfBytes : IRbfType
{
public string Name { get; set; }
public byte[] Value { get; set; }
public override string ToString() { return Name + ": " + Value.ToString(); }
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfFloat : IRbfType
{
public string Name { get; set; }
public float Value { get; set; }
public override string ToString() { return Name + ": " + Value.ToString(); }
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfFloat3 : IRbfType
{
public string Name { get; set; }
public float X { get; set; }
public float Y { get; set; }
public float Z { get; set; }
public override string ToString() { return string.Format("{0}: X:{1}, Y:{2}, Z:{3}", Name, X, Y, Z); }
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfString : IRbfType
{
public string Name { get; set; }
public string Value { get; set; }
public override string ToString() { return Name + ": " + Value.ToString(); }
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfStructure : IRbfType
{
public string Name { get; set; }
public List<IRbfType> Children { get; set; } = new List<IRbfType>();
public override string ToString() { return Name + ": {" + Children.Count.ToString() + "}"; }
public IRbfType FindChild(string name)
{
foreach (var child in Children)
{
if (child == null) continue;
if (child.Name == name) return child;
}
return null;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class RbfUint32 : IRbfType
{
public string Name { get; set; }
public uint Value { get; set; }
public override string ToString() { return Name + ": " + Value.ToString(); }
}
}

View File

@ -0,0 +1,774 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Xml;
using SharpDX;
namespace CodeWalker.GameFiles
{
public class XmlMeta
{
public static Meta GetMeta(XmlDocument doc)
{
MetaBuilder mb = new MetaBuilder();
Traverse(doc.DocumentElement, mb, 0, true);
var meta = mb.GetMeta();
return meta;
}
private static byte[] Traverse(XmlNode node, MetaBuilder mb, MetaName type = 0, bool isRoot = false)
{
if(type == 0)
{
type = (MetaName)(uint)GetHash(node.Name);
}
var infos = MetaTypes.GetStructureInfo(type);
if (infos != null)
{
byte[] data = new byte[infos.StructureSize];
var arrayResults = new ArrayResults();
arrayResults.Structures = new Dictionary<int, Array_Structure>();
arrayResults.StructurePointers = new Dictionary<int, Array_StructurePointer>();
arrayResults.UInts = new Dictionary<int, Array_uint>();
arrayResults.UShorts = new Dictionary<int, Array_ushort>();
arrayResults.UBytes = new Dictionary<int, Array_byte>();
arrayResults.Floats = new Dictionary<int, Array_float>();
arrayResults.Float_XYZs = new Dictionary<int, Array_Vector3>();
arrayResults.Hashes = new Dictionary<int, Array_uint>();
Array.Clear(data, 0, infos.StructureSize);
MetaStructureEntryInfo_s arrEntry = new MetaStructureEntryInfo_s();
if (isRoot)
{
mb.EnsureBlock(type);
}
for (int i = 0; i < infos.Entries.Length; i++)
{
var entry = infos.Entries[i];
var cnode = GetEntryNode(node.ChildNodes, entry);
if (entry.EntryNameHash == MetaName.ARRAYINFO)
{
arrEntry = entry;
continue;
}
if (cnode == null)
{
continue;
}
switch (entry.DataType)
{
case MetaStructureEntryDataType.Array:
{
TraverseArray(cnode, mb, arrEntry, entry.DataOffset, arrayResults);
break;
}
case MetaStructureEntryDataType.ArrayOfBytes:
{
GetParsedArrayOfBytes(cnode, data, entry, arrEntry);
break;
}
case MetaStructureEntryDataType.ArrayOfChars:
{
int offset = entry.DataOffset;
var split = Split(cnode.InnerText, 2);
for (int j = 0; j < split.Length; j++)
{
byte val = Convert.ToByte(split[j], 16);
data[offset] = val;
offset += sizeof(byte);
}
break;
}
case MetaStructureEntryDataType.Boolean:
{
byte val = (cnode.Attributes["value"].Value == "false") ? (byte)0 : (byte)1;
data[entry.DataOffset] = val;
break;
}
case MetaStructureEntryDataType.ByteEnum:
{
byte val = Convert.ToByte(cnode.Attributes["value"].Value);
data[entry.DataOffset] = val;
break;
}
case MetaStructureEntryDataType.CharPointer:
{
if (!string.IsNullOrEmpty(cnode.InnerText))
{
var ptr = mb.AddStringPtr(cnode.InnerText);
var val = MetaTypes.ConvertToBytes(ptr);
Buffer.BlockCopy(val, 0, data, entry.DataOffset, val.Length);
}
break;
}
case MetaStructureEntryDataType.DataBlockPointer:
{
// TODO
break;
}
case MetaStructureEntryDataType.Float:
{
float val = FloatUtil.Parse(cnode.Attributes["value"].Value);
Write(val, data, entry.DataOffset);
break;
}
case MetaStructureEntryDataType.Float_XYZ:
{
float x = FloatUtil.Parse(cnode.Attributes["x"].Value);
float y = FloatUtil.Parse(cnode.Attributes["y"].Value);
float z = FloatUtil.Parse(cnode.Attributes["z"].Value);
Write(x, data, entry.DataOffset);
Write(y, data, entry.DataOffset + sizeof(float));
Write(z, data, entry.DataOffset + sizeof(float) * 2);
break;
}
case MetaStructureEntryDataType.Float_XYZW:
{
float x = FloatUtil.Parse(cnode.Attributes["x"].Value);
float y = FloatUtil.Parse(cnode.Attributes["y"].Value);
float z = FloatUtil.Parse(cnode.Attributes["z"].Value);
float w = FloatUtil.Parse(cnode.Attributes["w"].Value);
Write(x, data, entry.DataOffset);
Write(y, data, entry.DataOffset + sizeof(float));
Write(z, data, entry.DataOffset + sizeof(float) * 2);
Write(w, data, entry.DataOffset + sizeof(float) * 3);
break;
}
case MetaStructureEntryDataType.Hash:
{
var hash = GetHash(cnode.InnerText);
Write(hash, data, entry.DataOffset);
break;
}
case MetaStructureEntryDataType.IntEnum:
case MetaStructureEntryDataType.IntFlags1:
case MetaStructureEntryDataType.IntFlags2:
{
var _infos = MetaTypes.GetEnumInfo(entry.ReferenceKey);
mb.AddEnumInfo(_infos.EnumNameHash);
int val = GetEnumInt(entry.ReferenceKey, cnode.InnerText);
Write(val, data, entry.DataOffset);
break;
}
case MetaStructureEntryDataType.ShortFlags:
{
var _infos = MetaTypes.GetEnumInfo(entry.ReferenceKey);
mb.AddEnumInfo(_infos.EnumNameHash);
int val = GetEnumInt(entry.ReferenceKey, cnode.InnerText);
Write((short)val, data, entry.DataOffset);
break;
}
case MetaStructureEntryDataType.SignedByte:
{
var val = Convert.ToSByte(cnode.Attributes["value"].Value);
data[entry.DataOffset] = (byte)val;
break;
}
case MetaStructureEntryDataType.SignedInt:
{
var val = Convert.ToInt32(cnode.Attributes["value"].Value);
Write(val, data, entry.DataOffset);
break;
}
case MetaStructureEntryDataType.SignedShort:
{
var val = Convert.ToInt16(cnode.Attributes["value"].Value);
Write(val, data, entry.DataOffset);
break;
}
case MetaStructureEntryDataType.Structure:
{
var struc = Traverse(cnode, mb, entry.ReferenceKey);
if(struc != null)
{
Buffer.BlockCopy(struc, 0, data, entry.DataOffset, struc.Length);
}
break;
}
case MetaStructureEntryDataType.StructurePointer:
{
// TODO
break;
}
case MetaStructureEntryDataType.UnsignedByte:
{
var val = Convert.ToByte(cnode.Attributes["value"].Value);
data[entry.DataOffset] = val;
break;
}
case MetaStructureEntryDataType.UnsignedInt:
{
switch (entry.EntryNameHash)
{
case MetaName.color:
{
var val = Convert.ToUInt32(cnode.Attributes["value"].Value, 16);
Write(val, data, entry.DataOffset);
break;
}
default:
{
var val = Convert.ToUInt32(cnode.Attributes["value"].Value);
Write(val, data, entry.DataOffset);
break;
}
}
break;
}
case MetaStructureEntryDataType.UnsignedShort:
{
var val = Convert.ToUInt16(cnode.Attributes["value"].Value);
Write(val, data, entry.DataOffset);
break;
}
default: break;
}
}
arrayResults.WriteArrays(data);
mb.AddStructureInfo(infos.StructureNameHash);
if (isRoot)
{
mb.AddItem(type, data);
}
return data;
}
return null;
}
private static void GetParsedArrayOfBytes(XmlNode node, byte[] data, MetaStructureEntryInfo_s entry, MetaStructureEntryInfo_s arrEntry)
{
int offset = entry.DataOffset;
string[] split;
switch (arrEntry.DataType)
{
default:
split = Split(node.InnerText, 2);
for (int j = 0; j < split.Length; j++)
{
byte val = Convert.ToByte(split[j], 16);
data[offset] = val;
offset += sizeof(byte);
}
break;
case MetaStructureEntryDataType.SignedByte:
split = node.InnerText.Split(); //split = Split(node.InnerText, 2); to read as unsplitted HEX
for (int j = 0; j < split.Length; j++)
{
sbyte val = Convert.ToSByte(split[j], 10);
data[offset] = (byte)val;
offset += sizeof(sbyte);
}
break;
case MetaStructureEntryDataType.UnsignedByte:
split = node.InnerText.Split();
for (int j = 0; j < split.Length; j++)
{
byte val = Convert.ToByte(split[j], 10);
data[offset] = val;
offset += sizeof(byte);
}
break;
case MetaStructureEntryDataType.SignedShort:
split = node.InnerText.Split();
for (int j = 0; j < split.Length; j++)
{
short val = Convert.ToInt16(split[j], 10);
Write(val, data, offset);
offset += sizeof(short);
}
break;
case MetaStructureEntryDataType.UnsignedShort:
split = node.InnerText.Split();
for (int j = 0; j < split.Length; j++)
{
ushort val = Convert.ToUInt16(split[j], 10);
Write(val, data, offset);
offset += sizeof(ushort);
}
break;
case MetaStructureEntryDataType.SignedInt:
split = node.InnerText.Split();
for (int j = 0; j < split.Length; j++)
{
int val = Convert.ToInt32(split[j], 10);
Write(val, data, offset);
offset += sizeof(int);
}
break;
case MetaStructureEntryDataType.UnsignedInt:
split = node.InnerText.Split();
for (int j = 0; j < split.Length; j++)
{
uint val = Convert.ToUInt32(split[j], 10);
Write(val, data, offset);
offset += sizeof(uint);
}
break;
case MetaStructureEntryDataType.Float:
split = node.InnerText.Split();
for (int j = 0; j < split.Length; j++)
{
float val = FloatUtil.Parse(split[j]);
Write(val, data, offset);
offset += sizeof(float);
}
break;
}
}
private static void TraverseArray(XmlNode node, MetaBuilder mb, MetaStructureEntryInfo_s arrEntry, int offset, ArrayResults results)
{
switch (arrEntry.DataType)
{
case MetaStructureEntryDataType.Structure:
{
results.Structures[offset] = TraverseArrayStructure(node, mb, arrEntry.ReferenceKey);
break;
}
case MetaStructureEntryDataType.StructurePointer:
{
results.StructurePointers[offset] = TraverseArrayStructurePointer(node, mb);
break;
}
case MetaStructureEntryDataType.UnsignedInt:
{
results.UInts[offset] = TraverseRawUIntArray(node, mb);
break;
}
case MetaStructureEntryDataType.UnsignedShort:
{
results.UShorts[offset] = TraverseRawUShortArray(node, mb);
break;
}
case MetaStructureEntryDataType.UnsignedByte:
{
results.UBytes[offset] = TraverseRawUByteArray(node, mb);
break;
}
case MetaStructureEntryDataType.Float:
{
results.Floats[offset] = TraverseRawFloatArray(node, mb);
break;
}
case MetaStructureEntryDataType.Float_XYZ:
{
results.Float_XYZs[offset] = TraverseRawVector3Array(node, mb);
break;
}
case MetaStructureEntryDataType.Hash:
{
results.Hashes[offset] = TraverseHashArray(node, mb);
break;
}
case MetaStructureEntryDataType.CharPointer:
{
// TODO
break;
}
case MetaStructureEntryDataType.DataBlockPointer:
{
// TODO
break;
}
default: break;
}
}
private static Array_Structure TraverseArrayStructure(XmlNode node, MetaBuilder mb, MetaName type)
{
var strucs = new List<byte[]>();
foreach (XmlNode cnode in node.ChildNodes)
{
var struc = Traverse(cnode, mb, type);
if (struc != null)
{
strucs.Add(struc);
}
}
return mb.AddItemArrayPtr(type, strucs.ToArray());
}
private static Array_StructurePointer TraverseArrayStructurePointer(XmlNode node, MetaBuilder mb)
{
var ptrs = new List<MetaPOINTER>();
foreach (XmlNode cnode in node.ChildNodes)
{
var type = (MetaName)(uint)GetHash(cnode.Attributes["type"].Value);
var struc = Traverse(cnode, mb, type);
if(struc != null)
{
var ptr = mb.AddItemPtr(type, struc);
ptrs.Add(ptr);
}
}
return mb.AddPointerArray(ptrs.ToArray());
}
private static Array_uint TraverseRawUIntArray(XmlNode node, MetaBuilder mb)
{
var data = new List<uint>();
if (node.InnerText != "")
{
var split = Regex.Split(node.InnerText, @"[\s\r\n\t]");
for (int i = 0; i < split.Length; i++)
{
if(!string.IsNullOrEmpty(split[i]))
{
var val = Convert.ToUInt32(split[i]);
data.Add(val);
}
}
}
return mb.AddUintArrayPtr(data.ToArray());
}
private static Array_ushort TraverseRawUShortArray(XmlNode node, MetaBuilder mb)
{
var data = new List<ushort>();
if (node.InnerText != "")
{
var split = Regex.Split(node.InnerText, @"[\s\r\n\t]");
for (int i = 0; i < split.Length; i++)
{
if (!string.IsNullOrEmpty(split[i]))
{
var val = Convert.ToUInt16(split[i]);
data.Add(val);
}
}
}
return mb.AddUshortArrayPtr(data.ToArray());
}
private static Array_byte TraverseRawUByteArray(XmlNode node, MetaBuilder mb)
{
var data = new List<byte>();
if (node.InnerText != "")
{
var split = Regex.Split(node.InnerText, @"[\s\r\n\t]");
for (int i = 0; i < split.Length; i++)
{
if (!string.IsNullOrEmpty(split[i]))
{
var val = Convert.ToByte(split[i]);
data.Add(val);
}
}
}
return mb.AddByteArrayPtr(data.ToArray());
}
private static Array_float TraverseRawFloatArray(XmlNode node, MetaBuilder mb)
{
var data = new List<float>();
if(node.InnerText != "")
{
var split = Regex.Split(node.InnerText, @"[\s\r\n\t]");
for (int i = 0; i < split.Length; i++)
{
var ts = split[i]?.Trim();
if (!string.IsNullOrEmpty(ts))
{
var val = FloatUtil.Parse(ts);// Convert.ToSingle(split[i]);
data.Add(val);
}
}
}
return mb.AddFloatArrayPtr(data.ToArray());
}
private static Array_Vector3 TraverseRawVector3Array(XmlNode node, MetaBuilder mb)
{
var items = new List<Vector4>();
var split = node.InnerText.Split('\n');// Regex.Split(node.InnerText, @"[\s\r\n\t]");
float x = 0f;
float y = 0f;
float z = 0f;
float w = 0f;
for (int i = 0; i < split.Length; i++)
{
var s = split[i]?.Trim();
if (string.IsNullOrEmpty(s)) continue;
var split2 = Regex.Split(s, @"[\s\t]");
int c = 0;
x = 0f; y = 0f; z = 0f;
for (int n = 0; n < split2.Length; n++)
{
var ts = split2[n]?.Trim();
if (string.IsNullOrEmpty(ts)) continue;
var f = FloatUtil.Parse(ts);
switch (c)
{
case 0: x = f; break;
case 1: y = f; break;
case 2: z = f; break;
}
c++;
}
if (c >= 3)
{
var val = new Vector4(x, y, z, w);
items.Add(val);
}
}
return mb.AddPaddedVector3ArrayPtr(items.ToArray());
}
private static Array_uint TraverseHashArray(XmlNode node, MetaBuilder mb)
{
var items = new List<MetaHash>();
foreach (XmlNode cnode in node.ChildNodes)
{
var val = GetHash(cnode.InnerText);
items.Add(val);
}
return mb.AddHashArrayPtr(items.ToArray());
}
private static void Write(int val, byte[] data, int offset)
{
byte[] bytes = BitConverter.GetBytes(val);
Buffer.BlockCopy(bytes, 0, data, offset, sizeof(int));
}
private static void Write(uint val, byte[] data, int offset)
{
byte[] bytes = BitConverter.GetBytes(val);
Buffer.BlockCopy(bytes, 0, data, offset, sizeof(uint));
}
private static void Write(short val, byte[] data, int offset)
{
byte[] bytes = BitConverter.GetBytes(val);
Buffer.BlockCopy(bytes, 0, data, offset, sizeof(short));
}
private static void Write(ushort val, byte[] data, int offset)
{
byte[] bytes = BitConverter.GetBytes(val);
Buffer.BlockCopy(bytes, 0, data, offset, sizeof(ushort));
}
private static void Write(float val, byte[] data, int offset)
{
byte[] bytes = BitConverter.GetBytes(val);
Buffer.BlockCopy(bytes, 0, data, offset, sizeof(float));
}
private static MetaHash GetHash(string str)
{
if (str.StartsWith("hash_"))
{
return (MetaHash) Convert.ToUInt32(str.Substring(5), 16);
}
else
{
return JenkHash.GenHash(str);
}
}
private static XmlNode GetEntryNode(XmlNodeList nodes, MetaStructureEntryInfo_s entry)
{
foreach (XmlNode node in nodes)
{
if (GetHash(node.Name) == (uint)entry.EntryNameHash)
{
return node;
}
}
return null;
}
private static string[] Split(string str, int maxChunkSize)
{
var chunks = new List<String>();
for (int i = 0; i < str.Length; i += maxChunkSize)
{
chunks.Add(str.Substring(i, Math.Min(maxChunkSize, str.Length - i)));
}
return chunks.ToArray();
}
private static int GetEnumInt(MetaName type, string enumString)
{
var enumName = (MetaName)(uint)GetHash(enumString);
var infos = MetaTypes.GetEnumInfo(type);
if (infos == null)
{
return 0;
}
for (int j = 0; j < infos.Entries.Length; j++)
{
var entry = infos.Entries[j];
if (entry.EntryNameHash == enumName)
{
return entry.EntryValue;
}
}
return 0;
}
}
struct ArrayResults
{
public Dictionary<int, Array_Structure> Structures;
public Dictionary<int, Array_StructurePointer> StructurePointers;
public Dictionary<int, Array_uint> UInts;
public Dictionary<int, Array_ushort> UShorts;
public Dictionary<int, Array_byte> UBytes;
public Dictionary<int, Array_float> Floats;
public Dictionary<int, Array_Vector3> Float_XYZs;
public Dictionary<int, Array_uint> Hashes;
public void WriteArrays(byte[] data)
{
foreach (KeyValuePair<int, Array_Structure> ptr in Structures)
{
var _data = MetaTypes.ConvertToBytes(ptr.Value);
Buffer.BlockCopy(_data, 0, data, ptr.Key, _data.Length);
}
foreach (KeyValuePair<int, Array_StructurePointer> ptr in StructurePointers)
{
var _data = MetaTypes.ConvertToBytes(ptr.Value);
Buffer.BlockCopy(_data, 0, data, ptr.Key, _data.Length);
}
foreach (KeyValuePair<int, Array_uint> ptr in UInts)
{
var _data = MetaTypes.ConvertToBytes(ptr.Value);
Buffer.BlockCopy(_data, 0, data, ptr.Key, _data.Length);
}
foreach (KeyValuePair<int, Array_ushort> ptr in UShorts)
{
var _data = MetaTypes.ConvertToBytes(ptr.Value);
Buffer.BlockCopy(_data, 0, data, ptr.Key, _data.Length);
}
foreach (KeyValuePair<int, Array_byte> ptr in UBytes)
{
var _data = MetaTypes.ConvertToBytes(ptr.Value);
Buffer.BlockCopy(_data, 0, data, ptr.Key, _data.Length);
}
foreach (KeyValuePair<int, Array_float> ptr in Floats)
{
var _data = MetaTypes.ConvertToBytes(ptr.Value);
Buffer.BlockCopy(_data, 0, data, ptr.Key, _data.Length);
}
foreach (KeyValuePair<int, Array_Vector3> ptr in Float_XYZs)
{
var _data = MetaTypes.ConvertToBytes(ptr.Value);
Buffer.BlockCopy(_data, 0, data, ptr.Key, _data.Length);
}
foreach (KeyValuePair<int, Array_uint> ptr in Hashes)
{
var _data = MetaTypes.ConvertToBytes(ptr.Value);
Buffer.BlockCopy(_data, 0, data, ptr.Key, _data.Length);
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,907 @@
/*
Copyright(c) 2016 Neodymium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
//now with enhanced uglification for codewalker
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMesh : ResourceFileBase
{
public override long BlockLength
{
get { return 368; }
}
public NavMeshFlags ContentFlags { get; set; }
public uint VersionUnk1 { get; set; } // 0x00010011
public uint Unused_018h { get; set; } // 0x00000000
public uint Unused_01Ch { get; set; } // 0x00000000
public Matrix Transform { get; set; } //(1,0,0,NaN),(0,1,0,NaN),(0,0,1,NaN),(0,0,0,NaN)
public Vector3 AABBSize { get; set; }
public float AABBUnk { get; set; } // 0x7F800001 //NaN
public ulong VerticesPointer { get; set; }
public uint Unused_078h { get; set; } // 0x00000000
public uint Unused_07Ch { get; set; } // 0x00000000
public ulong IndicesPointer { get; set; }
public ulong AdjPolysPointer { get; set; }
public uint AdjPolysIndicesCount { get; set; }
public NavMeshUintArray AdjAreaIDs { get; set; }
public ulong PolysPointer { get; set; }
public ulong SectorTreePointer { get; set; }
public ulong PortalsPointer { get; set; }
public ulong PortalLinksPointer { get; set; }
public uint VerticesCount { get; set; }
public uint PolysCount { get; set; }
public uint AreaID { get; set; } // X + Y*100
public uint TotalBytes { get; set; }
public uint SectorUnkCount { get; set; }
public uint PortalsCount { get; set; }
public uint PortalLinksCount { get; set; }
public uint Unused_154h { get; set; } // 0x00000000
public uint Unused_158h { get; set; } // 0x00000000
public uint Unused_15Ch { get; set; } // 0x00000000
public uint VersionUnk2 { get; set; } //2244687201 (0x85CB3561) for grid ynv's
public uint Unused_164h { get; set; } // 0x00000000
public uint Unused_168h { get; set; } // 0x00000000
public uint Unused_16Ch { get; set; } // 0x00000000
public NavMeshList<NavMeshVertex> Vertices { get; set; }
public NavMeshList<ushort> Indices { get; set; }
public NavMeshList<NavMeshAdjPoly> AdjPolys { get; set; }
public NavMeshList<NavMeshPoly> Polys { get; set; }
public NavMeshSector SectorTree { get; set; }
public NavMeshPortal[] Portals { get; set; }
public ushort[] PortalLinks { get; set; }
private ResourceSystemStructBlock<NavMeshPortal> PortalsBlock = null;
private ResourceSystemStructBlock<ushort> PortalLinksBlock = null;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
ContentFlags = (NavMeshFlags)reader.ReadUInt32();
VersionUnk1 = reader.ReadUInt32();
Unused_018h = reader.ReadUInt32();
Unused_01Ch = reader.ReadUInt32();
Transform = reader.ReadMatrix();
AABBSize = reader.ReadVector3();
AABBUnk = reader.ReadSingle();
VerticesPointer = reader.ReadUInt64();
Unused_078h = reader.ReadUInt32();
Unused_07Ch = reader.ReadUInt32();
IndicesPointer = reader.ReadUInt64();
AdjPolysPointer = reader.ReadUInt64();
AdjPolysIndicesCount = reader.ReadUInt32();
AdjAreaIDs = reader.ReadStruct<NavMeshUintArray>();
PolysPointer = reader.ReadUInt64();
SectorTreePointer = reader.ReadUInt64();
PortalsPointer = reader.ReadUInt64();
PortalLinksPointer = reader.ReadUInt64();
VerticesCount = reader.ReadUInt32();
PolysCount = reader.ReadUInt32();
AreaID = reader.ReadUInt32();
TotalBytes = reader.ReadUInt32();
SectorUnkCount = reader.ReadUInt32();
PortalsCount = reader.ReadUInt32();
PortalLinksCount = reader.ReadUInt32();
Unused_154h = reader.ReadUInt32();
Unused_158h = reader.ReadUInt32();
Unused_15Ch = reader.ReadUInt32();
VersionUnk2 = reader.ReadUInt32();
Unused_164h = reader.ReadUInt32();
Unused_168h = reader.ReadUInt32();
Unused_16Ch = reader.ReadUInt32();
Vertices = reader.ReadBlockAt<NavMeshList<NavMeshVertex>>(VerticesPointer);
Indices = reader.ReadBlockAt<NavMeshList<ushort>>(IndicesPointer);
AdjPolys = reader.ReadBlockAt<NavMeshList<NavMeshAdjPoly>>(AdjPolysPointer);
Polys = reader.ReadBlockAt<NavMeshList<NavMeshPoly>>(PolysPointer);
SectorTree = reader.ReadBlockAt<NavMeshSector>(SectorTreePointer);
Portals = reader.ReadStructsAt<NavMeshPortal>(PortalsPointer, PortalsCount);
PortalLinks = reader.ReadUshortsAt(PortalLinksPointer, PortalLinksCount);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
VerticesPointer = (ulong)(Vertices != null ? Vertices.FilePosition : 0);
IndicesPointer = (ulong)(Indices != null ? Indices.FilePosition : 0);
AdjPolysPointer = (ulong)(AdjPolys != null ? AdjPolys.FilePosition : 0);
PolysPointer = (ulong)(Polys != null ? Polys.FilePosition : 0);
SectorTreePointer = (ulong)(SectorTree != null ? SectorTree.FilePosition : 0);
PortalsPointer = (ulong)(PortalsBlock?.FilePosition ?? 0);
PortalLinksPointer = (ulong)(PortalLinksBlock?.FilePosition ?? 0);
writer.Write((uint)ContentFlags);
writer.Write(VersionUnk1);
writer.Write(Unused_018h);
writer.Write(Unused_01Ch);
writer.Write(Transform);
writer.Write(AABBSize);
writer.Write(AABBUnk);
writer.Write(VerticesPointer);
writer.Write(Unused_078h);
writer.Write(Unused_07Ch);
writer.Write(IndicesPointer);
writer.Write(AdjPolysPointer);
writer.Write(AdjPolysIndicesCount);
writer.WriteStruct(AdjAreaIDs);
writer.Write(PolysPointer);
writer.Write(SectorTreePointer);
writer.Write(PortalsPointer);
writer.Write(PortalLinksPointer);
writer.Write(VerticesCount);
writer.Write(PolysCount);
writer.Write(AreaID);
writer.Write(TotalBytes);
writer.Write(SectorUnkCount);
writer.Write(PortalsCount);
writer.Write(PortalLinksCount);
writer.Write(Unused_154h);
writer.Write(Unused_158h);
writer.Write(Unused_15Ch);
writer.Write(VersionUnk2);
writer.Write(Unused_164h);
writer.Write(Unused_168h);
writer.Write(Unused_16Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>(base.GetReferences());
if (Vertices != null) list.Add(Vertices);
if (Indices != null) list.Add(Indices);
if (AdjPolys != null) list.Add(AdjPolys);
if (Polys != null) list.Add(Polys);
if (SectorTree != null) list.Add(SectorTree);
if ((Portals != null) && (Portals.Length > 0))
{
PortalsBlock = new ResourceSystemStructBlock<NavMeshPortal>(Portals);
list.Add(PortalsBlock);
}
if ((PortalLinks != null) && (PortalLinks.Length > 0))
{
PortalLinksBlock = new ResourceSystemStructBlock<ushort>(PortalLinks);
list.Add(PortalLinksBlock);
}
return list.ToArray();
}
public override string ToString()
{
return "(Size: " + FloatUtil.GetVector3String(AABBSize) + ")";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshUintArray
{
public uint Count { get; set; }
public uint v00;
public uint v01;
public uint v02;
public uint v03;
public uint v04;
public uint v05;
public uint v06; // 0x00000000
public uint v07; // 0x00000000
public uint v08; // 0x00000000
public uint v09; // 0x00000000
public uint v10; // 0x00000000
public uint v11; // 0x00000000
public uint v12; // 0x00000000
public uint v13; // 0x00000000
public uint v14; // 0x00000000
public uint v15; // 0x00000000
public uint v16; // 0x00000000
public uint v17; // 0x00000000
public uint v18; // 0x00000000
public uint v19; // 0x00000000
public uint v20; // 0x00000000
public uint v21; // 0x00000000
public uint v22; // 0x00000000
public uint v23; // 0x00000000
public uint v24; // 0x00000000
public uint v25; // 0x00000000
public uint v26; // 0x00000000
public uint v27; // 0x00000000
public uint v28; // 0x00000000
public uint v29; // 0x00000000
public uint v30; // 0x00000000
public uint v31; // 0x00000000
public uint[] RawValues
{
get
{
return new[]{ v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,
v10,v11,v12,v13,v14,v15,v16,v17,v18,v19,
v20,v21,v22,v23,v24,v25,v26,v27,v28,v29,
v30,v31 };
}
}
public uint[] Values
{
get
{
uint[] vals = new uint[Count];
uint[] rvals = RawValues;
for (int i = 0; i < Count; i++)
{
vals[i] = rvals[i];
}
return vals;
}
set
{
Count = (uint)value.Length;
v00 = (Count > 0) ? value[0] : 0;
v01 = (Count > 1) ? value[1] : 0;
v02 = (Count > 2) ? value[2] : 0;
v03 = (Count > 3) ? value[3] : 0;
v04 = (Count > 4) ? value[4] : 0;
v05 = (Count > 5) ? value[5] : 0;
v06 = (Count > 6) ? value[6] : 0;
v07 = (Count > 7) ? value[7] : 0;
v08 = (Count > 8) ? value[8] : 0;
v09 = (Count > 9) ? value[9] : 0;
v10 = (Count > 10) ? value[10] : 0;
v11 = (Count > 11) ? value[11] : 0;
v12 = (Count > 12) ? value[12] : 0;
v13 = (Count > 13) ? value[13] : 0;
v14 = (Count > 14) ? value[14] : 0;
v15 = (Count > 15) ? value[15] : 0;
v16 = (Count > 16) ? value[16] : 0;
v17 = (Count > 17) ? value[17] : 0;
v18 = (Count > 18) ? value[18] : 0;
v19 = (Count > 19) ? value[19] : 0;
v20 = (Count > 20) ? value[20] : 0;
v21 = (Count > 21) ? value[21] : 0;
v22 = (Count > 22) ? value[22] : 0;
v23 = (Count > 23) ? value[23] : 0;
v24 = (Count > 24) ? value[24] : 0;
v25 = (Count > 25) ? value[25] : 0;
v26 = (Count > 26) ? value[26] : 0;
v27 = (Count > 27) ? value[27] : 0;
v28 = (Count > 28) ? value[28] : 0;
v29 = (Count > 29) ? value[29] : 0;
v30 = (Count > 30) ? value[30] : 0;
v31 = (Count > 31) ? value[31] : 0;
}
}
public override string ToString()
{
return "(Count: " + Count.ToString() + ")";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMeshList<T> : ResourceSystemBlock where T : struct
{
public override long BlockLength
{
get { return 48; }
}
public uint VFT { get; set; }
public uint Unknown_04h { get; set; } // 0x00000001
public uint ItemCount { get; set; }
public uint Unknown_0Ch { get; set; } // 0x00000000
public ulong ListPartsPointer { get; set; }
public ulong ListOffsetsPointer { get; set; }
public uint ListPartsCount { get; set; }
public uint Unknown_24h { get; set; } // 0x00000000
public uint Unknown_28h { get; set; } // 0x00000000
public uint Unknown_2Ch { get; set; } // 0x00000000
public ResourceSimpleArray<NavMeshListPart<T>> ListParts { get; set; }
public uint[] ListOffsets { get; set; }
private ResourceSystemStructBlock<uint> ListOffsetsBlock = null;
public int ItemSize { get { return System.Runtime.InteropServices.Marshal.SizeOf<T>(); } }
public override void Read(ResourceDataReader reader, params object[] parameters)
{
VFT = reader.ReadUInt32();
Unknown_04h = reader.ReadUInt32();
ItemCount = reader.ReadUInt32();
Unknown_0Ch = reader.ReadUInt32();
ListPartsPointer = reader.ReadUInt64();
ListOffsetsPointer = reader.ReadUInt64();
ListPartsCount = reader.ReadUInt32();
Unknown_24h = reader.ReadUInt32();
Unknown_28h = reader.ReadUInt32();
Unknown_2Ch = reader.ReadUInt32();
ListParts = reader.ReadBlockAt<ResourceSimpleArray<NavMeshListPart<T>>>(ListPartsPointer, ListPartsCount);
ListOffsets = reader.ReadUintsAt(ListOffsetsPointer, ListPartsCount);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
ListPartsPointer = (ulong)(ListParts != null ? ListParts.FilePosition : 0);
ListOffsetsPointer = (ulong)(ListOffsetsBlock?.FilePosition ?? 0);
ListPartsCount = (uint)(ListParts != null ? ListParts.Count : 0);
writer.Write(VFT);
writer.Write(Unknown_04h);
writer.Write(ItemCount);
writer.Write(Unknown_0Ch);
writer.Write(ListPartsPointer);
writer.Write(ListOffsetsPointer);
writer.Write(ListPartsCount);
writer.Write(Unknown_24h);
writer.Write(Unknown_28h);
writer.Write(Unknown_2Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if (ListParts != null) list.Add(ListParts);
if ((ListOffsets != null) && (ListOffsets.Length > 0))
{
ListOffsetsBlock = new ResourceSystemStructBlock<uint>(ListOffsets);
list.Add(ListOffsetsBlock);
}
return list.ToArray();
}
public List<T> GetFullList()
{
List<T> list = new List<T>((int)ItemCount);
if (ListParts != null)
{
foreach (var part in ListParts)
{
if (part.Items != null)
{
list.AddRange(part.Items);
}
}
}
return list;
}
public void RebuildList(List<T> items)
{
//max bytes per part: 16384
int maxpartbytes = 16384; //0x4000
int itembytes = ItemSize;
int itemsperpart = maxpartbytes / itembytes;
int currentitem = 0;
var parts = new ResourceSimpleArray<NavMeshListPart<T>>();
var partitems = new List<T>();
var offsets = new List<uint>();
while (currentitem < items.Count)
{
partitems.Clear();
int lastitem = currentitem + itemsperpart;
if (lastitem > items.Count) lastitem = items.Count;
for (int i = currentitem; i < lastitem; i++)
{
partitems.Add(items[i]);
}
var part = new NavMeshListPart<T>();
part.Items = partitems.ToArray();
part.Unknown_0Ch = 0;
parts.Add(part);
offsets.Add((uint)currentitem);
currentitem = lastitem;
}
ListParts = parts;
ListOffsets = offsets.ToArray();
}
public override string ToString()
{
return "(" + ItemCount.ToString() + " total items, " + ListPartsCount.ToString() + " parts)";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMeshListPart<T> : ResourceSystemBlock where T : struct
{
public override long BlockLength
{
get { return 16; }
}
public ulong Pointer { get; set; }
public uint Count { get; set; }
public uint Unknown_0Ch { get; set; } // 0x00000000
public T[] Items { get; set; }
private ResourceSystemStructBlock<T> ItemsBlock = null;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
Pointer = reader.ReadUInt64();
Count = reader.ReadUInt32();
Unknown_0Ch = reader.ReadUInt32();
Items = reader.ReadStructsAt<T>(Pointer, Count);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
Pointer = (ulong)(ItemsBlock?.FilePosition ?? 0);
Count = (uint)(Items?.Length ?? 0);
writer.Write(Pointer);
writer.Write(Count);
writer.Write(Unknown_0Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if ((Items != null) && (Items.Length > 0))
{
ItemsBlock = new ResourceSystemStructBlock<T>(Items);
list.Add(ItemsBlock);
}
return list.ToArray();
}
public override string ToString()
{
return "(" + Count.ToString() + " items)";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshVertex
{
public ushort X { get; set; }
public ushort Y { get; set; }
public ushort Z { get; set; }
public Vector3 Position { get { return ToVector3(); } set { FromVector3(value); } }
public Vector3 ToVector3()
{
const float usmax = ushort.MaxValue;
return new Vector3(X / usmax, Y / usmax, Z / usmax);
}
public void FromVector3(Vector3 v)
{
const float usmax = ushort.MaxValue;
X = (ushort)(v.X * usmax);
Y = (ushort)(v.Y * usmax);
Z = (ushort)(v.Z * usmax);
}
public static NavMeshVertex Create(Vector3 v)
{
var nmv = new NavMeshVertex();
nmv.FromVector3(v);
return nmv;
}
public override string ToString()
{
return X.ToString() + ", " + Y.ToString() + ", " + Z.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshAABB
{
public short MinX { get; set; }
public short MaxX { get; set; }
public short MinY { get; set; }
public short MaxY { get; set; }
public short MinZ { get; set; }
public short MaxZ { get; set; }
public Vector3 Min { get { return new Vector3(MinX / 4.0f, MinY / 4.0f, MinZ / 4.0f); } }
public Vector3 Max { get { return new Vector3(MaxX / 4.0f, MaxY / 4.0f, MaxZ / 4.0f); } }
public override string ToString()
{
Vector3 min = Min;
Vector3 max = Max;
return string.Format("({0}, {1}, {2}) | ({3}, {4}, {5})", min.X, min.Y, min.Z, max.X, max.Y, max.Z);
//return string.Format("({0}, {1}, {2}) | ({3}, {4}, {5})", MinX, MinY, MinZ, MaxX, MaxY, MaxZ);
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshAdjPoly
{
public NavMeshAdjPolyPart Unknown_0h { get; set; }
public NavMeshAdjPolyPart Unknown_4h { get; set; }
public override string ToString()
{
return //Unknown_0h.Bin + " | " + Unknown_4h.Bin + " | " +
Unknown_0h.ToString() + " | " + Unknown_4h.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshAdjPolyPart
{
public uint Value { get; set; }
public string Bin
{
get
{
return Convert.ToString(Value, 2).PadLeft(32, '0');
}
}
public uint AreaIDInd { get { return (Value >> 0) & 0x1F; } }
public uint PolyID { get { return (Value >> 5) & 0x3FFF; } }
public uint Unk2 { get { return (Value >> 19) & 0x3; } }
public uint Unk3 { get { return (Value >> 21) & 0x7FF; } }
public override string ToString()
{
return AreaIDInd.ToString() + ", " + PolyID.ToString() + ", " + Unk2.ToString() + ", " + Unk3.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshPoly
{
public ushort Unknown_00h { get; set; }
public ushort IndexFlags { get; set; }
public ushort IndexID { get; set; }
public ushort AreaID { get; set; }
public uint Unused_08h { get; set; } // 0x00000000
public uint Unused_0Ch { get; set; } // 0x00000000
public uint Unused_10h { get; set; } // 0x00000000
public uint Unused_14h { get; set; } // 0x00000000
public NavMeshAABB CellAABB { get; set; }
public FlagsUint Unknown_24h { get; set; }
public FlagsUint Unknown_28h { get; set; }
public ushort PartFlags { get; set; }
public ushort PortalID { get; set; }
//public int IndexUnk { get { return (IndexFlags >> 0) & 31; } } //always 0
public int IndexCount { get { return (IndexFlags >> 5); } }
//public int PartUnk1 { get { return (PartFlags >> 0) & 0xF; } } //always 0
public ushort PartID { get { return (ushort)((PartFlags >> 4) & 0xFF); } set { PartFlags = (ushort)((PartFlags & 0xF00F) | ((value & 0xFF) << 4)); } }
public byte PortalUnk { get { return (byte)((PartFlags >> 12) & 0xF); } set { PartFlags = (ushort)((PartFlags & 0x0FFF) | ((value & 0xF) << 12)); } }
public ushort Unknown_28h_16 { get { return (ushort)((Unknown_28h.Value & 0xFFFF)); } set { Unknown_28h = (Unknown_28h.Value & 0xFFFF0000) | (value & 0xFFFFu); } }
public byte Unknown_28h_8a { get { return (byte)((Unknown_28h.Value >> 0) & 0xFF); } set { Unknown_28h = (Unknown_28h.Value & 0xFFFFFF00) | ((value & 0xFFu)<<0); } }
public byte Unknown_28h_8b { get { return (byte)((Unknown_28h.Value >> 8) & 0xFF); } set { Unknown_28h = (Unknown_28h.Value & 0xFFFF00FF) | ((value & 0xFFu)<<8); } }
public override string ToString()
{
return
//Unknown_28h.Bin + ", (" + Unknown_28h_8a.ToString() + ", " + Unknown_28h_8b.ToString() + "), " +
Unknown_00h.ToString() + ", " +
//IndexFlags.ToString() + ", " +
IndexCount.ToString() + ", " + //IndexUnk.ToString() + ", " +
IndexID.ToString() + ", " + AreaID.ToString() + ", " +
CellAABB.ToString() + ", " +
Unknown_24h.Hex + ", " +
Unknown_28h.Hex + ", " +
//PartFlags.ToString() + ", " + //PartUnk1.ToString() + ", " +
PartID.ToString() + ", " +
PortalUnk.ToString() + ", " +
PortalID.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMeshSector : ResourceSystemBlock
{
public override long BlockLength
{
get { return 96; }
}
public Vector4 AABBMin { get; set; } //W==NaN
public Vector4 AABBMax { get; set; } //W==NaN
public NavMeshAABB CellAABB { get; set; }
public ulong DataPointer { get; set; }
public ulong SubTree1Pointer { get; set; }
public ulong SubTree2Pointer { get; set; }
public ulong SubTree3Pointer { get; set; }
public ulong SubTree4Pointer { get; set; }
public uint Unused_54h { get; set; } // 0x00000000
public uint Unused_58h { get; set; } // 0x00000000
public uint Unused_5Ch { get; set; } // 0x00000000
public NavMeshSectorData Data { get; set; }
public NavMeshSector SubTree1 { get; set; }
public NavMeshSector SubTree2 { get; set; }
public NavMeshSector SubTree3 { get; set; }
public NavMeshSector SubTree4 { get; set; }
public override void Read(ResourceDataReader reader, params object[] parameters)
{
AABBMin = reader.ReadVector4();
AABBMax = reader.ReadVector4();
CellAABB = reader.ReadStruct<NavMeshAABB>();
DataPointer = reader.ReadUInt64();
SubTree1Pointer = reader.ReadUInt64();
SubTree2Pointer = reader.ReadUInt64();
SubTree3Pointer = reader.ReadUInt64();
SubTree4Pointer = reader.ReadUInt64();
Unused_54h = reader.ReadUInt32();
Unused_58h = reader.ReadUInt32();
Unused_5Ch = reader.ReadUInt32();
Data = reader.ReadBlockAt<NavMeshSectorData>(DataPointer);
SubTree1 = reader.ReadBlockAt<NavMeshSector>(SubTree1Pointer);
SubTree2 = reader.ReadBlockAt<NavMeshSector>(SubTree2Pointer);
SubTree3 = reader.ReadBlockAt<NavMeshSector>(SubTree3Pointer);
SubTree4 = reader.ReadBlockAt<NavMeshSector>(SubTree4Pointer);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
DataPointer = (ulong)(Data != null ? Data.FilePosition : 0);
SubTree1Pointer = (ulong)(SubTree1 != null ? SubTree1.FilePosition : 0);
SubTree2Pointer = (ulong)(SubTree2 != null ? SubTree2.FilePosition : 0);
SubTree3Pointer = (ulong)(SubTree3 != null ? SubTree3.FilePosition : 0);
SubTree4Pointer = (ulong)(SubTree4 != null ? SubTree4.FilePosition : 0);
writer.Write(AABBMin);
writer.Write(AABBMax);
writer.WriteStruct(CellAABB);
writer.Write(DataPointer);
writer.Write(SubTree1Pointer);
writer.Write(SubTree2Pointer);
writer.Write(SubTree3Pointer);
writer.Write(SubTree4Pointer);
writer.Write(Unused_54h);
writer.Write(Unused_58h);
writer.Write(Unused_5Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if (Data != null) list.Add(Data);
if (SubTree1 != null) list.Add(SubTree1);
if (SubTree2 != null) list.Add(SubTree2);
if (SubTree3 != null) list.Add(SubTree3);
if (SubTree4 != null) list.Add(SubTree4);
return list.ToArray();
}
public override string ToString()
{
return "[Min: "+AABBMin.ToString() + "], [Max:" + AABBMax.ToString() + "]";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class NavMeshSectorData : ResourceSystemBlock
{
public override long BlockLength
{
get { return 32; }
}
public uint UnkDataStartID { get; set; }
public uint Unused_04h { get; set; } // 0x00000000
public ulong PolyIDsPointer { get; set; }
public ulong PointsPointer { get; set; }
public ushort PolyIDsCount { get; set; }
public ushort PointsCount { get; set; }
public uint Unused_1Ch { get; set; } // 0x00000000
public ushort[] PolyIDs { get; set; }
public NavMeshPoint[] Points { get; set; }
private ResourceSystemStructBlock<ushort> PolyIDsBlock = null;
private ResourceSystemStructBlock<NavMeshPoint> PointsBlock = null;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
UnkDataStartID = reader.ReadUInt32();
Unused_04h = reader.ReadUInt32();
PolyIDsPointer = reader.ReadUInt64();
PointsPointer = reader.ReadUInt64();
PolyIDsCount = reader.ReadUInt16();
PointsCount = reader.ReadUInt16();
Unused_1Ch = reader.ReadUInt32();
PolyIDs = reader.ReadUshortsAt(PolyIDsPointer, PolyIDsCount);
Points = reader.ReadStructsAt<NavMeshPoint>(PointsPointer, PointsCount);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
PolyIDsPointer = (ulong)(PolyIDsBlock?.FilePosition ?? 0);
PolyIDsCount = (ushort)(PolyIDs?.Length ?? 0);
PointsPointer = (ulong)(PointsBlock?.FilePosition ?? 0);
PointsCount = (ushort)(Points?.Length ?? 0);
writer.Write(UnkDataStartID);
writer.Write(Unused_04h);
writer.Write(PolyIDsPointer);
writer.Write(PointsPointer);
writer.Write(PolyIDsCount);
writer.Write(PointsCount);
writer.Write(Unused_1Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if ((PolyIDs != null) && (PolyIDs.Length > 0))
{
PolyIDsBlock = new ResourceSystemStructBlock<ushort>(PolyIDs);
list.Add(PolyIDsBlock);
}
if ((Points != null) && (Points.Length > 0))
{
PointsBlock = new ResourceSystemStructBlock<NavMeshPoint>(Points);
list.Add(PointsBlock);
}
return list.ToArray();
}
public override string ToString()
{
return "(Polys: " + PolyIDsCount.ToString() + ", UnkOffset: " + UnkDataStartID.ToString() + ", UnkCount: " + PointsCount.ToString() + ")";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshPoint
{
public ushort X { get; set; }
public ushort Y { get; set; }
public ushort Z { get; set; }
public byte Angle { get; set; }
public byte Flags { get; set; }
public Vector3 Position { get { return ToVector3(); } }
public Vector3 ToVector3()
{
const float usmax = ushort.MaxValue;
return new Vector3(X / usmax, Y / usmax, Z / usmax);
}
public override string ToString()
{
return Flags.ToString() + ": " + Angle.ToString() + ", " + Position.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NavMeshPortal
{
public uint TypeFlags { get; set; }
public NavMeshVertex Position1 { get; set; }
public NavMeshVertex Position2 { get; set; }
public ushort PolyID1a { get; set; }
public ushort PolyID1b { get; set; }
public ushort PolyID2a { get; set; }
public ushort PolyID2b { get; set; }
public uint AreaFlags { get; set; }
public uint Type1 { get { return TypeFlags & 0xFF; } }
public uint Type2 { get { return (TypeFlags >> 8) & 0xF; } }
public uint Type3 { get { return (TypeFlags >> 12) & 0xF; } }
public uint Type4 { get { return (TypeFlags >> 16) & 0xFFFF; } }
public ushort AreaID1 { get { return (ushort)(AreaFlags & 0x3FFF); } }
public ushort AreaID2 { get { return (ushort)((AreaFlags >> 14) & 0x3FFF); } }
public byte AreaUnk { get { return (byte)((AreaFlags >> 28) & 0xF); } }
public override string ToString()
{
return AreaID1.ToString() + ", " + AreaID2.ToString() + ", " + AreaUnk.ToString() + ", " +
PolyID1a.ToString() + ", " + PolyID1b.ToString() + ", " +
PolyID2a.ToString() + ", " + PolyID2b.ToString() + ", " +
Type1.ToString() + ", " + Type2.ToString() + ", " + Type3.ToString() + ", " + Type4.ToString() + ", " +
"(" + Position1.ToString() + " | " + Position2.ToString() + ")";
}
}
[Flags] public enum NavMeshFlags : uint
{
None = 0,
Vertices = 1,
Portals = 2,
Vehicle = 4,
Unknown8 = 8,
}
}

View File

@ -0,0 +1,280 @@
/*
Copyright(c) 2016 Neodymium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
//mangled to fit
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class NodeDictionary : ResourceFileBase
{
public override long BlockLength
{
get { return 112; }
}
public ulong NodesPointer { get; set; }
public uint NodesCount { get; set; }
public uint NodesCountVehicle { get; set; }
public uint NodesCountPed { get; set; }
public uint Unk24 { get; set; } // 0x00000000
public ulong LinksPtr { get; set; }
public uint LinksCount { get; set; }
public uint Unk34 { get; set; } // 0x00000000
public ulong JunctionsPtr { get; set; }
public ulong JunctionHeightmapBytesPtr { get; set; }
public uint Unk48 { get; set; } = 1; // 0x00000001
public uint Unk4C { get; set; } // 0x00000000
public ulong JunctionRefsPtr { get; set; }
public ushort JunctionRefsCount0 { get; set; }
public ushort JunctionRefsCount1 { get; set; } // same as JunctionRefsCount0
public uint Unk5C { get; set; } // 0x00000000
public uint JunctionsCount { get; set; } // same as JunctionRefsCount0
public uint JunctionHeightmapBytesCount { get; set; }
public uint Unk68 { get; set; } // 0x00000000
public uint Unk6C { get; set; } // 0x00000000
public Node[] Nodes { get; set; }
public NodeLink[] Links { get; set; }
public NodeJunction[] Junctions { get; set; }
public byte[] JunctionHeightmapBytes { get; set; }
public NodeJunctionRef[] JunctionRefs { get; set; }
private ResourceSystemStructBlock<Node> NodesBlock = null;
private ResourceSystemStructBlock<NodeLink> LinksBlock = null;
private ResourceSystemStructBlock<NodeJunction> JunctionsBlock = null;
private ResourceSystemStructBlock<byte> JunctionHeightmapBytesBlock = null;
private ResourceSystemStructBlock<NodeJunctionRef> JunctionRefsBlock = null;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
this.NodesPointer = reader.ReadUInt64();
this.NodesCount = reader.ReadUInt32();
this.NodesCountVehicle = reader.ReadUInt32();
this.NodesCountPed = reader.ReadUInt32();
this.Unk24 = reader.ReadUInt32();
this.LinksPtr = reader.ReadUInt64();
this.LinksCount = reader.ReadUInt32();
this.Unk34 = reader.ReadUInt32();
this.JunctionsPtr = reader.ReadUInt64();
this.JunctionHeightmapBytesPtr = reader.ReadUInt64();
this.Unk48 = reader.ReadUInt32();
this.Unk4C = reader.ReadUInt32();
this.JunctionRefsPtr = reader.ReadUInt64();
this.JunctionRefsCount0 = reader.ReadUInt16();
this.JunctionRefsCount1 = reader.ReadUInt16();
this.Unk5C = reader.ReadUInt32();
this.JunctionsCount = reader.ReadUInt32();
this.JunctionHeightmapBytesCount = reader.ReadUInt32();
this.Unk68 = reader.ReadUInt32();
this.Unk6C = reader.ReadUInt32();
this.Nodes = reader.ReadStructsAt<Node>(this.NodesPointer, this.NodesCount);
this.Links = reader.ReadStructsAt<NodeLink>(this.LinksPtr, this.LinksCount);
this.Junctions = reader.ReadStructsAt<NodeJunction>(this.JunctionsPtr, this.JunctionsCount);
this.JunctionHeightmapBytes = reader.ReadBytesAt(this.JunctionHeightmapBytesPtr, this.JunctionHeightmapBytesCount);
this.JunctionRefs = reader.ReadStructsAt<NodeJunctionRef>(this.JunctionRefsPtr, this.JunctionRefsCount1);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
// update structure data
NodesPointer = (ulong)(NodesBlock?.FilePosition ?? 0);
NodesCount = (uint)(Nodes?.Length ?? 0); //assume NodesCountVehicle and Ped already updated..
LinksPtr = (ulong)(LinksBlock?.FilePosition ?? 0);
LinksCount = (uint)(Links?.Length ?? 0);
JunctionsPtr = (ulong)(JunctionsBlock?.FilePosition ?? 0);
JunctionHeightmapBytesPtr = (ulong)(JunctionHeightmapBytesBlock?.FilePosition ?? 0);
JunctionRefsPtr = (ulong)(JunctionRefsBlock?.FilePosition ?? 0);
JunctionRefsCount0 = (ushort)(JunctionRefs?.Length ?? 0);
JunctionRefsCount1 = JunctionRefsCount1;
JunctionsCount = (uint)(Junctions?.Length ?? 0);
JunctionHeightmapBytesCount = (uint)(JunctionHeightmapBytes?.Length ?? 0);
// write structure data
writer.Write(this.NodesPointer);
writer.Write(this.NodesCount);
writer.Write(this.NodesCountVehicle);
writer.Write(this.NodesCountPed);
writer.Write(this.Unk24);
writer.Write(this.LinksPtr);
writer.Write(this.LinksCount);
writer.Write(this.Unk34);
writer.Write(this.JunctionsPtr);
writer.Write(this.JunctionHeightmapBytesPtr);
writer.Write(this.Unk48);
writer.Write(this.Unk4C);
writer.Write(this.JunctionRefsPtr);
writer.Write(this.JunctionRefsCount0);
writer.Write(this.JunctionRefsCount1);
writer.Write(this.Unk5C);
writer.Write(this.JunctionsCount);
writer.Write(this.JunctionHeightmapBytesCount);
writer.Write(this.Unk68);
writer.Write(this.Unk6C);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>(base.GetReferences());
if ((JunctionRefs != null) && (JunctionRefs.Length > 0))
{
JunctionRefsBlock = new ResourceSystemStructBlock<NodeJunctionRef>(JunctionRefs);
list.Add(JunctionRefsBlock);
}
if ((JunctionHeightmapBytes != null) && (JunctionHeightmapBytes.Length > 0))
{
JunctionHeightmapBytesBlock = new ResourceSystemStructBlock<byte>(JunctionHeightmapBytes);
list.Add(JunctionHeightmapBytesBlock);
}
if ((Junctions != null) && (Junctions.Length > 0))
{
JunctionsBlock = new ResourceSystemStructBlock<NodeJunction>(Junctions);
list.Add(JunctionsBlock);
}
if ((Links != null) && (Links.Length > 0))
{
LinksBlock = new ResourceSystemStructBlock<NodeLink>(Links);
list.Add(LinksBlock);
}
if ((Nodes != null) && (Nodes.Length > 0))
{
NodesBlock = new ResourceSystemStructBlock<Node>(Nodes);
list.Add(NodesBlock);
}
return list.ToArray();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct Node
{
public uint Unused0 { get; set; } // 0x00000000
public uint Unused1 { get; set; } // 0x00000000
public uint Unused2 { get; set; } // 0x00000000
public uint Unused3 { get; set; } // 0x00000000
public ushort AreaID { get; set; }
public ushort NodeID { get; set; }
public TextHash StreetName { get; set; }
public ushort Unused4 { get; set; }
public ushort LinkID { get; set; }
public short PositionX { get; set; }
public short PositionY { get; set; }
public FlagsByte Flags0 { get; set; }
public FlagsByte Flags1 { get; set; }
public short PositionZ { get; set; }
public FlagsByte Flags2 { get; set; }
public FlagsByte LinkCountFlags { get; set; }
public FlagsByte Flags3 { get; set; }
public FlagsByte Flags4 { get; set; }
public override string ToString()
{
//return Unused0.ToString() + ", " + Unused1.ToString() + ", " + Unused2.ToString() + ", " +
// Unused3.ToString() + ", " + AreaID.ToString() + ", " + NodeID.ToString() + ", " +
// UnknownInterp.ToString() + ", " + HeuristicCost.ToString() + ", " + LinkID.ToString() + ", " +
// PositionX.ToString() + ", " + PositionY.ToString() + ", " + Unk20.ToString() + ", " + Unk21.ToString() + ", " +
// Unk22.ToString() + ", " + Unk24.ToString() + ", " + Unk26.ToString();
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + StreetName.ToString();// + ", X:" +
//PositionX.ToString() + ", Y:" + PositionY.ToString() + ", " + PositionZ.ToString();// + ", " +
//Flags0.ToString() + ", " + Flags1.ToString() + ", Z:" +
//Flags2.ToString() + ", " + LinkCountFlags.ToString() + ", " +
//Flags3.ToString() + ", " + Flags4.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeLink
{
public ushort AreaID { get; set; }
public ushort NodeID { get; set; }
public FlagsByte Flags0 { get; set; }
public FlagsByte Flags1 { get; set; }
public FlagsByte Flags2 { get; set; }
public FlagsByte LinkLength { get; set; }
public override string ToString()
{
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + Flags0.Value.ToString() + ", " + Flags1.Value.ToString() + ", " + Flags2.Value.ToString() + ", " + LinkLength.Value.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeJunction
{
public short MaxZ { get; set; }
public short PositionX { get; set; }
public short PositionY { get; set; }
public short MinZ { get; set; }
public ushort HeightmapPtr { get; set; }
public byte HeightmapDimX { get; set; }
public byte HeightmapDimY { get; set; }
public override string ToString()
{
return PositionX.ToString() + ", " + PositionY.ToString() + ": " + MinZ.ToString() + ", " + MaxZ.ToString() + ": " + HeightmapDimX.ToString() + " x " + HeightmapDimY.ToString();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public struct NodeJunctionRef
{
public ushort AreaID { get; set; }
public ushort NodeID { get; set; }
public ushort JunctionID { get; set; }
public ushort Unk0 { get; set; }
public override string ToString()
{
return AreaID.ToString() + ", " + NodeID.ToString() + ", " + JunctionID.ToString();
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,340 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class ResourceBuilder
{
protected const int RESOURCE_IDENT = 0x37435352;
protected const int BASE_SIZE = 0x2000;
private const int SKIP_SIZE = 512;//256;//64;
private const int ALIGN_SIZE = 512;//64;
public static void GetBlocks(IResourceBlock rootBlock, out IList<IResourceBlock> sys, out IList<IResourceBlock> gfx)
{
var systemBlocks = new HashSet<IResourceBlock>();
var graphicBlocks = new HashSet<IResourceBlock>();
var protectedBlocks = new List<IResourceBlock>();
var stack = new Stack<IResourceBlock>();
stack.Push(rootBlock);
var processed = new HashSet<IResourceBlock>();
processed.Add(rootBlock);
while (stack.Count > 0)
{
var block = stack.Pop();
if (block == null)
continue;
if (block is IResourceSystemBlock)
{
if (!systemBlocks.Contains(block))
systemBlocks.Add(block);
// for system blocks, also process references...
var references = ((IResourceSystemBlock)block).GetReferences();
//Array.Reverse(references);
foreach (var reference in references)
if (!processed.Contains(reference))
{
stack.Push(reference);
processed.Add(reference);
}
var subs = new Stack<IResourceSystemBlock>();
foreach (var part in ((IResourceSystemBlock)block).GetParts())
subs.Push((IResourceSystemBlock)part.Item2);
while (subs.Count > 0)
{
var sub = subs.Pop();
foreach (var x in sub.GetReferences())
if (!processed.Contains(x))
{
stack.Push(x);
processed.Add(x);
}
foreach (var x in sub.GetParts())
subs.Push((IResourceSystemBlock)x.Item2);
protectedBlocks.Add(sub);
}
}
else
{
if (!graphicBlocks.Contains(block))
graphicBlocks.Add(block);
}
}
//var result = new List<IResourceBlock>();
//result.AddRange(systemBlocks);
//result.AddRange(graphicBlocks);
//return result;
// there are now sys-blocks in the list that actually
// only substructures and therefore must not get
// a new position!
// -> remove them from the list
foreach (var q in protectedBlocks)
if (systemBlocks.Contains(q))
systemBlocks.Remove(q);
sys = new List<IResourceBlock>();
foreach (var s in systemBlocks)
sys.Add(s);
gfx = new List<IResourceBlock>();
foreach (var s in graphicBlocks)
gfx.Add(s);
}
public static void AssignPositions(IList<IResourceBlock> blocks, uint basePosition, ref int pageSize, out int pageCount)
{
// find largest structure
long largestBlockSize = 0;
foreach (var block in blocks)
{
if (largestBlockSize < block.BlockLength)
largestBlockSize = block.BlockLength;
}
// find minimum page size
long currentPageSize = pageSize;// 0x2000;
while (currentPageSize < largestBlockSize)
currentPageSize *= 2;
long currentPageCount;
long currentPosition;
while (true)
{
currentPageCount = 0;
currentPosition = 0;
// reset all positions
foreach (var block in blocks)
block.FilePosition = -1;
foreach (var block in blocks)
{
if (block.FilePosition != -1)
throw new Exception("A position of -1 is not possible!");
//if (block.Length == 0)
// throw new Exception("A length of 0 is not allowed!");
// check if new page is necessary...
// if yes, add a new page and align to it
long maxSpace = currentPageCount * currentPageSize - currentPosition;
if (maxSpace < (block.BlockLength + SKIP_SIZE))
{
currentPageCount++;
currentPosition = currentPageSize * (currentPageCount - 1);
}
// set position
block.FilePosition = basePosition + currentPosition;
currentPosition += block.BlockLength + SKIP_SIZE;
// align...
if ((currentPosition % ALIGN_SIZE) != 0)
currentPosition += (ALIGN_SIZE - (currentPosition % ALIGN_SIZE));
}
// break if everything fits...
if (currentPageCount < 128)
break;
currentPageSize *= 2;
}
pageSize = (int)currentPageSize;
pageCount = (int)currentPageCount;
}
public static byte[] Build(ResourceFileBase fileBase, int version)
{
fileBase.FilePagesInfo = new ResourcePagesInfo();
IList<IResourceBlock> systemBlocks;
IList<IResourceBlock> graphicBlocks;
GetBlocks(fileBase, out systemBlocks, out graphicBlocks);
int systemPageSize = BASE_SIZE;// *4;
int systemPageCount;
AssignPositions(systemBlocks, 0x50000000, ref systemPageSize, out systemPageCount);
int graphicsPageSize = BASE_SIZE;
int graphicsPageCount;
AssignPositions(graphicBlocks, 0x60000000, ref graphicsPageSize, out graphicsPageCount);
fileBase.FilePagesInfo.SystemPagesCount = 0;
if (systemPageCount > 0)
fileBase.FilePagesInfo.SystemPagesCount = 1; // (byte)systemPageCount; //1
fileBase.FilePagesInfo.GraphicsPagesCount = (byte)graphicsPageCount;
var systemStream = new MemoryStream();
var graphicsStream = new MemoryStream();
var resourceWriter = new ResourceDataWriter(systemStream, graphicsStream);
resourceWriter.Position = 0x50000000;
foreach (var block in systemBlocks)
{
resourceWriter.Position = block.FilePosition;
var pos_before = resourceWriter.Position;
block.Write(resourceWriter);
var pos_after = resourceWriter.Position;
if ((pos_after - pos_before) != block.BlockLength)
{
throw new Exception("error in system length");
}
}
resourceWriter.Position = 0x60000000;
foreach (var block in graphicBlocks)
{
resourceWriter.Position = block.FilePosition;
var pos_before = resourceWriter.Position;
block.Write(resourceWriter);
var pos_after = resourceWriter.Position;
if ((pos_after - pos_before) != block.BlockLength)
{
throw new Exception("error in graphics length");
}
}
var sysDataSize = 0x2000;
while (sysDataSize < systemStream.Length)
{
sysDataSize *= 2;
}
var sysData = new byte[sysDataSize];
systemStream.Flush();
systemStream.Position = 0;
systemStream.Read(sysData, 0, (int)systemStream.Length);
var gfxPageSize = 0x2000;
while (gfxPageSize != graphicsPageSize)
{
gfxPageSize *= 2;
}
var gfxDataSize = graphicsPageCount * gfxPageSize;
var gfxData = new byte[gfxDataSize];
graphicsStream.Flush();
graphicsStream.Position = 0;
graphicsStream.Read(gfxData, 0, (int)graphicsStream.Length);
uint uv = (uint)version;
uint sv = (uv >> 4) & 0xF;
uint gv = (uv >> 0) & 0xF;
//uint sf = RpfResourceFileEntry.GetFlagsFromSize(sysDataSize, sv);
//uint gf = RpfResourceFileEntry.GetFlagsFromSize(gfxDataSize, gv); //TODO: might be broken...
uint sf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)systemPageCount, (uint)systemPageSize, sv);
uint gf = RpfResourceFileEntry.GetFlagsFromBlocks((uint)graphicsPageCount, (uint)graphicsPageSize, gv);
var tdatasize = sysDataSize + gfxDataSize;
var tdata = new byte[tdatasize];
Buffer.BlockCopy(sysData, 0, tdata, 0, sysDataSize);
Buffer.BlockCopy(gfxData, 0, tdata, sysDataSize, gfxDataSize);
var cdata = Compress(tdata);
var dataSize = 16 + cdata.Length;// sysDataSize + gfxDataSize;
var data = new byte[dataSize];
byte[] h1 = BitConverter.GetBytes((uint)0x37435352);
byte[] h2 = BitConverter.GetBytes((int)version);
byte[] h3 = BitConverter.GetBytes(sf);
byte[] h4 = BitConverter.GetBytes(gf);
Buffer.BlockCopy(h1, 0, data, 0, 4);
Buffer.BlockCopy(h2, 0, data, 4, 4);
Buffer.BlockCopy(h3, 0, data, 8, 4);
Buffer.BlockCopy(h4, 0, data, 12, 4);
Buffer.BlockCopy(cdata, 0, data, 16, cdata.Length);
//Buffer.BlockCopy(sysData, 0, data, 16, sysDataSize);
//Buffer.BlockCopy(gfxData, 0, data, 16 + sysDataSize, gfxDataSize);
return data;
}
public static byte[] AddResourceHeader(RpfResourceFileEntry entry, byte[] data)
{
if (data == null) return null;
byte[] newdata = new byte[data.Length + 16];
byte[] h1 = BitConverter.GetBytes((uint)0x37435352);
byte[] h2 = BitConverter.GetBytes(entry.Version);
byte[] h3 = BitConverter.GetBytes(entry.SystemFlags);
byte[] h4 = BitConverter.GetBytes(entry.GraphicsFlags);
Buffer.BlockCopy(h1, 0, newdata, 0, 4);
Buffer.BlockCopy(h2, 0, newdata, 4, 4);
Buffer.BlockCopy(h3, 0, newdata, 8, 4);
Buffer.BlockCopy(h4, 0, newdata, 12, 4);
Buffer.BlockCopy(data, 0, newdata, 16, data.Length);
return newdata;
}
public static byte[] Compress(byte[] data)
{
using (MemoryStream ms = new MemoryStream())
{
DeflateStream ds = new DeflateStream(ms, CompressionMode.Compress, true);
ds.Write(data, 0, data.Length);
ds.Close();
byte[] deflated = ms.GetBuffer();
byte[] outbuf = new byte[ms.Length]; //need to copy to the right size buffer...
Array.Copy(deflated, outbuf, outbuf.Length);
return outbuf;
}
}
public static byte[] Decompress(byte[] data)
{
using (MemoryStream ms = new MemoryStream(data))
{
DeflateStream ds = new DeflateStream(ms, CompressionMode.Decompress);
MemoryStream outstr = new MemoryStream();
ds.CopyTo(outstr);
byte[] deflated = outstr.GetBuffer();
byte[] outbuf = new byte[outstr.Length]; //need to copy to the right size buffer...
Array.Copy(deflated, outbuf, outbuf.Length);
return outbuf;
}
}
}
}

View File

@ -0,0 +1,750 @@
/*
Copyright(c) 2015 Neodymium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
//shamelessly stolen and mangled
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
/// <summary>
/// Represents a resource data reader.
/// </summary>
public class ResourceDataReader : DataReader
{
private const long SYSTEM_BASE = 0x50000000;
private const long GRAPHICS_BASE = 0x60000000;
private Stream systemStream;
private Stream graphicsStream;
// this is a dictionary that contains all the resource blocks
// which were read from this resource reader
private Dictionary<long, List<IResourceBlock>> blockPool;
/// <summary>
/// Gets the length of the underlying stream.
/// </summary>
public override long Length
{
get
{
return -1;
}
}
/// <summary>
/// Gets or sets the position within the underlying stream.
/// </summary>
public override long Position
{
get;
set;
}
/// <summary>
/// Initializes a new resource data reader for the specified system- and graphics-stream.
/// </summary>
public ResourceDataReader(Stream systemStream, Stream graphicsStream, Endianess endianess = Endianess.LittleEndian)
: base((Stream)null, endianess)
{
this.systemStream = systemStream;
this.graphicsStream = graphicsStream;
this.blockPool = new Dictionary<long, List<IResourceBlock>>();
}
public ResourceDataReader(RpfResourceFileEntry resentry, byte[] data, Endianess endianess = Endianess.LittleEndian)
: base((Stream)null, endianess)
{
var systemSize = resentry.SystemSize;
var graphicsSize = resentry.GraphicsSize;
this.systemStream = new MemoryStream(data, 0, systemSize);
this.graphicsStream = new MemoryStream(data, systemSize, graphicsSize);
this.blockPool = new Dictionary<long, List<IResourceBlock>>();
Position = 0x50000000;
}
public ResourceDataReader(int systemSize, int graphicsSize, byte[] data, Endianess endianess = Endianess.LittleEndian)
: base((Stream)null, endianess)
{
this.systemStream = new MemoryStream(data, 0, systemSize);
this.graphicsStream = new MemoryStream(data, systemSize, graphicsSize);
this.blockPool = new Dictionary<long, List<IResourceBlock>>();
Position = 0x50000000;
}
/// <summary>
/// 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)
{
if ((Position & SYSTEM_BASE) == SYSTEM_BASE)
{
// read from system stream...
systemStream.Position = Position & ~0x50000000;
var buffer = new byte[count];
systemStream.Read(buffer, 0, count);
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
Array.Reverse(buffer);
}
Position = systemStream.Position | 0x50000000;
return buffer;
}
if ((Position & GRAPHICS_BASE) == GRAPHICS_BASE)
{
// read from graphic stream...
graphicsStream.Position = Position & ~0x60000000;
var buffer = new byte[count];
graphicsStream.Read(buffer, 0, count);
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
Array.Reverse(buffer);
}
Position = graphicsStream.Position | 0x60000000;
return buffer;
}
throw new Exception("illegal position!");
}
/// <summary>
/// Reads a block.
/// </summary>
public T ReadBlock<T>(params object[] parameters) where T : IResourceBlock, new()
{
// make sure to return the same object if the same
// block is read again...
if (blockPool.ContainsKey(Position))
{
var blocks = blockPool[Position];
foreach (var block in blocks)
if (block is T)
{
Position += block.BlockLength;
// since a resource block of the same type
// has been found at the same address, return it
return (T)block;
}
}
var result = new T();
// replace with correct type...
if (result is IResourceXXSystemBlock)
result = (T)((IResourceXXSystemBlock)result).GetType(this, parameters);
if (result == null)
{
return default(T);
}
// add block to the block pool...
if (blockPool.ContainsKey(Position))
{
blockPool[Position].Add(result);
}
else
{
var blocks = new List<IResourceBlock>();
blocks.Add(result);
blockPool.Add(Position, blocks);
}
var classPosition = Position;
result.Read(this, parameters);
//result.Position = classPosition; //TODO: need this if writing stuff!
return (T)result;
}
/// <summary>
/// Reads a block at a specified position.
/// </summary>
public T ReadBlockAt<T>(ulong position, params object[] parameters) where T : IResourceBlock, new()
{
if (position != 0)
{
var positionBackup = Position;
Position = (long)position;
var result = ReadBlock<T>(parameters);
Position = positionBackup;
return result;
}
else
{
return default(T);
}
}
public byte[] ReadBytesAt(ulong position, uint count)
{
long pos = (long)position;
if ((pos <= 0) || (count == 0)) return null;
var posbackup = Position;
Position = pos;
var result = ReadBytes((int)count);
Position = posbackup;
return result;
}
public ushort[] ReadUshortsAt(ulong position, uint count)
{
if ((position <= 0) || (count == 0)) return null;
var result = new ushort[count];
var length = count * 2;
byte[] data = ReadBytesAt(position, length);
Buffer.BlockCopy(data, 0, result, 0, (int)length);
//var posbackup = Position;
//Position = position;
//var result2 = new ushort[count];
//for (uint i = 0; i < count; i++)
//{
// result2[i] = ReadUInt16();
//}
//Position = posbackup;
return result;
}
public uint[] ReadUintsAt(ulong position, uint count)
{
if ((position <= 0) || (count == 0)) return null;
var result = new uint[count];
var length = count * 4;
byte[] data = ReadBytesAt(position, length);
Buffer.BlockCopy(data, 0, result, 0, (int)length);
//var posbackup = Position;
//Position = position;
//var result = new uint[count];
//for (uint i = 0; i < count; i++)
//{
// result[i] = ReadUInt32();
//}
//Position = posbackup;
return result;
}
public ulong[] ReadUlongsAt(ulong position, uint count)
{
if ((position <= 0) || (count == 0)) return null;
var result = new ulong[count];
var length = count * 8;
byte[] data = ReadBytesAt(position, length);
Buffer.BlockCopy(data, 0, result, 0, (int)length);
//var posbackup = Position;
//Position = position;
//var result = new ulong[count];
//for (uint i = 0; i < count; i++)
//{
// result[i] = ReadUInt64();
//}
//Position = posbackup;
return result;
}
public float[] ReadFloatsAt(ulong position, uint count)
{
if ((position <= 0) || (count == 0)) return null;
var result = new float[count];
var length = count * 4;
byte[] data = ReadBytesAt(position, length);
Buffer.BlockCopy(data, 0, result, 0, (int)length);
//var posbackup = Position;
//Position = position;
//var result = new float[count];
//for (uint i = 0; i < count; i++)
//{
// result[i] = ReadSingle();
//}
//Position = posbackup;
return result;
}
public T[] ReadStructsAt<T>(ulong position, uint count)//, uint structsize)
{
if ((position <= 0) || (count == 0)) return null;
uint structsize = (uint)Marshal.SizeOf(typeof(T));
var length = count * structsize;
byte[] data = ReadBytesAt(position, length);
//var result2 = new T[count];
//Buffer.BlockCopy(data, 0, result2, 0, (int)length); //error: "object must be an array of primitives" :(
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();
return result;
}
public T[] ReadStructs<T>(uint count)
{
uint structsize = (uint)Marshal.SizeOf(typeof(T));
var result = new T[count];
var length = count * structsize;
byte[] data = ReadBytes((int)length);
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();
return result;
}
public T ReadStruct<T>() where T : struct
{
uint structsize = (uint)Marshal.SizeOf(typeof(T));
var length = structsize;
byte[] data = ReadBytes((int)length);
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
var h = handle.AddrOfPinnedObject();
var result = Marshal.PtrToStructure<T>(h);
handle.Free();
return result;
}
public T ReadStructAt<T>(long position) where T : struct
{
if ((position <= 0)) return default(T);
var posbackup = Position;
Position = (long)position;
var result = ReadStruct<T>();
Position = posbackup;
return result;
}
public string ReadStringAt(ulong position)
{
long newpos = (long)position;
if ((newpos <= 0)) return null;
var lastpos = Position;
Position = newpos;
var result = ReadString();
Position = lastpos;
return result;
}
}
/// <summary>
/// Represents a resource data writer.
/// </summary>
public class ResourceDataWriter : DataWriter
{
private const long SYSTEM_BASE = 0x50000000;
private const long GRAPHICS_BASE = 0x60000000;
private Stream systemStream;
private Stream graphicsStream;
/// <summary>
/// Gets the length of the underlying stream.
/// </summary>
public override long Length
{
get
{
return -1;
}
}
/// <summary>
/// Gets or sets the position within the underlying stream.
/// </summary>
public override long Position
{
get;
set;
}
/// <summary>
/// Initializes a new resource data reader for the specified system- and graphics-stream.
/// </summary>
public ResourceDataWriter(Stream systemStream, Stream graphicsStream, Endianess endianess = Endianess.LittleEndian)
: base((Stream)null, endianess)
{
this.systemStream = systemStream;
this.graphicsStream = graphicsStream;
}
/// <summary>
/// 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)
{
// write to system stream...
systemStream.Position = Position & ~SYSTEM_BASE;
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
var buf = (byte[])value.Clone();
Array.Reverse(buf);
systemStream.Write(buf, 0, buf.Length);
}
else
{
systemStream.Write(value, 0, value.Length);
}
Position = systemStream.Position | 0x50000000;
return;
}
if ((Position & GRAPHICS_BASE) == GRAPHICS_BASE)
{
// write to graphic stream...
graphicsStream.Position = Position & ~GRAPHICS_BASE;
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
var buf = (byte[])value.Clone();
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>
/// Writes a block.
/// </summary>
public void WriteBlock(IResourceBlock value)
{
value.Write(this);
}
public void WriteStruct<T>(T val) where T : struct
{
int size = Marshal.SizeOf(typeof(T));
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);
}
}
/// <summary>
/// Represents a data block in a resource file.
/// </summary>
public interface IResourceBlock
{
/// <summary>
/// Gets or sets the position of the data block.
/// </summary>
long FilePosition { get; set; }
/// <summary>
/// Gets the length of the data block.
/// </summary>
long BlockLength { get; }
/// <summary>
/// Reads the data block.
/// </summary>
void Read(ResourceDataReader reader, params object[] parameters);
/// <summary>
/// Writes the data block.
/// </summary>
void Write(ResourceDataWriter writer, params object[] parameters);
}
/// <summary>
/// Represents a data block of the system segement in a resource file.
/// </summary>
public interface IResourceSystemBlock : IResourceBlock
{
/// <summary>
/// Returns a list of data blocks that are part of this block.
/// </summary>
Tuple<long, IResourceBlock>[] GetParts();
/// <summary>
/// Returns a list of data blocks that are referenced by this block.
/// </summary>
IResourceBlock[] GetReferences();
}
public interface IResourceXXSystemBlock : IResourceSystemBlock
{
IResourceSystemBlock GetType(ResourceDataReader reader, params object[] parameters);
}
/// <summary>
/// Represents a data block of the graphics segmenet in a resource file.
/// </summary>
public interface IResourceGraphicsBlock : IResourceBlock
{ }
/// <summary>
/// Represents a data block of the system segement in a resource file.
/// </summary>
[TypeConverter(typeof(ExpandableObjectConverter))] public abstract class ResourceSystemBlock : IResourceSystemBlock
{
private long position;
/// <summary>
/// Gets or sets the position of the data block.
/// </summary>
public virtual long FilePosition
{
get
{
return position;
}
set
{
position = value;
foreach (var part in GetParts())
{
part.Item2.FilePosition = value + part.Item1;
}
}
}
/// <summary>
/// Gets the length of the data block.
/// </summary>
public abstract long BlockLength
{
get;
}
/// <summary>
/// Reads the data block.
/// </summary>
public abstract void Read(ResourceDataReader reader, params object[] parameters);
/// <summary>
/// Writes the data block.
/// </summary>
public abstract void Write(ResourceDataWriter writer, params object[] parameters);
/// <summary>
/// Returns a list of data blocks that are part of this block.
/// </summary>
public virtual Tuple<long, IResourceBlock>[] GetParts()
{
return new Tuple<long, IResourceBlock>[0];
}
/// <summary>
/// Returns a list of data blocks that are referenced by this block.
/// </summary>
public virtual IResourceBlock[] GetReferences()
{
return new IResourceBlock[0];
}
}
public abstract class ResourecTypedSystemBlock : ResourceSystemBlock, IResourceXXSystemBlock
{
public abstract IResourceSystemBlock GetType(ResourceDataReader reader, params object[] parameters);
}
/// <summary>
/// Represents a data block of the graphics segmenet in a resource file.
/// </summary>
public abstract class ResourceGraphicsBlock : IResourceGraphicsBlock
{
/// <summary>
/// Gets or sets the position of the data block.
/// </summary>
public virtual long FilePosition
{
get;
set;
}
/// <summary>
/// Gets the length of the data block.
/// </summary>
public abstract long BlockLength
{
get;
}
/// <summary>
/// Reads the data block.
/// </summary>
public abstract void Read(ResourceDataReader reader, params object[] parameters);
/// <summary>
/// Writes the data block.
/// </summary>
public abstract void Write(ResourceDataWriter writer, params object[] parameters);
}
public class ResourceSystemDataBlock : ResourceSystemBlock //used for writing resources.
{
public byte[] Data { get; set; }
public int DataLength { get; set; }
public override long BlockLength
{
get
{
return (Data != null) ? Data.Length : DataLength;
}
}
public ResourceSystemDataBlock(byte[] data)
{
Data = data;
DataLength = (Data != null) ? Data.Length : 0;
}
public override void Read(ResourceDataReader reader, params object[] parameters)
{
Data = reader.ReadBytes(DataLength);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
writer.Write(Data);
}
}
public class ResourceSystemStructBlock<T> : ResourceSystemBlock where T : struct //used for writing resources.
{
public T[] Items { get; set; }
public int ItemCount { get; set; }
public int StructureSize { get; set; }
public override long BlockLength
{
get
{
return ((Items != null) ? Items.Length : ItemCount) * StructureSize;
}
}
public ResourceSystemStructBlock(T[] items)
{
Items = items;
ItemCount = (Items != null) ? Items.Length : 0;
StructureSize = Marshal.SizeOf(typeof(T));
}
public override void Read(ResourceDataReader reader, params object[] parameters)
{
int datalength = ItemCount * StructureSize;
byte[] data = reader.ReadBytes(datalength);
Items = MetaTypes.ConvertDataArray<T>(data, 0, ItemCount);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
byte[] data = MetaTypes.ConvertArrayToBytes(Items);
writer.Write(data);
}
}
//public interface ResourceDataStruct
//{
// void Read(ResourceDataReader reader);
// void Write(ResourceDataWriter writer);
//}
}

View File

@ -0,0 +1,148 @@
/*
Copyright(c) 2015 Neodymium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
//shamelessly stolen and mangled
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class ResourceFileBase : ResourceSystemBlock
{
public override long BlockLength
{
get { return 16; }
}
// structure data
public uint FileVFT { get; set; }
public uint FileUnknown { get; set; }
public ulong FilePagesInfoPointer { get; set; }
// reference data
public ResourcePagesInfo FilePagesInfo { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.FileVFT = reader.ReadUInt32();
this.FileUnknown = reader.ReadUInt32();
this.FilePagesInfoPointer = reader.ReadUInt64();
// read reference data
this.FilePagesInfo = reader.ReadBlockAt<ResourcePagesInfo>(
this.FilePagesInfoPointer // offset
);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// update structure data
this.FilePagesInfoPointer = (ulong)(this.FilePagesInfo != null ? this.FilePagesInfo.FilePosition : 0);
// write structure data
writer.Write(this.FileVFT);
writer.Write(this.FileUnknown);
writer.Write(this.FilePagesInfoPointer);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
if (FilePagesInfo != null) list.Add(FilePagesInfo);
return list.ToArray();
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class ResourcePagesInfo : ResourceSystemBlock
{
public override long BlockLength
{
get { return 20; }
}
// structure data
public uint Unknown_0h { get; set; }
public uint Unknown_4h { get; set; }
public byte SystemPagesCount { get; set; }
public byte GraphicsPagesCount { get; set; }
public ushort Unknown_Ah { get; set; }
public uint Unknown_Ch { get; set; }
public uint Unknown_10h { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.Unknown_0h = reader.ReadUInt32();
this.Unknown_4h = reader.ReadUInt32();
this.SystemPagesCount = reader.ReadByte();
this.GraphicsPagesCount = reader.ReadByte();
this.Unknown_Ah = reader.ReadUInt16();
this.Unknown_Ch = reader.ReadUInt32();
this.Unknown_10h = reader.ReadUInt32();
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// write structure data
writer.Write(this.Unknown_0h);
writer.Write(this.Unknown_4h);
writer.Write(this.SystemPagesCount);
writer.Write(this.GraphicsPagesCount);
writer.Write(this.Unknown_Ah);
writer.Write(this.Unknown_Ch);
writer.Write(this.Unknown_10h);
}
public override string ToString()
{
return SystemPagesCount.ToString() + ", " + GraphicsPagesCount.ToString();
}
}
}

View File

@ -0,0 +1,445 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
[TypeConverter(typeof(ExpandableObjectConverter))] public class TextureDictionary : ResourceFileBase
{
public override long BlockLength
{
get
{
return 64;
}
}
// structure data
public uint Unknown_10h { get; set; } // 0x00000000
public uint Unknown_14h { get; set; } // 0x00000000
public uint Unknown_18h { get; set; } // 0x00000001
public uint Unknown_1Ch { get; set; } // 0x00000000
public ResourceSimpleList64Ptr TextureNameHashesPtr { get; set; }
public uint[] TextureNameHashes { get; set; }
public ResourcePointerList64<Texture> Textures { get; set; }
public Dictionary<uint, Texture> Dict { get; set; }
public long MemoryUsage
{
get
{
long val = 0;
if ((Textures != null) && (Textures.data_items != null))
{
foreach (var tex in Textures.data_items)
{
if (tex != null)
{
val += tex.MemoryUsage;
}
}
}
return val;
}
}
public TextureDictionary()
{
//this.TextureNameHashes = new ResourceSimpleList64<uint_r>();
this.Textures = new ResourcePointerList64<Texture>();
}
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
// read structure data
this.Unknown_10h = reader.ReadUInt32();
this.Unknown_14h = reader.ReadUInt32();
this.Unknown_18h = reader.ReadUInt32();
this.Unknown_1Ch = reader.ReadUInt32();
this.TextureNameHashesPtr = reader.ReadStruct<ResourceSimpleList64Ptr>();
this.TextureNameHashes = reader.ReadUintsAt(this.TextureNameHashesPtr.EntriesPointer, this.TextureNameHashesPtr.EntriesCount);
//this.TextureNameHashes = reader.ReadBlock<ResourceSimpleList64<uint_r>>();
this.Textures = reader.ReadBlock<ResourcePointerList64<Texture>>();
var dict = new Dictionary<uint, Texture>();
if ((Textures != null) && (Textures.data_items != null) && (TextureNameHashes != null))
{
for (int i = 0; (i < Textures.data_items.Length) && (i < TextureNameHashes.Length); i++)
{
var tex = Textures.data_items[i];
var hash = TextureNameHashes[i];
dict[hash] = tex;
}
}
Dict = new Dictionary<uint, Texture>(dict);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
// write structure data
writer.Write(this.Unknown_10h);
writer.Write(this.Unknown_14h);
writer.Write(this.Unknown_18h);
writer.Write(this.Unknown_1Ch);
//writer.WriteBlock(this.TextureNameHashes); //TODO: fix!
//writer.WriteBlock(this.Textures);
}
public override Tuple<long, IResourceBlock>[] GetParts()
{
return new Tuple<long, IResourceBlock>[] {
//new Tuple<long, IResourceBlock>(0x20, TextureNameHashes), //TODO: fix!
new Tuple<long, IResourceBlock>(0x30, Textures)
};
}
public Dictionary<uint, Texture> GetDictionary()
{
Dictionary<uint, Texture> td = new Dictionary<uint, Texture>();
if ((Textures != null) && (Textures.data_items != null))
{
var texs = Textures.data_items;
var hashes = TextureNameHashes;
for (int i = 0; (i < texs.Length) && (i < hashes.Length); i++)
{
td.Add(hashes[i], texs[i]);
}
}
return td;
}
public Texture Lookup(uint hash)
{
Texture tex = null;
if (Dict != null)
{
Dict.TryGetValue(hash, out tex);
}
return tex;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class TextureBase : ResourceSystemBlock
{
public override long BlockLength
{
get { return 64; }
}
// structure data
public uint VFT { get; set; }
public uint Unknown_4h { get; set; } // 0x00000001
public uint Unknown_8h { get; set; } // 0x00000000
public uint Unknown_Ch { get; set; } // 0x00000000
public uint Unknown_10h { get; set; } // 0x00000000
public uint Unknown_14h { get; set; } // 0x00000000
public uint Unknown_18h { get; set; } // 0x00000000
public uint Unknown_1Ch { get; set; } // 0x00000000
public uint Unknown_20h { get; set; } // 0x00000000
public uint Unknown_24h { get; set; } // 0x00000000
public ulong NamePointer { get; set; }
public uint Unknown_30h { get; set; }
public uint Unknown_34h { get; set; } // 0x00000000
public uint Unknown_38h { get; set; } // 0x00000000
public uint Unknown_3Ch { get; set; } // 0x00000000
// reference data
public string Name { get; set; }
public uint NameHash { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.VFT = reader.ReadUInt32();
this.Unknown_4h = reader.ReadUInt32();
this.Unknown_8h = reader.ReadUInt32();
this.Unknown_Ch = reader.ReadUInt32();
this.Unknown_10h = reader.ReadUInt32();
this.Unknown_14h = reader.ReadUInt32();
this.Unknown_18h = reader.ReadUInt32();
this.Unknown_1Ch = reader.ReadUInt32();
this.Unknown_20h = reader.ReadUInt32();
this.Unknown_24h = reader.ReadUInt32();
this.NamePointer = reader.ReadUInt64();
this.Unknown_30h = reader.ReadUInt32();
this.Unknown_34h = reader.ReadUInt32();
this.Unknown_38h = reader.ReadUInt32();
this.Unknown_3Ch = reader.ReadUInt32();
// read reference data
this.Name = reader.ReadStringAt( //BlockAt<string_r>(
this.NamePointer // offset
);
if (!string.IsNullOrEmpty(Name))
{
NameHash = JenkHash.GenHash(Name.ToLowerInvariant());
}
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// update structure data
//this.NamePointer = (ulong)(this.Name != null ? this.Name.Position : 0); //TODO: fix
// write structure data
writer.Write(this.VFT);
writer.Write(this.Unknown_4h);
writer.Write(this.Unknown_8h);
writer.Write(this.Unknown_Ch);
writer.Write(this.Unknown_10h);
writer.Write(this.Unknown_14h);
writer.Write(this.Unknown_18h);
writer.Write(this.Unknown_1Ch);
writer.Write(this.Unknown_20h);
writer.Write(this.Unknown_24h);
writer.Write(this.NamePointer);
writer.Write(this.Unknown_30h);
writer.Write(this.Unknown_34h);
writer.Write(this.Unknown_38h);
writer.Write(this.Unknown_3Ch);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>();
//if (Name != null) list.Add(Name); //TODO: fix
return list.ToArray();
}
public override string ToString()
{
return "TextureBase: " + Name;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class Texture : TextureBase
{
public override long BlockLength
{
get { return 144; }
}
// structure data
public uint Unknown_40h { get; set; }
public uint Unknown_44h { get; set; } // 0x00000000
public uint Unknown_48h { get; set; }
public uint Unknown_4Ch { get; set; } // 0x00000000
public ushort Width { get; set; }
public ushort Height { get; set; }
public ushort Unknown_54h { get; set; } // 0x0001
public ushort Stride { get; set; }
public TextureFormat Format { get; set; }
public byte Unknown_5Ch { get; set; } // 0x00
public byte Levels { get; set; }
public ushort Unknown_5Eh { get; set; } // 0x0000
public uint Unknown_60h { get; set; } // 0x00000000
public uint Unknown_64h { get; set; } // 0x00000000
public uint Unknown_68h { get; set; } // 0x00000000
public uint Unknown_6Ch { get; set; } // 0x00000000
public ulong DataPointer { get; set; }
public uint Unknown_78h { get; set; } // 0x00000000
public uint Unknown_7Ch { get; set; } // 0x00000000
public uint Unknown_80h { get; set; } // 0x00000000
public uint Unknown_84h { get; set; } // 0x00000000
public uint Unknown_88h { get; set; } // 0x00000000
public uint Unknown_8Ch { get; set; } // 0x00000000
// reference data
public TextureData Data { get; set; }
public long MemoryUsage
{
get
{
long val = 0;
if (Data != null)
{
val += Data.FullData.LongLength;
}
return val;
}
}
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
// read structure data
this.Unknown_40h = reader.ReadUInt32();
this.Unknown_44h = reader.ReadUInt32();
this.Unknown_48h = reader.ReadUInt32();
this.Unknown_4Ch = reader.ReadUInt32();
this.Width = reader.ReadUInt16();
this.Height = reader.ReadUInt16();
this.Unknown_54h = reader.ReadUInt16();
this.Stride = reader.ReadUInt16();
this.Format = (TextureFormat)reader.ReadUInt32();
this.Unknown_5Ch = reader.ReadByte();
this.Levels = reader.ReadByte();
this.Unknown_5Eh = reader.ReadUInt16();
this.Unknown_60h = reader.ReadUInt32();
this.Unknown_64h = reader.ReadUInt32();
this.Unknown_68h = reader.ReadUInt32();
this.Unknown_6Ch = reader.ReadUInt32();
this.DataPointer = reader.ReadUInt64();
this.Unknown_78h = reader.ReadUInt32();
this.Unknown_7Ch = reader.ReadUInt32();
this.Unknown_80h = reader.ReadUInt32();
this.Unknown_84h = reader.ReadUInt32();
this.Unknown_88h = reader.ReadUInt32();
this.Unknown_8Ch = reader.ReadUInt32();
// read reference data
this.Data = reader.ReadBlockAt<TextureData>(
this.DataPointer, // offset
this.Format,
this.Width,
this.Height,
this.Levels,
this.Stride
);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
this.DataPointer = (ulong)this.Data.FilePosition;
// write structure data
writer.Write(this.Unknown_40h);
writer.Write(this.Unknown_44h);
writer.Write(this.Unknown_48h);
writer.Write(this.Unknown_4Ch);
writer.Write(this.Width);
writer.Write(this.Height);
writer.Write(this.Unknown_54h);
writer.Write(this.Stride);
writer.Write((uint)this.Format);
writer.Write(this.Unknown_5Ch);
writer.Write(this.Levels);
writer.Write(this.Unknown_5Eh);
writer.Write(this.Unknown_60h);
writer.Write(this.Unknown_64h);
writer.Write(this.Unknown_68h);
writer.Write(this.Unknown_6Ch);
writer.Write(this.DataPointer);
writer.Write(this.Unknown_78h);
writer.Write(this.Unknown_7Ch);
writer.Write(this.Unknown_80h);
writer.Write(this.Unknown_84h);
writer.Write(this.Unknown_88h);
writer.Write(this.Unknown_8Ch);
}
/// <summary>
/// Returns a list of data blocks which are referenced by this block.
/// </summary>
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>(base.GetReferences());
list.Add(Data);
return list.ToArray();
}
public override string ToString()
{
return "Texture: " + Width.ToString() + "x" + Height.ToString() + ": " + Name;
}
}
[TypeConverter(typeof(ExpandableObjectConverter))] public class TextureData : ResourceGraphicsBlock
{
public override long BlockLength
{
get
{
return FullData.Length;
}
}
public byte[] FullData { get; set; }
/// <summary>
/// Reads the data-block from a stream.
/// </summary>
public override void Read(ResourceDataReader reader, params object[] parameters)
{
uint format = Convert.ToUInt32(parameters[0]);
int Width = Convert.ToInt32(parameters[1]);
int Height = Convert.ToInt32(parameters[2]);
int Levels = Convert.ToInt32(parameters[3]);
int Stride = Convert.ToInt32(parameters[4]);
int fullLength = 0;
int length = Stride * Height;
for (int i = 0; i < Levels; i++)
{
fullLength += length;
length /= 4;
}
FullData = reader.ReadBytes(fullLength);
}
/// <summary>
/// Writes the data-block to a stream.
/// </summary>
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
writer.Write(FullData);
}
}
public enum TextureFormat : uint
{
D3DFMT_A8R8G8B8 = 21,
D3DFMT_A1R5G5B5 = 25,
D3DFMT_A8 = 28,
D3DFMT_A8B8G8R8 = 32,
D3DFMT_L8 = 50,
// fourCC
D3DFMT_DXT1 = 0x31545844,
D3DFMT_DXT3 = 0x33545844,
D3DFMT_DXT5 = 0x35545844,
D3DFMT_ATI1 = 0x31495441,
D3DFMT_ATI2 = 0x32495441,
D3DFMT_BC7 = 0x20374342,
//UNKNOWN
}
}

View File

@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class VehicleRecordList : ResourceFileBase
{
public override long BlockLength => 0x20;
public ResourceSimpleList64<VehicleRecordEntry> Entries;
public VehicleRecordList()
{
this.Entries = new ResourceSimpleList64<VehicleRecordEntry>();
}
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
this.Entries = reader.ReadBlock<ResourceSimpleList64<VehicleRecordEntry>>();
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
writer.WriteBlock(this.Entries);
}
public override Tuple<long, IResourceBlock>[] GetParts()
{
return new Tuple<long, IResourceBlock>[] {
new Tuple<long, IResourceBlock>(16, Entries)
};
}
}
public class VehicleRecordEntry : ResourceSystemBlock
{
// this looks exactly like an rrr entry:
// -> http://www.gtamodding.com/wiki/Carrec
public override long BlockLength => 0x20;
// structure data
public uint Time;
public short VelocityX;
public short VelocityY;
public short VelocityZ;
public sbyte RightX;
public sbyte RightY;
public sbyte RightZ;
public sbyte TopX;
public sbyte TopY;
public sbyte TopZ;
public byte SteeringAngle;
public byte GasPedalPower;
public byte BrakePedalPower;
public byte HandbrakeUsed;
public float PositionX;
public float PositionY;
public float PositionZ;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.Time = reader.ReadUInt32();
this.VelocityX = reader.ReadInt16();
this.VelocityY = reader.ReadInt16();
this.VelocityZ = reader.ReadInt16();
this.RightX = (sbyte)reader.ReadByte();
this.RightY = (sbyte)reader.ReadByte();
this.RightZ = (sbyte)reader.ReadByte();
this.TopX = (sbyte)reader.ReadByte();
this.TopY = (sbyte)reader.ReadByte();
this.TopZ = (sbyte)reader.ReadByte();
this.SteeringAngle = reader.ReadByte();
this.GasPedalPower = reader.ReadByte();
this.BrakePedalPower = reader.ReadByte();
this.HandbrakeUsed = reader.ReadByte();
this.PositionX = reader.ReadSingle();
this.PositionY = reader.ReadSingle();
this.PositionZ = reader.ReadSingle();
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// write structure data
writer.Write(this.Time);
writer.Write(this.VelocityX);
writer.Write(this.VelocityY);
writer.Write(this.VelocityZ);
writer.Write(this.RightX);
writer.Write(this.RightY);
writer.Write(this.RightZ);
writer.Write(this.TopX);
writer.Write(this.TopY);
writer.Write(this.TopZ);
writer.Write(this.SteeringAngle);
writer.Write(this.GasPedalPower);
writer.Write(this.BrakePedalPower);
writer.Write(this.HandbrakeUsed);
writer.Write(this.PositionX);
writer.Write(this.PositionY);
writer.Write(this.PositionZ);
}
}
}

View File

@ -0,0 +1,62 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public enum VertexType : uint
{
Default = 89, //PNCT
DefaultEx = 16473, //PNCTX
PNCCT = 121,
PNCCTTTT = 1017,
PCCNCCTTX = 16639,
PCCNCCT = 127,
PNCTTTX = 16857,
PNCTTX = 16601,
PNCTTTX_2 = 19545,
PNCTTTX_3 = 17113,
PNCCTTX = 16633,
PNCCTTX_2 = 17017,
PNCCTTTX = 17145,
PCCNCCTX = 16511,
PCCNCTX = 16479,
PCCNCT = 95,
PNCCTT = 249,
PNCCTX = 16505,
PCT = 81,
PT = 65,
PTT = 193,
PNC = 25,
PC = 17,
PCC = 7,
PCCH2H4 = 2147500121, //0x80004059 (16473 + 0x80000000) DefaultEx Cloth?
PNCH2 = 2147483737, //0x80000059 (89 + 0x80000000) Default Cloth?
PNCTTTTX = 19673, //normal_spec_detail_dpm_vertdecal_tnt
PNCTTTT = 985,
PCCNCCTT = 255,
PCTT = 209,
PCCCCT = 119,
PCCNC = 31,
PCCNCTT = 223,
PCCNCTTX = 16607,
PCCNCTTT = 479,
PNCTT = 217,
PNCTTT = 473,
}
//vertex data to be used by the editor. TODO: maybe move somewhere else.
public struct EditorVertex
{
public Vector3 Position;
public uint Colour;
}
}

View File

@ -0,0 +1,107 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class WaypointRecordList : ResourceFileBase
{
public override long BlockLength => 0x30;
public uint Unknown_10h; // 0x00000000
public uint Unknown_14h; // 0x00000000
public ulong EntriesPointer;
public uint EntriesCount;
public uint Unknown_24h; // 0x00000000
public uint Unknown_28h; // 0x00000000
public uint Unknown_2Ch; // 0x00000000
public ResourceSimpleArray<WaypointRecordEntry> Entries;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
base.Read(reader, parameters);
this.Unknown_10h = reader.ReadUInt32();
this.Unknown_14h = reader.ReadUInt32();
this.EntriesPointer = reader.ReadUInt64();
this.EntriesCount = reader.ReadUInt32();
this.Unknown_24h = reader.ReadUInt32();
this.Unknown_28h = reader.ReadUInt32();
this.Unknown_2Ch = reader.ReadUInt32();
this.Entries = reader.ReadBlockAt<ResourceSimpleArray<WaypointRecordEntry>>(
this.EntriesPointer, // offset
this.EntriesCount
);
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
base.Write(writer, parameters);
//// update structure data
//this.EntriesPointer = (ulong)(this.Entries?.Position ?? 0);
//this.EntriesCount = (uint)(this.Entries?.Count ?? 0);
// write structure data
writer.Write(this.Unknown_10h);
writer.Write(this.Unknown_14h);
writer.Write(this.EntriesPointer);
writer.Write(this.EntriesCount);
writer.Write(this.Unknown_24h);
writer.Write(this.Unknown_28h);
writer.Write(this.Unknown_2Ch);
}
public override IResourceBlock[] GetReferences()
{
var list = new List<IResourceBlock>(base.GetReferences());
if (Entries != null) list.Add(Entries);
return list.ToArray();
}
}
public class WaypointRecordEntry : ResourceSystemBlock
{
public override long BlockLength => 20;
public float PositionX;
public float PositionY;
public float PositionZ;
public ushort Unk0;
public ushort Unk1;
public ushort Unk2;
public ushort Unk3;
public override void Read(ResourceDataReader reader, params object[] parameters)
{
// read structure data
this.PositionX = reader.ReadSingle();
this.PositionY = reader.ReadSingle();
this.PositionZ = reader.ReadSingle();
this.Unk0 = reader.ReadUInt16();
this.Unk1 = reader.ReadUInt16();
this.Unk2 = reader.ReadUInt16();
this.Unk3 = reader.ReadUInt16();
}
public override void Write(ResourceDataWriter writer, params object[] parameters)
{
// write structure data
writer.Write(this.PositionX);
writer.Write(this.PositionY);
writer.Write(this.PositionZ);
writer.Write(this.Unk0);
writer.Write(this.Unk1);
writer.Write(this.Unk2);
writer.Write(this.Unk3);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,492 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.GameFiles
{
public class RpfManager
{
//for caching and management of RPF file data.
public string Folder { get; private set; }
public string[] ExcludePaths { get; set; }
public bool EnableMods { get; set; }
public Action<string> UpdateStatus { get; private set; }
public Action<string> ErrorLog { get; private set; }
public List<RpfFile> BaseRpfs { get; private set; }
public List<RpfFile> ModRpfs { get; private set; }
public List<RpfFile> DlcRpfs { get; private set; }
public List<RpfFile> AllRpfs { get; private set; }
public List<RpfFile> DlcNoModRpfs { get; private set; }
public List<RpfFile> AllNoModRpfs { get; private set; }
public Dictionary<string, RpfFile> RpfDict { get; private set; }
public Dictionary<string, RpfEntry> EntryDict { get; private set; }
public Dictionary<string, RpfFile> ModRpfDict { get; private set; }
public Dictionary<string, RpfEntry> ModEntryDict { get; private set; }
public volatile bool IsInited = false;
public void Init(string folder, Action<string> updateStatus, Action<string> errorLog, bool rootOnly = false, bool buildIndex = true)
{
UpdateStatus = updateStatus;
ErrorLog = errorLog;
string replpath = folder + "\\";
var sopt = rootOnly ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories;
string[] allfiles = Directory.GetFiles(folder, "*.rpf", sopt);
BaseRpfs = new List<RpfFile>();
ModRpfs = new List<RpfFile>();
DlcRpfs = new List<RpfFile>();
AllRpfs = new List<RpfFile>();
DlcNoModRpfs = new List<RpfFile>();
AllNoModRpfs = new List<RpfFile>();
RpfDict = new Dictionary<string, RpfFile>();
EntryDict = new Dictionary<string, RpfEntry>();
ModRpfDict = new Dictionary<string, RpfFile>();
ModEntryDict = new Dictionary<string, RpfEntry>();
foreach (string rpfpath in allfiles)
{
try
{
RpfFile rf = new RpfFile(rpfpath, rpfpath.Replace(replpath, ""));
if (ExcludePaths != null)
{
bool excl = false;
for (int i = 0; i < ExcludePaths.Length; i++)
{
if (rf.Path.StartsWith(ExcludePaths[i]))
{
excl = true;
break;
}
}
if (excl) continue; //skip files in exclude paths.
}
rf.ScanStructure(updateStatus, errorLog);
AddRpfFile(rf, false, false);
}
catch (Exception ex)
{
errorLog(rpfpath + ": " + ex.ToString());
}
}
if (buildIndex)
{
updateStatus("Building jenkindex...");
BuildBaseJenkIndex();
}
updateStatus("Scan complete");
IsInited = true;
}
public void Init(List<RpfFile> allRpfs)
{
//fast init used by RPF explorer's File cache
AllRpfs = allRpfs;
BaseRpfs = new List<RpfFile>();
ModRpfs = new List<RpfFile>();
DlcRpfs = new List<RpfFile>();
DlcNoModRpfs = new List<RpfFile>();
AllNoModRpfs = new List<RpfFile>();
RpfDict = new Dictionary<string, RpfFile>();
EntryDict = new Dictionary<string, RpfEntry>();
ModRpfDict = new Dictionary<string, RpfFile>();
ModEntryDict = new Dictionary<string, RpfEntry>();
foreach (var rpf in allRpfs)
{
RpfDict[rpf.Path] = rpf;
if (rpf.AllEntries == null) continue;
foreach (var entry in rpf.AllEntries)
{
EntryDict[entry.Path] = entry;
}
}
BuildBaseJenkIndex();
IsInited = true;
}
private void AddRpfFile(RpfFile file, bool isdlc, bool ismod)
{
isdlc = isdlc || (file.NameLower == "dlc.rpf") || (file.NameLower == "update.rpf");
ismod = ismod || (file.Path.StartsWith("mods\\"));
if (file.AllEntries != null)
{
AllRpfs.Add(file);
if (!ismod)
{
AllNoModRpfs.Add(file);
}
if (isdlc)
{
DlcRpfs.Add(file);
if (!ismod)
{
DlcNoModRpfs.Add(file);
}
}
else
{
if (ismod)
{
ModRpfs.Add(file);
}
else
{
BaseRpfs.Add(file);
}
}
if (ismod)
{
ModRpfDict[file.Path.Substring(5)] = file;
}
RpfDict[file.Path] = file;
foreach (RpfEntry entry in file.AllEntries)
{
try
{
if (!string.IsNullOrEmpty(entry.Name))
{
if (ismod)
{
ModEntryDict[entry.Path] = entry;
ModEntryDict[entry.Path.Substring(5)] = entry;
}
else
{
EntryDict[entry.Path] = entry;
}
if (entry is RpfFileEntry)
{
RpfFileEntry fentry = entry as RpfFileEntry;
entry.NameHash = JenkHash.GenHash(entry.NameLower);
int ind = entry.NameLower.LastIndexOf('.');
entry.ShortNameHash = (ind > 0) ? JenkHash.GenHash(entry.NameLower.Substring(0, ind)) : entry.NameHash;
if (entry.ShortNameHash != 0)
{
//EntryHashDict[entry.ShortNameHash] = entry;
}
}
}
}
catch (Exception ex)
{
file.LastError = ex.ToString();
file.LastException = ex;
ErrorLog(entry.Path + ": " + ex.ToString());
}
}
}
if (file.Children != null)
{
foreach (RpfFile cfile in file.Children)
{
AddRpfFile(cfile, isdlc, ismod);
}
}
}
public RpfFile FindRpfFile(string path)
{
RpfFile file = null; //check the dictionary
if (EnableMods && ModRpfDict.TryGetValue(path, out file))
{
return file;
}
if (RpfDict.TryGetValue(path, out file))
{
return file;
}
string lpath = path.ToLowerInvariant(); //try look at names etc
foreach (RpfFile tfile in AllRpfs)
{
if (tfile.NameLower == lpath)
{
return tfile;
}
if (tfile.Path == lpath)
{
return tfile;
}
}
return file;
}
public RpfEntry GetEntry(string path)
{
RpfEntry entry;
string pathl = path.ToLowerInvariant();
if (EnableMods && ModEntryDict.TryGetValue(pathl, out entry))
{
return entry;
}
EntryDict.TryGetValue(pathl, out entry);
if (entry == null)
{
pathl = pathl.Replace("/", "\\");
pathl = pathl.Replace("common:", "common.rpf");
if (EnableMods && ModEntryDict.TryGetValue(pathl, out entry))
{
return entry;
}
EntryDict.TryGetValue(pathl, out entry);
}
return entry;
}
public byte[] GetFileData(string path)
{
byte[] data = null;
RpfFileEntry entry = GetEntry(path) as RpfFileEntry;
if (entry != null)
{
data = entry.File.ExtractFile(entry);
}
return data;
}
public string GetFileUTF8Text(string path)
{
byte[] bytes = GetFileData(path);
if (bytes == null)
{ return string.Empty; } //file not found..
if ((bytes.Length > 3) && (bytes[0] == 0xEF) && (bytes[1] == 0xBB) && (bytes[2] == 0xBF))
{
byte[] newb = new byte[bytes.Length - 3];
for (int i = 3; i < bytes.Length; i++)
{
newb[i - 3] = bytes[i];
}
bytes = newb; //trim starting 3 "magic" bytes?
}
return Encoding.UTF8.GetString(bytes);
}
public XmlDocument GetFileXml(string path)
{
XmlDocument doc = new XmlDocument();
string text = GetFileUTF8Text(path);
if (!string.IsNullOrEmpty(text))
{
doc.LoadXml(text);
}
return doc;
}
public T GetFile<T>(string path) where T : class, PackedFile, new()
{
T file = null;
byte[] data = null;
RpfFileEntry entry = GetEntry(path) as RpfFileEntry;
if (entry != null)
{
data = entry.File.ExtractFile(entry);
}
if (data != null)
{
file = new T();
file.Load(data, entry);
}
return file;
}
public T GetFile<T>(RpfEntry e) where T : class, PackedFile, new()
{
T file = null;
byte[] data = null;
RpfFileEntry entry = e as RpfFileEntry;
if (entry != null)
{
data = entry.File.ExtractFile(entry);
}
if (data != null)
{
file = new T();
file.Load(data, entry);
}
return file;
}
public bool LoadFile<T>(T file, RpfEntry e) where T : class, PackedFile
{
byte[] data = null;
RpfFileEntry entry = e as RpfFileEntry;
if (entry != null)
{
data = entry.File.ExtractFile(entry);
}
if (data != null)
{
file.Load(data, entry);
return true;
}
return false;
}
public void BuildBaseJenkIndex()
{
JenkIndex.Clear();
StringBuilder sb = new StringBuilder();
foreach (RpfFile file in AllRpfs)
{
try
{
JenkIndex.Ensure(file.Name);
foreach (RpfEntry entry in file.AllEntries)
{
var nlow = entry.NameLower;
if (string.IsNullOrEmpty(nlow)) continue;
//JenkIndex.Ensure(entry.Name);
//JenkIndex.Ensure(nlow);
int ind = nlow.LastIndexOf('.');
if (ind > 0)
{
JenkIndex.Ensure(entry.Name.Substring(0, ind));
JenkIndex.Ensure(nlow.Substring(0, ind));
//if (ind < entry.Name.Length - 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));
//}
}
else
{
JenkIndex.Ensure(entry.Name);
JenkIndex.Ensure(nlow);
}
if (nlow.EndsWith(".ydr") || nlow.EndsWith(".yft"))
{
var sname = nlow.Substring(0, nlow.Length - 4);
JenkIndex.Ensure(sname + "_lod");
JenkIndex.Ensure(sname + "_loda");
JenkIndex.Ensure(sname + "_lodb");
}
if (nlow.EndsWith(".ydd"))
{
if (nlow.EndsWith("_children.ydd"))
{
var strn = nlow.Substring(0, nlow.Length - 13);
JenkIndex.Ensure(strn);
JenkIndex.Ensure(strn + "_lod");
JenkIndex.Ensure(strn + "_loda");
JenkIndex.Ensure(strn + "_lodb");
}
var idx = nlow.LastIndexOf('_');
if (idx > 0)
{
var str1 = nlow.Substring(0, idx);
var idx2 = str1.LastIndexOf('_');
if (idx2 > 0)
{
var str2 = str1.Substring(0, idx2);
JenkIndex.Ensure(str2 + "_lod");
var maxi = 100;
for (int i = 1; i <= maxi; i++)
{
var str3 = str2 + "_" + i.ToString().PadLeft(2, '0');
//JenkIndex.Ensure(str3);
JenkIndex.Ensure(str3 + "_lod");
}
}
}
}
if (nlow.EndsWith(".awc")) //create audio container path hashes...
{
string[] parts = entry.Path.Split('\\');
int pl = parts.Length;
if (pl > 2)
{
string fn = parts[pl - 1];
string fd = parts[pl - 2];
string hpath = fn.Substring(0, fn.Length - 4);
if (fd.EndsWith(".rpf"))
{
fd = fd.Substring(0, fd.Length - 4);
}
hpath = fd + "/" + hpath;
if (parts[pl - 3] != "sfx")
{ }//no hit
JenkIndex.Ensure(hpath);
}
}
if (nlow.EndsWith(".nametable"))
{
RpfBinaryFileEntry binfe = entry as RpfBinaryFileEntry;
if (binfe != null)
{
byte[] data = file.ExtractFile(binfe);
if (data != null)
{
sb.Clear();
for (int i = 0; i < data.Length; i++)
{
byte c = data[i];
if (c == 0)
{
string str = sb.ToString();
if (!string.IsNullOrEmpty(str))
{
string strl = str.ToLowerInvariant();
//JenkIndex.Ensure(str);
JenkIndex.Ensure(strl);
////DirMod_Sounds_ entries apparently can be used to infer SP audio strings
////no luck here yet though
//if (strl.StartsWith("dirmod_sounds_") && (strl.Length > 14))
//{
// strl = strl.Substring(14);
// JenkIndex.Ensure(strl);
//}
}
sb.Clear();
}
else
{
sb.Append((char)c);
}
}
}
}
else
{ }
}
}
}
catch
{
//failing silently!! not so good really
}
}
}
}
}

View File

@ -0,0 +1,483 @@
/*
Copyright(c) 2015 Neodymium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
//shamelessly stolen
using SharpDX;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public enum Endianess
{
LittleEndian,
BigEndian
}
public enum DataType
{
Byte = 0,
Int16 = 1,
Int32 = 2,
Int64 = 3,
Uint16 = 4,
Uint32 = 5,
Uint64 = 6,
Float = 7,
Double = 8,
String = 9,
}
public class DataReader
{
private Stream baseStream;
/// <summary>
/// Gets or sets the endianess of the underlying stream.
/// </summary>
public Endianess Endianess
{
get;
set;
}
/// <summary>
/// Gets the length of the underlying stream.
/// </summary>
public virtual long Length
{
get
{
return baseStream.Length;
}
}
/// <summary>
/// Gets or sets the position within the underlying stream.
/// </summary>
public virtual long Position
{
get
{
return baseStream.Position;
}
set
{
baseStream.Position = value;
}
}
/// <summary>
/// Initializes a new data reader for the specified stream.
/// </summary>
public DataReader(Stream stream, Endianess endianess = Endianess.LittleEndian)
{
this.baseStream = stream;
this.Endianess = endianess;
}
/// <summary>
/// Reads data from the underlying stream. This is the only method that directly accesses
/// the data in the underlying stream.
/// </summary>
protected virtual byte[] ReadFromStream(int count, bool ignoreEndianess = false)
{
var buffer = new byte[count];
baseStream.Read(buffer, 0, count);
// handle endianess
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
Array.Reverse(buffer);
}
return buffer;
}
/// <summary>
/// Reads a byte.
/// </summary>
public byte ReadByte()
{
return ReadFromStream(1)[0];
}
/// <summary>
/// Reads a sequence of bytes.
/// </summary>
public byte[] ReadBytes(int count)
{
return ReadFromStream(count, true);
}
/// <summary>
/// Reads a signed 16-bit value.
/// </summary>
public short ReadInt16()
{
return BitConverter.ToInt16(ReadFromStream(2), 0);
}
/// <summary>
/// Reads a signed 32-bit value.
/// </summary>
public int ReadInt32()
{
return BitConverter.ToInt32(ReadFromStream(4), 0);
}
/// <summary>
/// Reads a signed 64-bit value.
/// </summary>
public long ReadInt64()
{
return BitConverter.ToInt64(ReadFromStream(8), 0);
}
/// <summary>
/// Reads an unsigned 16-bit value.
/// </summary>
public ushort ReadUInt16()
{
return BitConverter.ToUInt16(ReadFromStream(2), 0);
}
/// <summary>
/// Reads an unsigned 32-bit value.
/// </summary>
public uint ReadUInt32()
{
return BitConverter.ToUInt32(ReadFromStream(4), 0);
}
/// <summary>
/// Reads an unsigned 64-bit value.
/// </summary>
public ulong ReadUInt64()
{
return BitConverter.ToUInt64(ReadFromStream(8), 0);
}
/// <summary>
/// Reads a single precision floating point value.
/// </summary>
public float ReadSingle()
{
return BitConverter.ToSingle(ReadFromStream(4), 0);
}
/// <summary>
/// Reads a double precision floating point value.
/// </summary>
public double ReadDouble()
{
return BitConverter.ToDouble(ReadFromStream(8), 0);
}
/// <summary>
/// Reads a string.
/// </summary>
public string ReadString()
{
var bytes = new List<byte>();
var temp = ReadFromStream(1)[0];
while (temp != 0)
{
bytes.Add(temp);
temp = ReadFromStream(1)[0];
}
return Encoding.UTF8.GetString(bytes.ToArray());
}
public Vector3 ReadVector3()
{
Vector3 v = new Vector3();
v.X = ReadSingle();
v.Y = ReadSingle();
v.Z = ReadSingle();
return v;
}
public Vector4 ReadVector4()
{
Vector4 v = new Vector4();
v.X = ReadSingle();
v.Y = ReadSingle();
v.Z = ReadSingle();
v.W = ReadSingle();
return v;
}
public Matrix ReadMatrix()
{
Matrix m = new Matrix();
m.M11 = ReadSingle();
m.M21 = ReadSingle();
m.M31 = ReadSingle();
m.M41 = ReadSingle();
m.M12 = ReadSingle();
m.M22 = ReadSingle();
m.M32 = ReadSingle();
m.M42 = ReadSingle();
m.M13 = ReadSingle();
m.M23 = ReadSingle();
m.M33 = ReadSingle();
m.M43 = ReadSingle();
m.M14 = ReadSingle();
m.M24 = ReadSingle();
m.M34 = ReadSingle();
m.M44 = ReadSingle();
return m;
}
//TODO: put this somewhere else...
public static uint SizeOf(DataType type)
{
switch (type)
{
default:
case DataType.Byte: return 1;
case DataType.Int16: return 2;
case DataType.Int32: return 4;
case DataType.Int64: return 8;
case DataType.Uint16: return 2;
case DataType.Uint32: return 4;
case DataType.Uint64: return 8;
case DataType.Float: return 4;
case DataType.Double: return 8;
case DataType.String: return 0; //how long is a string..?
}
}
}
public class DataWriter
{
private Stream baseStream;
/// <summary>
/// Gets or sets the endianess of the underlying stream.
/// </summary>
public Endianess Endianess
{
get;
set;
}
/// <summary>
/// Gets the length of the underlying stream.
/// </summary>
public virtual long Length
{
get
{
return baseStream.Length;
}
}
/// <summary>
/// Gets or sets the position within the underlying stream.
/// </summary>
public virtual long Position
{
get
{
return baseStream.Position;
}
set
{
baseStream.Position = value;
}
}
/// <summary>
/// Initializes a new data writer for the specified stream.
/// </summary>
public DataWriter(Stream stream, Endianess endianess = Endianess.LittleEndian)
{
this.baseStream = stream;
this.Endianess = endianess;
}
/// <summary>
/// Writes data to the underlying stream. This is the only method that directly accesses
/// the data in the underlying stream.
/// </summary>
protected virtual void WriteToStream(byte[] value, bool ignoreEndianess = false)
{
if (!ignoreEndianess && (Endianess == Endianess.BigEndian))
{
var buffer = (byte[])value.Clone();
Array.Reverse(buffer);
baseStream.Write(buffer, 0, buffer.Length);
}
else
{
baseStream.Write(value, 0, value.Length);
}
}
/// <summary>
/// Writes a byte.
/// </summary>
public void Write(byte value)
{
WriteToStream(new byte[] { value });
}
/// <summary>
/// Writes a sequence of bytes.
/// </summary>
public void Write(byte[] value)
{
WriteToStream(value, true);
}
/// <summary>
/// Writes a signed 16-bit value.
/// </summary>
public void Write(short value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a signed 32-bit value.
/// </summary>
public void Write(int value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a signed 64-bit value.
/// </summary>
public void Write(long value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes an unsigned 16-bit value.
/// </summary>
public void Write(ushort value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes an unsigned 32-bit value.
/// </summary>
public void Write(uint value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes an unsigned 64-bit value.
/// </summary>
public void Write(ulong value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a single precision floating point value.
/// </summary>
public void Write(float value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a double precision floating point value.
/// </summary>
public void Write(double value)
{
WriteToStream(BitConverter.GetBytes(value));
}
/// <summary>
/// Writes a string.
/// </summary>
public void Write(string value)
{
foreach (var c in value)
Write((byte)c);
Write((byte)0);
}
public void Write(Vector3 value)
{
Write(value.X);
Write(value.Y);
Write(value.Z);
}
public void Write(Vector4 value)
{
Write(value.X);
Write(value.Y);
Write(value.Z);
Write(value.W);
}
public void Write(Matrix value)
{
Write(value.M11);
Write(value.M21);
Write(value.M31);
Write(value.M41);
Write(value.M12);
Write(value.M22);
Write(value.M32);
Write(value.M42);
Write(value.M13);
Write(value.M23);
Write(value.M33);
Write(value.M43);
Write(value.M14);
Write(value.M24);
Write(value.M34);
Write(value.M44);
}
}
}

View File

@ -0,0 +1,429 @@
/*
Copyright(c) 2015 Neodymium
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
//shamelessly stolen
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class GTACrypto
{
public static byte[] DecryptAES(byte[] data)
{
return DecryptAESData(data, GTA5Keys.PC_AES_KEY);
}
public static byte[] EncryptAES(byte[] data)
{
return EncryptAESData(data, GTA5Keys.PC_AES_KEY);
}
public static byte[] DecryptAESData(byte[] data, byte[] key, int rounds = 1)
{
var rijndael = Rijndael.Create();
rijndael.KeySize = 256;
rijndael.Key = key;
rijndael.BlockSize = 128;
rijndael.Mode = CipherMode.ECB;
rijndael.Padding = PaddingMode.None;
var buffer = (byte[])data.Clone();
var length = data.Length - data.Length % 16;
// decrypt...
if (length > 0)
{
var decryptor = rijndael.CreateDecryptor();
for (var roundIndex = 0; roundIndex < rounds; roundIndex++)
decryptor.TransformBlock(buffer, 0, length, buffer, 0);
}
return buffer;
}
public static byte[] EncryptAESData(byte[] data, byte[] key, int rounds = 1)
{
var rijndael = Rijndael.Create();
rijndael.KeySize = 256;
rijndael.Key = key;
rijndael.BlockSize = 128;
rijndael.Mode = CipherMode.ECB;
rijndael.Padding = PaddingMode.None;
var buffer = (byte[])data.Clone();
var length = data.Length - data.Length % 16;
// encrypt...
if (length > 0)
{
var encryptor = rijndael.CreateEncryptor();
for (var roundIndex = 0; roundIndex < rounds; roundIndex++)
encryptor.TransformBlock(buffer, 0, length, buffer, 0);
}
return buffer;
}
public static byte[] GetNGKey(string name, uint length)
{
uint hash = GTA5Hash.CalculateHash(name);
uint keyidx = (hash + length + (101 - 40)) % 0x65;
return GTA5Keys.PC_NG_KEYS[keyidx];
}
public static byte[] DecryptNG(byte[] data, string name, uint length)
{
byte[] key = GetNGKey(name, length);
return DecryptNG(data, key);
}
public static byte[] DecryptNG(byte[] data, byte[] key)
{
var decryptedData = new byte[data.Length];
var keyuints = new uint[key.Length / 4];
Buffer.BlockCopy(key, 0, keyuints, 0, key.Length);
for (int blockIndex = 0; blockIndex < data.Length / 16; blockIndex++)
{
var encryptedBlock = new byte[16];
Array.Copy(data, 16 * blockIndex, encryptedBlock, 0, 16);
var decryptedBlock = DecryptNGBlock(encryptedBlock, keyuints);
Array.Copy(decryptedBlock, 0, decryptedData, 16 * blockIndex, 16);
}
if (data.Length % 16 != 0)
{
var left = data.Length % 16;
Buffer.BlockCopy(data, data.Length - left, decryptedData, data.Length - left, left);
}
return decryptedData;
}
public static byte[] DecryptNGBlock(byte[] data, uint[] key)
{
var buffer = data;
// prepare key...
var subKeys = new uint[17][];
for (int i = 0; i < 17; i++)
{
subKeys[i] = new uint[4];
subKeys[i][0] = key[4 * i + 0];
subKeys[i][1] = key[4 * i + 1];
subKeys[i][2] = key[4 * i + 2];
subKeys[i][3] = key[4 * i + 3];
}
buffer = DecryptNGRoundA(buffer, subKeys[0], GTA5Keys.PC_NG_DECRYPT_TABLES[0]);
buffer = DecryptNGRoundA(buffer, subKeys[1], GTA5Keys.PC_NG_DECRYPT_TABLES[1]);
for (int k = 2; k <= 15; k++)
buffer = DecryptNGRoundB(buffer, subKeys[k], GTA5Keys.PC_NG_DECRYPT_TABLES[k]);
buffer = DecryptNGRoundA(buffer, subKeys[16], GTA5Keys.PC_NG_DECRYPT_TABLES[16]);
return buffer;
}
// round 1,2,16
public static byte[] DecryptNGRoundA(byte[] data, uint[] key, uint[][] table)
{
var x1 =
table[0][data[0]] ^
table[1][data[1]] ^
table[2][data[2]] ^
table[3][data[3]] ^
key[0];
var x2 =
table[4][data[4]] ^
table[5][data[5]] ^
table[6][data[6]] ^
table[7][data[7]] ^
key[1];
var x3 =
table[8][data[8]] ^
table[9][data[9]] ^
table[10][data[10]] ^
table[11][data[11]] ^
key[2];
var x4 =
table[12][data[12]] ^
table[13][data[13]] ^
table[14][data[14]] ^
table[15][data[15]] ^
key[3];
var result = new byte[16];
Array.Copy(BitConverter.GetBytes(x1), 0, result, 0, 4);
Array.Copy(BitConverter.GetBytes(x2), 0, result, 4, 4);
Array.Copy(BitConverter.GetBytes(x3), 0, result, 8, 4);
Array.Copy(BitConverter.GetBytes(x4), 0, result, 12, 4);
return result;
}
// round 3-15
public static byte[] DecryptNGRoundB(byte[] data, uint[] key, uint[][] table)
{
var x1 =
table[0][data[0]] ^
table[7][data[7]] ^
table[10][data[10]] ^
table[13][data[13]] ^
key[0];
var x2 =
table[1][data[1]] ^
table[4][data[4]] ^
table[11][data[11]] ^
table[14][data[14]] ^
key[1];
var x3 =
table[2][data[2]] ^
table[5][data[5]] ^
table[8][data[8]] ^
table[15][data[15]] ^
key[2];
var x4 =
table[3][data[3]] ^
table[6][data[6]] ^
table[9][data[9]] ^
table[12][data[12]] ^
key[3];
//var result = new byte[16];
//Array.Copy(BitConverter.GetBytes(x1), 0, result, 0, 4);
//Array.Copy(BitConverter.GetBytes(x2), 0, result, 4, 4);
//Array.Copy(BitConverter.GetBytes(x3), 0, result, 8, 4);
//Array.Copy(BitConverter.GetBytes(x4), 0, result, 12, 4);
//return result;
var result = new byte[16];
result[0] = (byte)((x1 >> 0) & 0xFF);
result[1] = (byte)((x1 >> 8) & 0xFF);
result[2] = (byte)((x1 >> 16) & 0xFF);
result[3] = (byte)((x1 >> 24) & 0xFF);
result[4] = (byte)((x2 >> 0) & 0xFF);
result[5] = (byte)((x2 >> 8) & 0xFF);
result[6] = (byte)((x2 >> 16) & 0xFF);
result[7] = (byte)((x2 >> 24) & 0xFF);
result[8] = (byte)((x3 >> 0) & 0xFF);
result[9] = (byte)((x3 >> 8) & 0xFF);
result[10] = (byte)((x3 >> 16) & 0xFF);
result[11] = (byte)((x3 >> 24) & 0xFF);
result[12] = (byte)((x4 >> 0) & 0xFF);
result[13] = (byte)((x4 >> 8) & 0xFF);
result[14] = (byte)((x4 >> 16) & 0xFF);
result[15] = (byte)((x4 >> 24) & 0xFF);
return result;
}
public static byte[] EncryptNG(byte[] data, string name, uint length)
{
byte[] key = GetNGKey(name, length);
return EncryptNG(data, key);
}
public static byte[] EncryptNG(byte[] data, byte[] key)
{
if ((GTA5Keys.PC_NG_ENCRYPT_TABLES == null) || (GTA5Keys.PC_NG_ENCRYPT_LUTs == null))
{
throw new Exception("Unable to encrypt - tables not loaded.");
}
var encryptedData = new byte[data.Length];
var keyuints = new uint[key.Length / 4];
Buffer.BlockCopy(key, 0, keyuints, 0, key.Length);
for (int blockIndex = 0; blockIndex < data.Length / 16; blockIndex++)
{
byte[] decryptedBlock = new byte[16];
Array.Copy(data, 16 * blockIndex, decryptedBlock, 0, 16);
byte[] encryptedBlock = EncryptBlock(decryptedBlock, keyuints);
Array.Copy(encryptedBlock, 0, encryptedData, 16 * blockIndex, 16);
}
if (data.Length % 16 != 0)
{
var left = data.Length % 16;
Buffer.BlockCopy(data, data.Length - left, encryptedData, data.Length - left, left);
}
return encryptedData;
}
public static byte[] EncryptBlock(byte[] data, uint[] key)
{
var buffer = data;
// prepare key...
var subKeys = new uint[17][];
for (int i = 0; i < 17; i++)
{
subKeys[i] = new uint[4];
subKeys[i][0] = key[4 * i + 0];
subKeys[i][1] = key[4 * i + 1];
subKeys[i][2] = key[4 * i + 2];
subKeys[i][3] = key[4 * i + 3];
}
buffer = EncryptRoundA(buffer, subKeys[16], GTA5Keys.PC_NG_ENCRYPT_TABLES[16]);
for (int k = 15; k >= 2; k--)
buffer = EncryptRoundB_LUT(buffer, subKeys[k], GTA5Keys.PC_NG_ENCRYPT_LUTs[k]);
buffer = EncryptRoundA(buffer, subKeys[1], GTA5Keys.PC_NG_ENCRYPT_TABLES[1]);
buffer = EncryptRoundA(buffer, subKeys[0], GTA5Keys.PC_NG_ENCRYPT_TABLES[0]);
return buffer;
}
public static byte[] EncryptRoundA(byte[] data, uint[] key, uint[][] table)
{
// apply xor to data first...
var xorbuf = new byte[16];
Buffer.BlockCopy(key, 0, xorbuf, 0, 16);
var x1 =
table[0][data[0] ^ xorbuf[0]] ^
table[1][data[1] ^ xorbuf[1]] ^
table[2][data[2] ^ xorbuf[2]] ^
table[3][data[3] ^ xorbuf[3]];
var x2 =
table[4][data[4] ^ xorbuf[4]] ^
table[5][data[5] ^ xorbuf[5]] ^
table[6][data[6] ^ xorbuf[6]] ^
table[7][data[7] ^ xorbuf[7]];
var x3 =
table[8][data[8] ^ xorbuf[8]] ^
table[9][data[9] ^ xorbuf[9]] ^
table[10][data[10] ^ xorbuf[10]] ^
table[11][data[11] ^ xorbuf[11]];
var x4 =
table[12][data[12] ^ xorbuf[12]] ^
table[13][data[13] ^ xorbuf[13]] ^
table[14][data[14] ^ xorbuf[14]] ^
table[15][data[15] ^ xorbuf[15]];
var buf = new byte[16];
Array.Copy(BitConverter.GetBytes(x1), 0, buf, 0, 4);
Array.Copy(BitConverter.GetBytes(x2), 0, buf, 4, 4);
Array.Copy(BitConverter.GetBytes(x3), 0, buf, 8, 4);
Array.Copy(BitConverter.GetBytes(x4), 0, buf, 12, 4);
return buf;
}
public static byte[] EncryptRoundA_LUT(byte[] dataOld, uint[] key, GTA5NGLUT[] lut)
{
var data = (byte[])dataOld.Clone();
// apply xor to data first...
var xorbuf = new byte[16];
Buffer.BlockCopy(key, 0, xorbuf, 0, 16);
for (int y = 0; y < 16; y++)
{
data[y] ^= xorbuf[y];
}
return new byte[] {
lut[0].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
lut[1].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
lut[2].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
lut[3].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
lut[4].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
lut[5].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
lut[6].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
lut[7].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
lut[8].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
lut[9].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
lut[10].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
lut[11].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
lut[12].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
lut[13].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
lut[14].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
lut[15].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0))
};
}
public static byte[] EncryptRoundB_LUT(byte[] dataOld, uint[] key, GTA5NGLUT[] lut)
{
var data = (byte[])dataOld.Clone();
// apply xor to data first...
var xorbuf = new byte[16];
Buffer.BlockCopy(key, 0, xorbuf, 0, 16);
for (int y = 0; y < 16; y++)
{
data[y] ^= xorbuf[y];
}
return new byte[] {
lut[0].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
lut[1].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
lut[2].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
lut[3].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
lut[4].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
lut[5].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
lut[6].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
lut[7].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
lut[8].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0)),
lut[9].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
lut[10].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
lut[11].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
lut[12].LookUp(BitConverter.ToUInt32( new byte[] { data[12], data[13], data[14], data[15] }, 0)),
lut[13].LookUp(BitConverter.ToUInt32( new byte[] { data[0], data[1], data[2], data[3] }, 0)),
lut[14].LookUp(BitConverter.ToUInt32( new byte[] { data[4], data[5], data[6], data[7] }, 0)),
lut[15].LookUp(BitConverter.ToUInt32( new byte[] { data[8], data[9], data[10], data[11] }, 0))};
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,264 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.GameFiles
{
public class JenkHash
{
public JenkHashInputEncoding Encoding { get; set; }
public string Text { get; set; }
public int HashInt { get; set; }
public uint HashUint { get; set; }
public string HashHex { get; set; }
public JenkHash(string text, JenkHashInputEncoding encoding)
{
Encoding = encoding;
Text = text;
HashUint = GenHash(text, encoding);
HashInt = (int)HashUint;
HashHex = "0x" + HashUint.ToString("X");
}
public static uint GenHash(string text, JenkHashInputEncoding encoding)
{
uint h = 0;
byte[] chars;
switch (encoding)
{
default:
case JenkHashInputEncoding.UTF8:
chars = UTF8Encoding.UTF8.GetBytes(text);
break;
case JenkHashInputEncoding.ASCII:
chars = ASCIIEncoding.ASCII.GetBytes(text);
break;
}
for (uint i = 0; i < chars.Length; i++)
{
h += chars[i];
h += (h << 10);
h ^= (h >> 6);
}
h += (h << 3);
h ^= (h >> 11);
h += (h << 15);
return h;
}
public static uint GenHash(string text)
{
uint h = 0;
for (int i = 0; i < text.Length; i++)
{
h += (byte)text[i];
h += (h << 10);
h ^= (h >> 6);
}
h += (h << 3);
h ^= (h >> 11);
h += (h << 15);
return h;
}
public static uint GenHash(byte[] data)
{
uint h = 0;
for (uint i = 0; i < data.Length; i++)
{
h += data[i];
h += (h << 10);
h ^= (h >> 6);
}
h += (h << 3);
h ^= (h >> 11);
h += (h << 15);
return h;
}
}
public enum JenkHashInputEncoding
{
UTF8 = 0,
ASCII = 1,
}
public class JenkIndMatch
{
public string Hash { get; set; }
public string Value { get; set; }
public double Score { get; set; }
public JenkIndMatch(string hash, string val)
{
Hash = hash;
Value = val;
CalculateScore();
}
public void CalculateScore()
{
int wordlength = 0;
int wordrank = 0;
string okwordsymbs = " _-.";
string goodwordsymbs = "_";
for (int i = 0; i < Value.Length; i++)
{
char c = Value[i];
bool wordchar = (char.IsLetter(c) || char.IsDigit(c) || goodwordsymbs.Contains(c));
if (wordchar)
{
wordlength++;
}
else if (okwordsymbs.Contains(c))
{
//wordlength++; //don't add this to the score, but allow it to continue the chain
}
else
{
if (wordlength > 2)
{
wordrank += wordlength; //linear word increment, ignoring 1-2char matches
}
wordlength = 0;
}
//wordrank += wordlength; //each sequential letter in a word contributes more to the rank, ie. 1+2+3+4+...
}
if (wordlength > 2)
{
wordrank += wordlength; //linear word increment, ignoring 1-2char matches
}
if (Value.Length > 0)
{
//the max value for a given length when 1+2+3+4+5+..n = n(n+1)/2
//double n = (double)Value.Length;
//double maxscore = n * (n + 1.0) * 0.5;
double n = (double)Value.Length;
Score = (((double)wordrank) / n);
//Score = (((double)wordrank));
}
else
{
Score = 0.0;
}
}
public override string ToString()
{
return string.Format("{0} -> {1} ({2:0.##})", Hash, Value, Score);
}
}
public class JenkIndProblem
{
public string Filename { get; set; }
public string Excuse { get; set; }
public int Line { get; set; }
public JenkIndProblem(string filepath, string excuse, int line)
{
Filename = Path.GetFileName(filepath);
Excuse = excuse;
Line = line;
}
public override string ToString()
{
return string.Format("{0} : {1} at line {2}", Filename, Excuse, Line);
}
}
public static class JenkIndex
{
public static Dictionary<uint, string> Index = new Dictionary<uint, string>();
private static object syncRoot = new object();
public static void Clear()
{
lock (syncRoot)
{
Index.Clear();
}
}
public static bool Ensure(string str)
{
uint hash = JenkHash.GenHash(str);
if (hash == 0) return true;
lock (syncRoot)
{
if (!Index.ContainsKey(hash))
{
Index.Add(hash, str);
return false;
}
}
return true;
}
public static string GetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = hash.ToString();
}
}
return res;
}
public static string TryGetString(uint hash)
{
string res;
lock (syncRoot)
{
if (!Index.TryGetValue(hash, out res))
{
res = string.Empty;
}
}
return res;
}
public static string[] GetAllStrings()
{
string[] res = null;
lock (syncRoot)
{
res = Index.Values.ToArray();
}
return res;
}
}
}

View 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.Core")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CodeWalker.Core")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[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("de50d3a6-b49e-47a0-abe6-101473a00759")]
// 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")]

View File

@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CodeWalker.Core.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CodeWalker.Core.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized resource of type System.Byte[].
/// </summary>
internal static byte[] magic {
get {
object obj = ResourceManager.GetObject("magic", resourceCulture);
return ((byte[])(obj));
}
}
}
}

View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="magic" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\magic.dat;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
</root>

Binary file not shown.

View File

@ -0,0 +1,121 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace CodeWalker
{
public class Cache<TKey, TVal> where TVal : Cacheable<TKey>
{
public long MaxMemoryUsage = 536870912; //512mb
public long CurrentMemoryUsage = 0;
public double CacheTime = 5.0; //seconds to keep something that's not used
private LinkedList<TVal> loadedList = new LinkedList<TVal>();
private Dictionary<TKey, LinkedListNode<TVal>> loadedListDict = new Dictionary<TKey, LinkedListNode<TVal>>();
public Cache()
{
}
public Cache(long maxMemoryUsage, double cacheTime)
{
MaxMemoryUsage = maxMemoryUsage;
CacheTime = cacheTime;
}
public TVal TryGet(TKey key)
{
LinkedListNode<TVal> lln = null;
if (loadedListDict.TryGetValue(key, out lln))
{
loadedList.Remove(lln);
loadedList.AddLast(lln);
lln.Value.LastUseTime = DateTime.Now;
}
return (lln != null) ? lln.Value : null;
}
public bool TryAdd(TKey key, TVal item)
{
if (item.MemoryUsage == 0)
{
}
item.Key = key;
if (CanAdd())
{
var lln = loadedList.AddLast(item);
loadedListDict.Add(key, lln);
Interlocked.Add(ref CurrentMemoryUsage, item.MemoryUsage);
return true;
}
else
{
//cache full, check the front of the list for oldest..
var oldlln = loadedList.First;
var cachetime = CacheTime;
int iter = 0, maxiter = 2;
while (!CanAdd() && (iter<maxiter))
{
while ((!CanAdd()) && (oldlln != null) && ((DateTime.Now - oldlln.Value.LastUseTime).TotalSeconds > cachetime))
{
Interlocked.Add(ref CurrentMemoryUsage, -oldlln.Value.MemoryUsage);
loadedListDict.Remove(oldlln.Value.Key);
loadedList.Remove(oldlln); //gc should free up memory later..
oldlln.Value = null;
oldlln = null;
//GC.Collect();
oldlln = loadedList.First;
}
cachetime *= 0.5;
iter++;
}
if (CanAdd()) //see if there's enough memory now...
{
var newlln = loadedList.AddLast(item);
loadedListDict.Add(key, newlln);
Interlocked.Add(ref CurrentMemoryUsage, item.MemoryUsage);
return true;
}
else
{
//really shouldn't get here, but it's possible under stress.
}
}
return false;
}
public bool CanAdd()
{
return Interlocked.Read(ref CurrentMemoryUsage) < MaxMemoryUsage;
}
public void Clear()
{
loadedList.Clear();
loadedListDict.Clear();
CurrentMemoryUsage = 0;
}
public void Remove(TKey key)
{
LinkedListNode<TVal> n;
if (loadedListDict.TryGetValue(key, out n))
{
loadedListDict.Remove(key);
loadedList.Remove(n);
CurrentMemoryUsage -= n.Value.MemoryUsage;
}
}
}
public abstract class Cacheable<TKey>
{
public TKey Key;
public DateTime LastUseTime = DateTime.Now;
public long MemoryUsage;
}
}

View File

@ -0,0 +1,42 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker
{
public static class MatrixExtensions
{
public static Vector3 MultiplyW(this Matrix m, Vector3 v)
{
float x = (((m.M11 * v.X) + (m.M21 * v.Y)) + (m.M31 * v.Z)) + m.M41;
float y = (((m.M12 * v.X) + (m.M22 * v.Y)) + (m.M32 * v.Z)) + m.M42;
float z = (((m.M13 * v.X) + (m.M23 * v.Y)) + (m.M33 * v.Z)) + m.M43;
float w = (((m.M14 * v.X) + (m.M24 * v.Y)) + (m.M34 * v.Z)) + m.M44;
float iw = 1.0f / Math.Abs(w);
return new Vector3(x * iw, y * iw, z * iw);
}
public static Vector3 Multiply(this Matrix m, Vector3 v)
{
float x = (((m.M11 * v.X) + (m.M21 * v.Y)) + (m.M31 * v.Z)) + m.M41;
float y = (((m.M12 * v.X) + (m.M22 * v.Y)) + (m.M32 * v.Z)) + m.M42;
float z = (((m.M13 * v.X) + (m.M23 * v.Y)) + (m.M33 * v.Z)) + m.M43;
return new Vector3(x, y, z);
//this quick mul ignores W...
}
public static Vector4 Multiply(this Matrix m, Vector4 v)
{
float x = (((m.M11 * v.X) + (m.M21 * v.Y)) + (m.M31 * v.Z)) + m.M41;
float y = (((m.M12 * v.X) + (m.M22 * v.Y)) + (m.M32 * v.Z)) + m.M42;
float z = (((m.M13 * v.X) + (m.M23 * v.Y)) + (m.M33 * v.Z)) + m.M43;
float w = (((m.M14 * v.X) + (m.M24 * v.Y)) + (m.M34 * v.Z)) + m.M44;
return new Vector4(x, y, z, w);
}
}
}

View File

@ -0,0 +1,74 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker
{
public static class QuaternionExtension
{
public static Vector3 Multiply(this Quaternion a, Vector3 b)
{
float axx = a.X * 2.0f;
float ayy = a.Y * 2.0f;
float azz = a.Z * 2.0f;
float awxx = a.W * axx;
float awyy = a.W * ayy;
float awzz = a.W * azz;
float axxx = a.X * axx;
float axyy = a.X * ayy;
float axzz = a.X * azz;
float ayyy = a.Y * ayy;
float ayzz = a.Y * azz;
float azzz = a.Z * azz;
return new Vector3(((b.X * ((1.0f - ayyy) - azzz)) + (b.Y * (axyy - awzz))) + (b.Z * (axzz + awyy)),
((b.X * (axyy + awzz)) + (b.Y * ((1.0f - axxx) - azzz))) + (b.Z * (ayzz - awxx)),
((b.X * (axzz - awyy)) + (b.Y * (ayzz + awxx))) + (b.Z * ((1.0f - axxx) - ayyy)));
}
public static Matrix ToMatrix(this Quaternion q)
{
float xx = q.X * q.X;
float yy = q.Y * q.Y;
float zz = q.Z * q.Z;
float xy = q.X * q.Y;
float zw = q.Z * q.W;
float zx = q.Z * q.X;
float yw = q.Y * q.W;
float yz = q.Y * q.Z;
float xw = q.X * q.W;
Matrix result = new Matrix();
result.M11 = 1.0f - (2.0f * (yy + zz));
result.M12 = 2.0f * (xy + zw);
result.M13 = 2.0f * (zx - yw);
result.M14 = 0.0f;
result.M21 = 2.0f * (xy - zw);
result.M22 = 1.0f - (2.0f * (zz + xx));
result.M23 = 2.0f * (yz + xw);
result.M24 = 0.0f;
result.M31 = 2.0f * (zx + yw);
result.M32 = 2.0f * (yz - xw);
result.M33 = 1.0f - (2.0f * (yy + xx));
result.M34 = 0.0f;
result.M41 = 0.0f;
result.M42 = 0.0f;
result.M43 = 0.0f;
result.M44 = 1.0f;
return result;
}
public static Vector4 ToVector4(this Quaternion q)
{
return new Vector4(q.X, q.Y, q.Z, q.W);
}
}
}

View File

@ -0,0 +1,221 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker
{
public static class TextUtil
{
public static string GetBytesReadable(long i)
{
//shamelessly stolen from stackoverflow, and a bit mangled
// Returns the human-readable file size for an arbitrary, 64-bit file size
// The default format is "0.### XB", e.g. "4.2 KB" or "1.434 GB"
// Get absolute value
long absolute_i = (i < 0 ? -i : i);
// Determine the suffix and readable value
string suffix;
double readable;
if (absolute_i >= 0x1000000000000000) // Exabyte
{
suffix = "EB";
readable = (i >> 50);
}
else if (absolute_i >= 0x4000000000000) // Petabyte
{
suffix = "PB";
readable = (i >> 40);
}
else if (absolute_i >= 0x10000000000) // Terabyte
{
suffix = "TB";
readable = (i >> 30);
}
else if (absolute_i >= 0x40000000) // Gigabyte
{
suffix = "GB";
readable = (i >> 20);
}
else if (absolute_i >= 0x100000) // Megabyte
{
suffix = "MB";
readable = (i >> 10);
}
else if (absolute_i >= 0x400) // Kilobyte
{
suffix = "KB";
readable = i;
}
else
{
return i.ToString("0 bytes"); // Byte
}
// Divide by 1024 to get fractional value
readable = (readable / 1024);
string fmt = "0.### ";
if (readable > 1000)
{
fmt = "0";
}
else if (readable > 100)
{
fmt = "0.#";
}
else if (readable > 10)
{
fmt = "0.##";
}
// Return formatted number with suffix
return readable.ToString(fmt) + suffix;
}
}
public static class FloatUtil
{
public static bool TryParse(string s, out float f)
{
f = 0.0f;
if (float.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out f))
{
return true;
}
return false;
}
public static float Parse(string s)
{
float f;
TryParse(s, out f);
return f;
}
public static string ToString(float f)
{
var c = CultureInfo.InvariantCulture;
return f.ToString(c);
}
public static string GetVector2String(Vector2 v)
{
var c = CultureInfo.InvariantCulture;
return v.X.ToString(c) + ", " + v.Y.ToString(c);
}
public static string GetVector3String(Vector3 v)
{
var c = CultureInfo.InvariantCulture;
return v.X.ToString(c) + ", " + v.Y.ToString(c) + ", " + v.Z.ToString(c);
}
public static string GetVector3String(Vector3 v, string format)
{
var c = CultureInfo.InvariantCulture;
return v.X.ToString(format, c) + ", " + v.Y.ToString(format, c) + ", " + v.Z.ToString(format, c);
}
public static string GetVector3XmlString(Vector3 v)
{
var c = CultureInfo.InvariantCulture;
return string.Format("x=\"{0}\" y=\"{1}\" z=\"{2}\"", v.X.ToString(c), v.Y.ToString(c), v.Z.ToString(c));
}
public static string GetVector4XmlString(Vector4 v)
{
var c = CultureInfo.InvariantCulture;
return string.Format("x=\"{0}\" y=\"{1}\" z=\"{2}\" w=\"{3}\"", v.X.ToString(c), v.Y.ToString(c), v.Z.ToString(c), v.W.ToString(c));
}
public static string GetQuaternionXmlString(Quaternion q)
{
var c = CultureInfo.InvariantCulture;
return string.Format("x=\"{0}\" y=\"{1}\" z=\"{2}\" w=\"{3}\"", q.X.ToString(c), q.Y.ToString(c), q.Z.ToString(c), q.W.ToString(c));
}
public static Vector3 ParseVector3String(string s)
{
Vector3 p = new Vector3(0.0f);
string[] ss = s.Split(',');
if (ss.Length > 0)
{
FloatUtil.TryParse(ss[0].Trim(), out p.X);
}
if (ss.Length > 1)
{
FloatUtil.TryParse(ss[1].Trim(), out p.Y);
}
if (ss.Length > 2)
{
FloatUtil.TryParse(ss[2].Trim(), out p.Z);
}
return p;
}
public static string GetVector4String(Vector4 v)
{
var c = CultureInfo.InvariantCulture;
return v.X.ToString(c) + ", " + v.Y.ToString(c) + ", " + v.Z.ToString(c) + ", " + v.W.ToString(c);
}
public static Vector4 ParseVector4String(string s)
{
Vector4 p = new Vector4(0.0f);
string[] ss = s.Split(',');
if (ss.Length > 0)
{
FloatUtil.TryParse(ss[0].Trim(), out p.X);
}
if (ss.Length > 1)
{
FloatUtil.TryParse(ss[1].Trim(), out p.Y);
}
if (ss.Length > 2)
{
FloatUtil.TryParse(ss[2].Trim(), out p.Z);
}
if (ss.Length > 3)
{
FloatUtil.TryParse(ss[3].Trim(), out p.W);
}
return p;
}
}
public static class BitUtil
{
public static bool IsBitSet(uint value, int bit)
{
return (((value >> bit) & 1) > 0);
}
public static uint SetBit(uint value, int bit)
{
return (value | (1u << bit));
}
public static uint ClearBit(uint value, int bit)
{
return (value & (~(1u << bit)));
}
public static uint UpdateBit(uint value, int bit, bool flag)
{
if (flag) return SetBit(value, bit);
else return ClearBit(value, bit);
}
}
}

View File

@ -0,0 +1,65 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker
{
public static class Vectors
{
public static Vector3 XYZ(this Vector4 v)
{
return new Vector3(v.X, v.Y, v.Z);
}
public static Vector3 Round(this Vector3 v)
{
return new Vector3((float)Math.Round(v.X), (float)Math.Round(v.Y), (float)Math.Round(v.Z));
}
public static Vector4 Floor(this Vector4 v)
{
return new Vector4((float)Math.Floor(v.X), (float)Math.Floor(v.Y), (float)Math.Floor(v.Z), (float)Math.Floor(v.W));
}
}
public struct Vector2I
{
public int X;
public int Y;
public Vector2I(int x, int y)
{
X = x;
Y = y;
}
public Vector2I(Vector2 v)
{
X = (int)Math.Floor(v.X);
Y = (int)Math.Floor(v.Y);
}
public override string ToString()
{
return X.ToString() + ", " + Y.ToString();
}
public static Vector2I operator +(Vector2I a, Vector2I b)
{
return new Vector2I(a.X + b.X, a.Y + b.Y);
}
public static Vector2I operator -(Vector2I a, Vector2I b)
{
return new Vector2I(a.X - b.X, a.Y - b.Y);
}
}
}

View File

@ -0,0 +1,137 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker
{
public static class Xml
{
public static string GetStringAttribute(XmlNode node, string attribute)
{
if (node == null) return null;
return node.Attributes[attribute]?.InnerText;
}
public static bool GetBoolAttribute(XmlNode node, string attribute)
{
if (node == null) return false;
string val = node.Attributes[attribute]?.InnerText;
bool b;
bool.TryParse(val, out b);
return b;
}
public static int GetIntAttribute(XmlNode node, string attribute)
{
if (node == null) return 0;
string val = node.Attributes[attribute]?.InnerText;
int i;
int.TryParse(val, out i);
return i;
}
public static float GetFloatAttribute(XmlNode node, string attribute)
{
if (node == null) return 0;
string val = node.Attributes[attribute]?.InnerText;
float f;
FloatUtil.TryParse(val, out f);
return f;
}
public static string GetChildInnerText(XmlNode node, string name)
{
if (node == null) return null;
return node.SelectSingleNode(name)?.InnerText;
}
public static bool GetChildBoolInnerText(XmlNode node, string name)
{
if (node == null) return false;
string val = node.SelectSingleNode(name)?.InnerText;
bool b;
bool.TryParse(val, out b);
return b;
}
public static int GetChildIntInnerText(XmlNode node, string name)
{
if (node == null) return 0;
string val = node.SelectSingleNode(name)?.InnerText;
int i;
int.TryParse(val, out i);
return i;
}
public static float GetChildFloatInnerText(XmlNode node, string name)
{
if (node == null) return 0;
string val = node.SelectSingleNode(name)?.InnerText;
float f;
FloatUtil.TryParse(val, out f);
return f;
}
public static bool GetChildBoolAttribute(XmlNode node, string name, string attribute)
{
if (node == null) return false;
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
bool b;
bool.TryParse(val, out b);
return b;
}
public static int GetChildIntAttribute(XmlNode node, string name, string attribute)
{
if (node == null) return 0;
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
int i;
int.TryParse(val, out i);
return i;
}
public static float GetChildFloatAttribute(XmlNode node, string name, string attribute)
{
if (node == null) return 0;
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
float f;
FloatUtil.TryParse(val, out f);
return f;
}
public static string GetChildStringAttribute(XmlNode node, string name, string attribute)
{
if (node == null) return string.Empty;
string val = node.SelectSingleNode(name)?.Attributes[attribute]?.InnerText;
return val;
}
public static Vector3 GetChildVector3Attributes(XmlNode node, string name, string x, string y, string z)
{
float fx = GetChildFloatAttribute(node, name, x);
float fy = GetChildFloatAttribute(node, name, y);
float fz = GetChildFloatAttribute(node, name, z);
return new Vector3(fx, fy, fz);
}
public static XmlElement GetChild(XmlElement element, string name)
{
return element.SelectSingleNode(name) as XmlElement;
}
public static XmlElement AddChild(XmlDocument doc, XmlNode node, string name)
{
XmlElement child = doc.CreateElement(name);
node.AppendChild(child);
return child;
}
public static XmlElement AddChildWithInnerText(XmlDocument doc, XmlNode node, string name, string innerText)
{
XmlElement child = AddChild(doc, node, name);
child.InnerText = innerText;
return child;
}
public static XmlElement AddChildWithAttribute(XmlDocument doc, XmlNode node, string name, string attributeName, string attributeValue)
{
XmlElement child = AddChild(doc, node, name);
child.SetAttribute(attributeName, attributeValue);
return child;
}
}
}

View File

@ -0,0 +1,279 @@
using CodeWalker.GameFiles;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.World
{
public class AudioZones // : BasePathData
{
public volatile bool Inited = false;
public GameFileCache GameFileCache;
//public Vector4[] GetNodePositions()
//{
// return null;
//}
//public EditorVertex[] GetPathVertices()
//{
// return null;
//}
//public EditorVertex[] GetTriangleVertices()
//{
// return TriangleVerts;
//}
//public EditorVertex[] TriangleVerts;
public List<AudioPlacement> Zones = new List<AudioPlacement>();
public List<AudioPlacement> Emitters = new List<AudioPlacement>();
public List<AudioPlacement> AllItems = new List<AudioPlacement>();
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
{
Inited = false;
GameFileCache = gameFileCache;
var rpfman = gameFileCache.RpfMan;
Zones.Clear();
Emitters.Clear();
AllItems.Clear();
Dictionary<uint, RpfFileEntry> datrelentries = new Dictionary<uint, RpfFileEntry>();
var audrpf = rpfman.FindRpfFile("x64\\audio\\audio_rel.rpf");
if (audrpf != null)
{
AddRpfDatRels(audrpf, datrelentries);
}
if (gameFileCache.EnableDlc)
{
var updrpf = rpfman.FindRpfFile("update\\update.rpf");
if (updrpf != null)
{
AddRpfDatRels(updrpf, datrelentries);
}
foreach (var dlcrpf in GameFileCache.DlcActiveRpfs) //load from current dlc rpfs
{
AddRpfDatRels(dlcrpf, datrelentries);
}
}
foreach (var dat151entry in datrelentries.Values)
{
var relfile = rpfman.GetFile<RelFile>(dat151entry);
if (relfile != null)
{
foreach (var reldata in relfile.RelDatas)
{
if (reldata is Dat151AmbientZone)
{
Zones.Add(new AudioPlacement(relfile, reldata as Dat151AmbientZone));
}
else if (reldata is Dat151AmbientEmitter)
{
Emitters.Add(new AudioPlacement(relfile, reldata as Dat151AmbientEmitter));
}
}
}
}
AllItems.AddRange(Zones);
AllItems.AddRange(Emitters);
Inited = true;
}
private void AddRpfDatRels(RpfFile rpffile, Dictionary<uint, RpfFileEntry> datrelentries)
{
if (rpffile.AllEntries == null) return;
foreach (var entry in rpffile.AllEntries)
{
if (entry is RpfFileEntry)
{
RpfFileEntry fentry = entry as RpfFileEntry;
//if (entry.NameLower.EndsWith(".rel"))
//{
// datrelentries[entry.NameHash] = fentry;
//}
if (entry.NameLower.EndsWith(".dat54.rel"))
{
datrelentries[entry.NameHash] = fentry;
}
if (entry.NameLower.EndsWith(".dat151.rel"))
{
datrelentries[entry.NameHash] = fentry;
}
}
}
}
}
public class AudioPlacement
{
public string Name { get; set; }
public MetaHash NameHash { get; set; }
public RelFile RelFile { get; set; }
public Dat151AmbientZone AudioZone { get; set; }
public Dat151AmbientEmitter AudioEmitter { get; set; }
public Dat151ZoneShape Shape { get; set; }
public string ShortTypeName { get; set; }
public string FullTypeName { get; set; }
public Vector3 InnerPos { get; set; }
public Vector3 InnerMin { get; set; }
public Vector3 InnerMax { get; set; }
public float InnerRad { get; set; }
public Quaternion InnerOri { get; set; }
public Vector3 OuterPos { get; set; }
public Vector3 OuterMin { get; set; }
public Vector3 OuterMax { get; set; }
public float OuterRad { get; set; }
public Quaternion OuterOri { get; set; }
public Vector3 Position { get; set; }
public Vector3 HitboxMin { get; set; }
public Vector3 HitboxMax { get; set; }
public Quaternion Orientation { get; set; }
public Quaternion OrientationInv { get; set; }
public float HitSphereRad { get; set; }
public AudioPlacement(RelFile rel, Dat151AmbientZone zone)
{
RelFile = rel;
AudioZone = zone;
Shape = zone.Shape;
ShortTypeName = "AudioZone";
FullTypeName = "Audio Zone";
Name = zone.Name;
NameHash = zone.NameHash;
float deg2rad = (float)(Math.PI / 180.0);
switch (zone.Shape)
{
case Dat151ZoneShape.Box:
InnerPos = zone.InnerPos;
InnerMax = zone.InnerSize * 0.5f;
InnerMin = -InnerMax;
InnerOri = Quaternion.RotationAxis(Vector3.UnitZ, zone.InnerAngle * deg2rad);
break;
case Dat151ZoneShape.Sphere:
InnerPos = zone.InnerPos;
InnerOri = Quaternion.Identity;
InnerRad = zone.InnerSize.X;
OuterRad = zone.OuterSize.X;
break;
case Dat151ZoneShape.Line:
InnerPos = zone.InnerPos;
InnerMin = new Vector3(-1.0f, -1.0f, 0.0f);
InnerMax = new Vector3(1.0f, 1.0f, (zone.InnerSize - zone.InnerPos).Length());
InnerOri = Quaternion.Invert(Quaternion.LookAtLH(zone.InnerPos, zone.InnerSize, Vector3.UnitZ));
break;
}
OuterPos = zone.OuterPos;
OuterMax = zone.OuterSize * 0.5f;
OuterMin = -OuterMax;
OuterOri = Quaternion.RotationAxis(Vector3.UnitZ, zone.OuterAngle * deg2rad);
bool useouter = ((InnerMax.X == 0) || (InnerMax.Y == 0) || (InnerMax.Z == 0));
if (useouter && (zone.Shape != Dat151ZoneShape.Sphere))
{ } //not sure what these are yet!
Position = useouter ? OuterPos : InnerPos;
HitboxMax = useouter ? OuterMax : InnerMax;
HitboxMin = useouter ? OuterMin : InnerMin;
Orientation = useouter ? OuterOri : InnerOri;
OrientationInv = Quaternion.Invert(Orientation);
HitSphereRad = InnerRad;
if (zone.Shape == Dat151ZoneShape.Sphere)
{
Position = InnerPos;
}
}
public AudioPlacement(RelFile rel, Dat151AmbientEmitter emitter)
{
RelFile = rel;
AudioEmitter = emitter;
Shape = Dat151ZoneShape.Sphere;
ShortTypeName = "AudioEmitter";
FullTypeName = "Audio Emitter";
Name = emitter.Name;
NameHash = emitter.NameHash;
Orientation = Quaternion.Identity;
OrientationInv = Quaternion.Identity;
InnerPos = emitter.Position;
OuterPos = InnerPos;
InnerRad = emitter.InnerRad;
OuterRad = emitter.OuterRad;
bool useouter = (InnerRad == 0);
if (useouter)
{
InnerRad = 1;
}
Position = InnerPos;
HitSphereRad = InnerRad;// useouter ? OuterRad : InnerRad;
}
public void SetPosition(Vector3 pos)
{
bool useouter = ((InnerMax.X == 0) || (InnerMax.Y == 0) || (InnerMax.Z == 0));
Vector3 delta = pos - InnerPos;
InnerPos = pos;
OuterPos += delta;
Position = useouter ? OuterPos : InnerPos;
}
public void SetOrientation(Quaternion ori)
{
Orientation = ori;
OrientationInv = Quaternion.Invert(ori);
if (InnerOri == OuterOri)
{
InnerOri = Orientation;
OuterOri = Orientation;
}
else
{
//not sure yet how to allow independent rotation of inner & outer boxes...
//maybe only in project window?
bool useouter = ((InnerMax.X == 0) || (InnerMax.Y == 0) || (InnerMax.Z == 0));
if (useouter)
{
OuterOri = Orientation;
}
else
{
InnerOri = Orientation;
}
}
}
public string GetNameString()
{
if (!string.IsNullOrEmpty(Name)) return Name;
return NameHash.ToString();
}
}
}

View File

@ -0,0 +1,338 @@
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.World
{
public class Camera
{
public Vector3 TargetRotation = Vector3.Zero;
public Vector3 CurrentRotation = Vector3.Zero;
public float Smoothness;// 10.0f;//0.15f;
public float Sensitivity;// 0.005f;
public float TargetDistance = 1.0f;
public float CurrentDistance = 1.0f;
public float ZoomCurrentTime = 0.0f;
public float ZoomTargetTime = 2.0f;
public float ZoomVelocity = 0.0f;
public float ZoomSpeed = 0.1f;
public float Width = 1920.0f;
public float Height = 1080.0f;
public float FieldOfView;// 1.0f;
public float FieldOfViewFactor = 0.5f / (float)Math.Tan(/*FieldOfView*/ 1.0f * 0.5f);
public float AspectRatio = 1920.0f / 1080.0f;
public float ZNear = 0.5f;
public float ZFar = 12000.0f;
public Entity FollowEntity = null;
public Vector3 LocalLookAt = Vector3.ForwardLH;
public float VOffset = 0.0f;
public bool UpdateProj = true;
public bool IsMapView = false;
public bool IsOrthographic = false;
public float OrthographicSize = 20.0f;
public float OrthographicTargetSize = 20.0f;
public Matrix ProjMatrix = Matrix.Identity;
public Vector3 Position = Vector3.Zero;
public Vector3 UpDirection = Vector3.Up;
public Vector3 ViewDirection = Vector3.ForwardLH;
public Quaternion ViewQuaternion = Quaternion.Identity;
public Quaternion ViewInvQuaternion = Quaternion.Identity;
public Matrix ViewMatrix = Matrix.Identity;
public Matrix ViewInvMatrix = Matrix.Identity;
public Matrix ViewProjMatrix = Matrix.Identity;
public Matrix ViewProjInvMatrix = Matrix.Identity;
public Frustum ViewFrustum = new Frustum();
public Vector3 MouseRayNear = Vector3.Zero;
public Vector3 MouseRayFar = Vector3.Zero;
public Ray MouseRay;
private float MouseX = 0;
private float MouseY = 0;
private object syncRoot = new object();
public Camera(float smoothness, float sensitivity, float fov)
{
Smoothness = smoothness;
Sensitivity = sensitivity;
FieldOfView = fov;
FieldOfViewFactor = 0.5f / (float)Math.Tan(FieldOfView * 0.5f);
}
public void SetMousePosition(int x, int y)
{
MouseX = (x / Width) * 2.0f - 1.0f;
MouseY = (y / Height) * -2.0f + 1.0f;
}
public void SetFollowEntity(Entity e)
{
FollowEntity = e;
}
public void Update(float elapsed)
{
lock (syncRoot)
{
UpdateFollow(elapsed);
if (UpdateProj) UpdateProjMatrix();
//float mx = (LastMouseX / Width) * 2.0f;
//float my = (LastMouseY / Height) * -2.0f;
////MousedItem = nullptr;
////MousedThing = nullptr;
////MousedItemSpace = nullptr;
UpdateProjection();//, mx, my);
}
}
private void UpdateFollow(float elapsed)
{
const float ythresh = 1.55f;
const float nythresh = -1.55f;
Vector3 up = Vector3.Up;// new Vector3(0.0f, 1.0f, 0.0f);
if (TargetRotation.Y > ythresh) TargetRotation.Y = ythresh;
if (TargetRotation.Y < nythresh) TargetRotation.Y = nythresh;
float sv = Math.Min(Smoothness * elapsed, 1.0f);
CurrentRotation = CurrentRotation + ((TargetRotation - CurrentRotation) * sv);
if (TargetDistance > 11000.0f) TargetDistance = 11000.0f; //11km max zoom dist
if (TargetDistance < 0.0001f) TargetDistance = 0.0001f; //0.1mm min zoom dist...
ZoomCurrentTime += elapsed;
if (ZoomCurrentTime > ZoomTargetTime) ZoomCurrentTime = ZoomTargetTime;
float currentTime = ZoomCurrentTime / ZoomTargetTime;
float deltaDist = TargetDistance - CurrentDistance;
if (currentTime < 1.0f && deltaDist > 0.0f)
{
//TODO: when to properly reset ZoomCurrentTime?
float y = currentTime*currentTime*currentTime; //powf(currentTime, 3.0f);
deltaDist *= y;
}
CurrentDistance = CurrentDistance + deltaDist * ZoomSpeed;
if (IsOrthographic || IsMapView)
{
if (OrthographicTargetSize > 20000.0f) OrthographicTargetSize = 20000.0f;
if (OrthographicTargetSize < 1.0f) OrthographicTargetSize = 1.0f;
OrthographicSize = OrthographicSize + ((OrthographicTargetSize - OrthographicSize) * sv);
UpdateProj = true;
}
if (IsMapView)
{
//in map view, need a constant view matrix aligned to XY.
Vector3 cpos = new Vector3();
if (FollowEntity != null)
{
cpos = FollowEntity.Position;
}
LocalLookAt = Vector3.Zero;
Position = cpos;
//Position.Z = 1000.0f;
ViewDirection = -Vector3.UnitZ;
UpDirection = Vector3.UnitY;
}
else
{
//normal view mode
Vector3 rdir = new Vector3();
float cryd = (float)Math.Cos(CurrentRotation.Y);
rdir.X = -(float)Math.Sin(-CurrentRotation.X) * cryd;
rdir.Z = -(float)Math.Cos(-CurrentRotation.X) * cryd;
rdir.Y = (float)Math.Sin(CurrentRotation.Y);
Vector3 lookat = new Vector3(0.0f, VOffset, 0.0f);
Vector3 cpos = new Vector3();
if (FollowEntity != null)
{
up = FollowEntity.Orientation.Multiply(up);
lookat = FollowEntity.Orientation.Multiply(lookat);
rdir = FollowEntity.Orientation.Multiply(rdir);
cpos = FollowEntity.Position;
}
LocalLookAt = (rdir * CurrentDistance) + lookat;
Position = cpos + LocalLookAt;
ViewDirection = Vector3.Normalize(-rdir);
UpDirection = up;
}
//M16FLookAt(LocalProjection.ViewMatrix, V3F(0.0f, 0.0f, 0.0f), LocalProjection.ViewDirection, LocalProjection.UpDirection);
ViewQuaternion = Quaternion.LookAtRH(Vector3.Zero, ViewDirection, UpDirection);
ViewInvQuaternion = Quaternion.Invert(ViewQuaternion);
ViewMatrix = ViewQuaternion.ToMatrix();
ViewInvMatrix = Matrix.Invert(ViewMatrix);
}
private void UpdateProjMatrix()
{
if (IsMapView)
{
ProjMatrix = Matrix.OrthoRH(AspectRatio * OrthographicSize, OrthographicSize, 1.0f, 3000.0f);
}
else if (IsOrthographic)
{
ProjMatrix = Matrix.OrthoRH(AspectRatio * OrthographicSize, OrthographicSize, ZNear, ZFar);
}
else
{
ProjMatrix = Matrix.PerspectiveFovRH(FieldOfView, AspectRatio, ZNear, ZFar);
}
//ProjMatrix._33/=ZFar;
//ProjMatrix._43/=ZFar;
UpdateProj = false;
}
private void UpdateProjection() //CameraSpaceProjection& p, float mx, float my)
{
float mx = MouseX;
float my = MouseY;
ViewProjMatrix = Matrix.Multiply(ViewMatrix, ProjMatrix);
ViewProjInvMatrix = Matrix.Invert(ViewProjMatrix);
MouseRayNear = ViewProjInvMatrix.MultiplyW(new Vector3(mx, my, 0.0f));
MouseRayFar = ViewProjInvMatrix.MultiplyW(new Vector3(mx, my, 1.0f));
MouseRay.Position = Vector3.Zero;
MouseRay.Direction = Vector3.Normalize(MouseRayFar - MouseRayNear);
if (IsMapView || IsOrthographic)
{
MouseRay.Position = MouseRayNear;
}
ViewFrustum.Update(ref ViewProjMatrix);
ViewFrustum.Position = Position;
}
private void UpdateMousedItem()
{
//////MousedItem = nullptr;
//////MousedThing = nullptr;
//////MousedItemSpace = nullptr;
////int i = 0;
//////var cp = &SpaceProjections[i++];
//////auto item = cp->MousedItem;
//////auto thing = cp->MousedThing;
////auto count = cp->MouseTestedItems;
//////while((item==nullptr) && (thing==nullptr) && (i<SpaceProjections.size()))
////Moused.Clear();
////if (cp->Moused.HasValue) Moused.Set(cp->Moused);
////while (!Moused.HasValue && (i < SpaceProjections.size()))
////{
//// cp = &SpaceProjections[i++];
//// //item = cp->MousedItem;
//// //thing = cp->MousedThing;
//// if (cp->Moused.HasValue)
//// {
//// Moused.Set(cp->Moused);
//// }
//// count += cp->MouseTestedItems;
////}
//////if((item!=nullptr) || (thing!=nullptr))
//////{
////// MousedItem = item;
////// MousedThing = thing;
////// MousedItemSpace = cp->MousedItemSpace;
//////}
}
public void OnWindowResize(int w, int h)
{
lock (syncRoot)
{
Width = (float)w;
Height = (float)h;
AspectRatio = Width / Height;
UpdateProj = true;
}
}
public void ControllerRotate(float x, float y)
{
lock (syncRoot)
{
TargetRotation.X += x;
TargetRotation.Y += y;
}
}
public void ControllerZoom(float z)
{
lock (syncRoot)
{
float v = (z < 0) ? (1.0f - z) : (z > 0) ? (1.0f / (1.0f + z)) : 1.0f;
TargetDistance *= v;
OrthographicTargetSize *= v;
}
}
public void MouseRotate(int x, int y)
{
lock (syncRoot)
{
TargetRotation.X += x * Sensitivity;
TargetRotation.Y += y * Sensitivity;
}
}
public void MouseZoom(int z)
{
lock (syncRoot)
{
float v = (z < 0) ? 1.1f : (z > 0) ? 1.0f / 1.1f : 1.0f;
TargetDistance *= v;
OrthographicTargetSize *= v;
}
}
}
public class Frustum
{
public Plane[] Planes = new Plane[6];
public Vector3 Position;
public void Update(ref Matrix vp)
{
//left, right, top, bottom, near, far
Planes[0] = Plane.Normalize(new Plane((vp.M14 + vp.M11), (vp.M24 + vp.M21), (vp.M34 + vp.M31), (vp.M44 + vp.M41)));
Planes[1] = Plane.Normalize(new Plane((vp.M14 - vp.M11), (vp.M24 - vp.M21), (vp.M34 - vp.M31), (vp.M44 - vp.M41)));
Planes[2] = Plane.Normalize(new Plane((vp.M14 - vp.M12), (vp.M24 - vp.M22), (vp.M34 - vp.M32), (vp.M44 - vp.M42)));
Planes[3] = Plane.Normalize(new Plane((vp.M14 + vp.M12), (vp.M24 + vp.M22), (vp.M34 + vp.M32), (vp.M44 + vp.M42)));
Planes[4] = Plane.Normalize(new Plane((vp.M13), (vp.M23), (vp.M33), 0.0f));//(vp.M43));
Planes[5] = Plane.Normalize(new Plane((vp.M14 - vp.M13), (vp.M24 - vp.M23), (vp.M34 - vp.M33), (vp.M44 - vp.M43)));
}
//public bool ContainsSphere(ref Vector3 c, float cls, float r)
//{
// //cls = c length squared, for optimization
// if (cls < (r * r))
// {
// return true; //frustrum center is in the sphere
// }
// float nr = -r;
// for (int i = 0; i < 6; i++)
// {
// if (Plane.DotCoordinate(Planes[i], c) < nr)
// {
// return false;
// }
// }
// return true;
//}
public bool ContainsSphereNoClipNoOpt(ref Vector3 c, float r)
{
float nr = -r;
for (int i = 0; i < 5; i++)
{
if (Plane.DotCoordinate(Planes[i], c) < nr)
{
return false;
}
}
return true;
}
}
}

View File

@ -0,0 +1,459 @@
using CodeWalker.GameFiles;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.World
{
public class Clouds
{
public volatile bool Inited = false;
public Weather Weather;
public Timecycle Timecycle;
public Dictionary<string, CloudAnimSetting> AnimSettings { get; set; }
public CloudAnimOverrides AnimOverrides = new CloudAnimOverrides();
public CloudHatManager HatManager;
public CloudSettingsMap SettingsMap;
public Clouds()
{
AnimSettings = new Dictionary<string, CloudAnimSetting>();
AddAnimSetting(new CloudAnimSetting("UVOffset1.X", "UV Offset 1 X", -1.0f, 1.0f, 0.0f));
AddAnimSetting(new CloudAnimSetting("UVOffset1.Y", "UV Offset 1 Y", -1.0f, 1.0f, 0.0f));
AddAnimSetting(new CloudAnimSetting("UVOffset2.X", "UV Offset 2 X", -1.0f, 1.0f, 0.0f));
AddAnimSetting(new CloudAnimSetting("UVOffset2.Y", "UV Offset 2 Y", -1.0f, 1.0f, 0.0f));
AddAnimSetting(new CloudAnimSetting("UVOffset3.X", "UV Offset 3 X", -1.0f, 1.0f, 0.0f));
AddAnimSetting(new CloudAnimSetting("UVOffset3.Y", "UV Offset 3 Y", -1.0f, 1.0f, 0.0f));
//AddAnimSetting(new CloudAnimSetting("RescaleUV1.X", "Rescale UV 1 X", 0.0f, 50.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("RescaleUV1.Y", "Rescale UV 1 Y", 0.0f, 50.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("RescaleUV2.X", "Rescale UV 2 X", 0.0f, 50.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("RescaleUV2.Y", "Rescale UV 2 Y", 0.0f, 50.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("RescaleUV3.X", "Rescale UV 3 X", 0.0f, 50.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("RescaleUV3.Y", "Rescale UV 3 Y", 0.0f, 50.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale1.X", "Anim Scale 1 X", 0.0f, 8.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale1.Y", "Anim Scale 1 Y", 0.0f, 8.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale2.X", "Anim Scale 2 X", 0.0f, 8.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale2.Y", "Anim Scale 2 Y", 0.0f, 8.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale3.X", "Anim Scale 3 X", 0.0f, 8.0f, 1.0f));
//AddAnimSetting(new CloudAnimSetting("cloudLayerAnimScale3.Y", "Anim Scale 3 Y", 0.0f, 8.0f, 1.0f));
}
private void AddAnimSetting(CloudAnimSetting setting)
{
AnimSettings[setting.Name] = setting;
}
private void UpdateAnimOverrides()
{
AnimOverrides.UVOffset1.X = AnimSettings["UVOffset1.X"].CurrentValue;
AnimOverrides.UVOffset1.Y = AnimSettings["UVOffset1.Y"].CurrentValue;
AnimOverrides.UVOffset2.X = AnimSettings["UVOffset2.X"].CurrentValue;
AnimOverrides.UVOffset2.Y = AnimSettings["UVOffset2.Y"].CurrentValue;
AnimOverrides.UVOffset3.X = AnimSettings["UVOffset3.X"].CurrentValue;
AnimOverrides.UVOffset3.Y = AnimSettings["UVOffset3.Y"].CurrentValue;
//AnimOverrides.RescaleUV1.X = AnimSettings["RescaleUV1.X"].CurrentValue;
//AnimOverrides.RescaleUV1.Y = AnimSettings["RescaleUV1.Y"].CurrentValue;
//AnimOverrides.RescaleUV2.X = AnimSettings["RescaleUV2.X"].CurrentValue;
//AnimOverrides.RescaleUV2.Y = AnimSettings["RescaleUV2.Y"].CurrentValue;
//AnimOverrides.RescaleUV3.X = AnimSettings["RescaleUV3.X"].CurrentValue;
//AnimOverrides.RescaleUV3.Y = AnimSettings["RescaleUV3.Y"].CurrentValue;
//AnimOverrides.cloudLayerAnimScale1.X = AnimSettings["cloudLayerAnimScale1.X"].CurrentValue;
//AnimOverrides.cloudLayerAnimScale1.Y = AnimSettings["cloudLayerAnimScale1.Y"].CurrentValue;
//AnimOverrides.cloudLayerAnimScale2.X = AnimSettings["cloudLayerAnimScale2.X"].CurrentValue;
//AnimOverrides.cloudLayerAnimScale2.Y = AnimSettings["cloudLayerAnimScale2.Y"].CurrentValue;
//AnimOverrides.cloudLayerAnimScale3.X = AnimSettings["cloudLayerAnimScale3.X"].CurrentValue;
//AnimOverrides.cloudLayerAnimScale3.Y = AnimSettings["cloudLayerAnimScale3.Y"].CurrentValue;
}
public void Init(GameFileCache gameFileCache, Action<string> updateStatus, Weather weather)
{
Weather = weather;
Timecycle = weather.Timecycle;
var rpfman = gameFileCache.RpfMan;
string filename = "common.rpf\\data\\clouds.xml";
//TODO: RpfMan should be able to get the right version? or maybe let gameFileCache do it!
string kffilename = "common.rpf\\data\\cloudkeyframes.xml";
if (gameFileCache.EnableDlc)
{
kffilename = "update\\update.rpf\\common\\data\\cloudkeyframes.xml";
}
XmlDocument cloudsxml = rpfman.GetFileXml(filename);
XmlDocument cloudskfxml = rpfman.GetFileXml(kffilename);
HatManager = new CloudHatManager();
HatManager.Init(cloudsxml.DocumentElement); //CloudHatManager
SettingsMap = new CloudSettingsMap();
SettingsMap.Init(cloudskfxml.DocumentElement); //CloudSettingsMap
Inited = true;
}
public void Update(float elapsed)
{
UpdateAnimOverrides();
}
}
public class CloudHatManager
{
public CloudHatFrag[] CloudHatFrags { get; set; }
public float DesiredTransitionTimeSec { get; set; }
public Vector3 CamPositionScaler { get; set; }
public float AltitudeScrollScaler { get; set; }
public void Init(XmlElement xml)
{
List<CloudHatFrag> fraglist = new List<CloudHatFrag>();
XmlNodeList frags = xml.SelectNodes("mCloudHatFrags/Item");
foreach (XmlNode node in frags)
{
XmlElement fragel = node as XmlElement;
if (fragel != null)
{
CloudHatFrag frag = new CloudHatFrag();
frag.Init(fragel);
fraglist.Add(frag);
}
}
CloudHatFrags = fraglist.ToArray();
DesiredTransitionTimeSec = Xml.GetChildFloatAttribute(xml, "mDesiredTransitionTimeSec", "value");
CamPositionScaler = Xml.GetChildVector3Attributes(xml, "mCamPositionScaler", "x", "y", "z");
AltitudeScrollScaler = Xml.GetChildFloatAttribute(xml, "mAltitudeScrollScaler", "value");
}
public CloudHatFrag FindFrag(string name)
{
for (int i = 0; i < CloudHatFrags.Length; i++)
{
CloudHatFrag f = CloudHatFrags[i];
if (f.Name == name)
{
return f;
}
}
return null;
}
}
public class CloudHatFrag
{
public Vector3 Position { get; set; }
public Vector3 Rotation { get; set; }
public Vector3 Scale { get; set; }
public string Name { get; set; }
public CloudHatFragLayer[] Layers { get; set; }
public float TransitionAlphaRange { get; set; }
public float TransitionMidPoint { get; set; }
public bool Enabled { get; set; }
public Vector3 AngularVelocity { get; set; }
public Vector3 AnimBlendWeights { get; set; }
public Vector2[] UVVelocity { get; set; }
public byte[] AnimMode { get; set; }
public bool[] ShowLayer { get; set; }
public bool EnableAnimations { get; set; }
public void Init(XmlElement xml)
{
Position = Xml.GetChildVector3Attributes(xml, "mPosition", "x", "y", "z");
Rotation = Xml.GetChildVector3Attributes(xml, "mRotation", "x", "y", "z");
Scale = Xml.GetChildVector3Attributes(xml, "mScale", "x", "y", "z");
Name = Xml.GetChildInnerText(xml, "mName");
List<CloudHatFragLayer> layerlist = new List<CloudHatFragLayer>();
XmlNodeList layersxml = xml.SelectNodes("mLayers/Item");
foreach (XmlNode node in layersxml)
{
XmlElement layerel = node as XmlElement;
if (layerel != null)
{
CloudHatFragLayer layer = new CloudHatFragLayer();
layer.Init(layerel);
layerlist.Add(layer);
}
}
Layers = layerlist.ToArray();
TransitionAlphaRange = Xml.GetChildFloatAttribute(xml, "mTransitionAlphaRange", "value");
TransitionMidPoint = Xml.GetChildFloatAttribute(xml, "mTransitionMidPoint", "value");
Enabled = Xml.GetChildBoolAttribute(xml, "mEnabled", "value");
AngularVelocity = Xml.GetChildVector3Attributes(xml, "mAngularVelocity", "x", "y", "z");
AnimBlendWeights = Xml.GetChildVector3Attributes(xml, "mAnimBlendWeights", "x", "y", "z");
string uvvelocitystr = Xml.GetChildInnerText(xml, "mUVVelocity").Trim();
string[] uvvelocities = uvvelocitystr.Split('\n');
UVVelocity = new Vector2[uvvelocities.Length];
for (int i = 0; i < uvvelocities.Length; i++)
{
Vector2 vel = Vector2.Zero;
string uvvel = uvvelocities[i].Trim();
string[] uvvelc = uvvel.Split('\t');
if (uvvelc.Length == 2)
{
FloatUtil.TryParse(uvvelc[0].Trim(), out vel.X);
FloatUtil.TryParse(uvvelc[1].Trim(), out vel.Y);
}
UVVelocity[i] = vel;
}
string animmodestr = Xml.GetChildInnerText(xml, "mAnimMode").Trim();
string[] animmodes = animmodestr.Split('\n');
AnimMode = new byte[animmodes.Length];
for (int i = 0; i < animmodes.Length; i++)
{
byte.TryParse(animmodes[i].Trim(), out AnimMode[i]);
}
//string showlayerstr = Xml.GetChildInnerText(xml, "mShowLayer").Trim();
XmlNodeList showlayersxml = xml.SelectNodes("mShowLayer/Item");
ShowLayer = new bool[showlayersxml.Count];
for (int i = 0; i < showlayersxml.Count; i++)
{
XmlNode slnode = showlayersxml[i];
if (slnode is XmlElement)
{
ShowLayer[i] = Xml.GetBoolAttribute(slnode, "value");
}
}
EnableAnimations = Xml.GetChildBoolAttribute(xml, "mEnableAnimations", "value");
}
public override string ToString()
{
return Name;
}
}
public class CloudHatFragLayer
{
public string Filename { get; set; }
public float CostFactor { get; set; }
public float RotationScale { get; set; }
public float CamPositionScalerAdjust { get; set; }
public float TransitionInTimePercent { get; set; }
public float TransitionOutTimePercent { get; set; }
public float TransitionInDelayPercent { get; set; }
public float TransitionOutDelayPercent { get; set; }
public float HeightTigger { get; set; }
public float HeightFadeRange { get; set; }
public void Init(XmlElement xml)
{
Filename = Xml.GetChildInnerText(xml, "mFilename");
CostFactor = Xml.GetChildFloatAttribute(xml, "mCostFactor", "value");
RotationScale = Xml.GetChildFloatAttribute(xml, "mRotationScale", "value");
CamPositionScalerAdjust = Xml.GetChildFloatAttribute(xml, "mCamPositionScalerAdjust", "value");
TransitionInTimePercent = Xml.GetChildFloatAttribute(xml, "mTransitionInTimePercent", "value");
TransitionOutTimePercent = Xml.GetChildFloatAttribute(xml, "mTransitionOutTimePercent", "value");
TransitionInDelayPercent = Xml.GetChildFloatAttribute(xml, "mTransitionInDelayPercent", "value");
TransitionOutDelayPercent = Xml.GetChildFloatAttribute(xml, "mTransitionOutDelayPercent", "value");
HeightTigger = Xml.GetChildFloatAttribute(xml, "mHeightTigger", "value");
HeightFadeRange = Xml.GetChildFloatAttribute(xml, "mHeightFadeRange", "value");
}
public override string ToString()
{
return Filename;
}
}
public class CloudSettingsMap
{
public float[] KeyframeTimes { get; set; }
public Dictionary<string, CloudSettingsMapItem> SettingsMap { get; set; }
public void Init(XmlElement xml)
{
string kftstr = Xml.GetChildInnerText(xml, "KeyframeTimes").Trim();
string[] kftarr = kftstr.Split('\n');
KeyframeTimes = new float[kftarr.Length];
for (int i = 0; i < kftarr.Length; i++)
{
FloatUtil.TryParse(kftarr[i].Trim(), out KeyframeTimes[i]);
}
SettingsMap = new Dictionary<string, CloudSettingsMapItem>();
XmlNodeList mapxml = xml.SelectNodes("SettingsMap/Item");
foreach (XmlNode node in mapxml)
{
XmlElement itemel = node as XmlElement;
if (itemel != null)
{
CloudSettingsMapItem item = new CloudSettingsMapItem();
item.Init(itemel);
SettingsMap[item.Name] = item;
}
}
}
}
public class CloudSettingsMapItem
{
public string Name { get; set; }
public CloudSettingsMapCloudList CloudList { get; set; } = new CloudSettingsMapCloudList();
public CloudSettingsMapKeyData CloudColor { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudLightColor { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudAmbientColor { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudSkyColor { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudBounceColor { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudEastColor { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudWestColor { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudScaleFillColors { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudDensityShift_Scale_ScatteringConst_Scale { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudPiercingLightPower_Strength_NormalStrength_Thickness { get; set; } = new CloudSettingsMapKeyData();
public CloudSettingsMapKeyData CloudScaleDiffuseFillAmbient_WrapAmount { get; set; } = new CloudSettingsMapKeyData();
public void Init(XmlNode xml)
{
Name = Xml.GetChildInnerText(xml, "Name");
var snode = xml.SelectSingleNode("Settings");
CloudList.Init(snode.SelectSingleNode("CloudList"));
CloudColor.Init(snode.SelectSingleNode("CloudColor"));
CloudLightColor.Init(snode.SelectSingleNode("CloudLightColor"));
CloudAmbientColor.Init(snode.SelectSingleNode("CloudAmbientColor"));
CloudSkyColor.Init(snode.SelectSingleNode("CloudSkyColor"));
CloudBounceColor.Init(snode.SelectSingleNode("CloudBounceColor"));
CloudEastColor.Init(snode.SelectSingleNode("CloudEastColor"));
CloudWestColor.Init(snode.SelectSingleNode("CloudWestColor"));
CloudScaleFillColors.Init(snode.SelectSingleNode("CloudScaleFillColors"));
CloudDensityShift_Scale_ScatteringConst_Scale.Init(snode.SelectSingleNode("CloudDensityShift_Scale_ScatteringConst_Scale"));
CloudPiercingLightPower_Strength_NormalStrength_Thickness.Init(snode.SelectSingleNode("CloudPiercingLightPower_Strength_NormalStrength_Thickness"));
CloudScaleDiffuseFillAmbient_WrapAmount.Init(snode.SelectSingleNode("CloudScaleDiffuseFillAmbient_WrapAmount"));
}
public override string ToString()
{
return Name;
}
}
public class CloudSettingsMapCloudList
{
public int[] Probability { get; set; }
public int[] Bits { get; set; } //one bit for each cloud hat frag
public void Init(XmlNode xml)
{
string pstr = Xml.GetChildInnerText(xml, "mProbability").Trim();
string bstr = Xml.GetChildInnerText(xml, "mBits").Trim();
string[] parr = pstr.Split('\n');
string[] barr = bstr.Split('\n');
Probability = new int[parr.Length];
Bits = new int[barr.Length];
for (int i = 0; i < parr.Length; i++)
{
int.TryParse(parr[i].Trim(), out Probability[i]);
}
for (int i = 0; i < barr.Length; i++)
{
Bits[i] = Convert.ToInt32(barr[i].Trim(), 16);
}
}
}
public class CloudSettingsMapKeyData
{
public int numKeyEntries { get; set; }
public Dictionary<float, Vector4> keyEntryData { get; set; }
public void Init(XmlNode xml)
{
var kdxml = xml.SelectSingleNode("keyData");
numKeyEntries = Xml.GetChildIntAttribute(kdxml, "numKeyEntries", "value");
string kestr = Xml.GetChildInnerText(kdxml, "keyEntryData").Trim();
string[] kearr = kestr.Split('\n');
keyEntryData = new Dictionary<float, Vector4>();
for (int i = 0; i < kearr.Length; i++)
{
string kvstr = kearr[i].Trim();
string[] kvarr = kvstr.Split('\t');
float key = 0.0f;
Vector4 val = Vector4.Zero;
if (kvarr.Length >= 5)
{
FloatUtil.TryParse(kvarr[0].Trim(), out key);
FloatUtil.TryParse(kvarr[1].Trim(), out val.X);
FloatUtil.TryParse(kvarr[2].Trim(), out val.Y);
FloatUtil.TryParse(kvarr[3].Trim(), out val.Z);
FloatUtil.TryParse(kvarr[4].Trim(), out val.W);
}
else
{ }
keyEntryData[key] = val;
}
}
}
public class CloudAnimSetting
{
public string Name { get; set; }
public string DisplayName { get; set; }
public float MinValue { get; set; }
public float MaxValue { get; set; }
public float DefaultValue { get; set; }
public float CurrentValue { get; set; }
public CloudAnimSetting(string name, string displayname, float minval, float maxval, float defaultval)
{
Name = name;
DisplayName = displayname;
MinValue = minval;
MaxValue = maxval;
DefaultValue = defaultval;
CurrentValue = defaultval;
}
public override string ToString()
{
return DisplayName;
}
}
public class CloudAnimOverrides
{
public Vector2 UVOffset1 = Vector2.Zero;
public Vector2 UVOffset2 = Vector2.Zero;
public Vector2 UVOffset3 = Vector2.Zero;
public Vector2 RescaleUV1 = Vector2.One;
public Vector2 RescaleUV2 = Vector2.One;
public Vector2 RescaleUV3 = Vector2.One;
public Vector2 cloudLayerAnimScale1 = Vector2.One;
public Vector2 cloudLayerAnimScale2 = Vector2.One;
public Vector2 cloudLayerAnimScale3 = Vector2.One;
}
}

View File

@ -0,0 +1,179 @@
using CodeWalker.GameFiles;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.World
{
public class Entity
{
public Space Space;
public YmapEntityDef EntityDef;
public float Radius;
public Vector3 Center;
public Vector3 Position;
public Quaternion Orientation = Quaternion.Identity;
public Quaternion OrientationInv = Quaternion.Identity;
public float Mass;
public Matrix MomentOfInertia;
public Vector3 Momentum;
public Vector3 Velocity;
public Vector3 AngularMomentum;
public Vector3 AngularVelocity;
public bool WasColliding;
public bool EnableCollisions;
public bool Enabled;
//public CollisionShape ..
public virtual void PreUpdate(float elapsed)
{ }
}
public class PedEntity : Entity
{
public Vector2 ControlMovement;
public bool ControlJump;
public bool ControlBoost;
public Vector3 ForwardVec;
public Quaternion CameraOrientation = Quaternion.LookAtLH(Vector3.Zero, Vector3.Up, Vector3.ForwardLH);
public Entity CameraEntity = new Entity();
public bool OnGround = false;
public PedEntity()
{
Radius = 0.5f;
Center = new Vector3(0.0f, 0.0f, -1.2f); //base collision point is 1.7m below center... for camera offset
Mass = 80.0f;
ForwardVec = Vector3.UnitY;
CameraEntity.Orientation = CameraOrientation;
CameraEntity.OrientationInv = Quaternion.Invert(Orientation);
}
public override void PreUpdate(float elapsed)
{
//float rotspd = 0.5f;
float movspd = 10.0f;
float velspd = 10.0f;
float jmpvel = 3.0f;
float boostmult = 10.0f;
if (ControlBoost) movspd *= boostmult;
Quaternion rot = Quaternion.Identity;// .RotationAxis(Vector3.UnitZ, -ControlMovement.X * rotspd * elapsed);
Quaternion ori = Quaternion.Multiply(Orientation, rot);
SetOrientation(ori);
float jmpamt = (ControlJump ? jmpvel : 0);
Vector3 curvel = Velocity;
Vector3 controlvel = new Vector3(ControlMovement * movspd, jmpamt);
Vector3 targetvel = controlvel + new Vector3(0, 0, curvel.Z);
Vector3 newvel = curvel + (targetvel - curvel) * velspd * elapsed;
Velocity = newvel;
var coll = Space.FindFirstCollision(this, elapsed);
if (coll.Hit)
{
Vector3 collpos = coll.PrePos; //last known ok position
Vector3 disp = Velocity * elapsed;
Vector3 oldpos = Position;
Vector3 targetpos = Position + disp;
float displ = disp.Length();
//////BoundingSphere sph = new BoundingSphere(targetpos + Center, Radius);
//////r.SphereHit = SphereIntersect(sph);
if ((disp.Z > -0.25f))/* && (displ < Radius * 2.0f)*/
{
Vector3 raydir = new Vector3(0.0f, 0.0f, -1.0f);
Vector3 rayoff = new Vector3(0.0f, 0.0f, 0.0f);
Ray ray = new Ray(targetpos + Center + rayoff, raydir);
var rayhit = Space.RayIntersect(ray, 1.0f);
if (rayhit.Hit)
{
if (rayhit.HitDist > 0)
{
Position = rayhit.Position - Center + new Vector3(0, 0, Radius);
//collpos = Position;//targetpos;//
}
else
{
//the start of the ray was a collision... can't move here
Position = collpos;
}
}
else //might happen when about to go off a big drop?
{
Position = targetpos;// collpos;
//collpos = targetpos;
}
}
else //moving fast...
{
Position = collpos; //last known ok position
}
//Position = collpos; //last known ok position
bool wasOnGround = OnGround;
OnGround = (Vector3.Dot(coll.SphereHit.Normal, Vector3.UnitZ) > 0.8f);
if (OnGround)
{
}
Vector3 findisp = Position - oldpos;
float findispl = findisp.Length();
float fdisp = Math.Min(displ, findispl);
Vector3 dispdir = findisp / Math.Max(findispl, 0.0001f);
float absvel = fdisp / Math.Max(elapsed, 0.0001f);
Velocity = dispdir * absvel;
//Vector3 veldir = Vector3.Normalize(Position - oldpos);
//float vellen = (collpos - oldpos).Length() / Math.Max(elapsed, 0.0001f);
//Velocity = veldir * vellen;
//Velocity = (Position - oldpos) / Math.Max(elapsed, 0.0001f);
}
else
{
Position = coll.HitPos; //hitpos is the end pos if not hit
OnGround = false;
}
CameraEntity.Position = Position;
}
private void SetOrientation(Quaternion ori)
{
Orientation = ori;
OrientationInv = Quaternion.Invert(Orientation);
CameraEntity.Orientation = Quaternion.Multiply(Orientation, CameraOrientation);
CameraEntity.OrientationInv = Quaternion.Invert(Orientation);
}
}
}

View File

@ -0,0 +1,206 @@
using CodeWalker.GameFiles;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CodeWalker.World
{
public class PopZones : BasePathData
{
public volatile bool Inited = false;
public GameFileCache GameFileCache;
public Dictionary<string, PopZone> Groups = new Dictionary<string, PopZone>();
public Vector4[] GetNodePositions()
{
return null;
}
public EditorVertex[] GetPathVertices()
{
return null;
}
public EditorVertex[] GetTriangleVertices()
{
return TriangleVerts;
}
public EditorVertex[] TriangleVerts;
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
{
Inited = false;
GameFileCache = gameFileCache;
var rpfman = gameFileCache.RpfMan;
string filename = "common.rpf\\data\\levels\\gta5\\popzone.ipl";
if (gameFileCache.EnableDlc)
{
filename = "update\\update.rpf\\common\\data\\levels\\gta5\\popzone.ipl";
}
string ipltext = rpfman.GetFileUTF8Text(filename);
if (string.IsNullOrEmpty(ipltext))
{
ipltext = "";
}
Groups.Clear();
var ipllines = ipltext.Split('\n');
bool inzone = false;
foreach (var iplline in ipllines)
{
var linet = iplline.Trim();
if (linet == "zone")
{
inzone = true;
}
else if (linet == "end")
{
inzone = false;
}
else if (inzone)
{
PopZoneBox box = new PopZoneBox();
box.Init(linet);
PopZone group;
if (!Groups.TryGetValue(box.NameLabel, out group))
{
group = new PopZone();
group.NameLabel = box.NameLabel;
Groups[box.NameLabel] = group;
}
group.Boxes.Add(box);
}
}
foreach (var group in Groups.Values)
{
var hash = JenkHash.GenHash(group.NameLabel.ToLowerInvariant());
group.Name = GlobalText.TryGetString(hash);
}
BuildVertices();
Inited = true;
}
public void BuildVertices()
{
var vlist = new List<EditorVertex>();
var v1 = new EditorVertex();
var v2 = new EditorVertex();
var v3 = new EditorVertex();
var v4 = new EditorVertex();
foreach (var group in Groups.Values)
{
var hash = JenkHash.GenHash(group.NameLabel.ToLowerInvariant());
byte cr = (byte)((hash >> 8) & 0xFF);
byte cg = (byte)((hash >> 16) & 0xFF);
byte cb = (byte)((hash >> 24) & 0xFF);
byte ca = 60;
uint cv = (uint)new Color(cr, cg, cb, ca).ToRgba();
v1.Colour = cv;
v2.Colour = cv;
v3.Colour = cv;
v4.Colour = cv;
foreach (var box in group.Boxes)
{
var min = box.Box.Minimum;
var max = box.Box.Maximum;
v1.Position = new Vector3(min.X, min.Y, 0);
v2.Position = new Vector3(max.X, min.Y, 0);
v3.Position = new Vector3(min.X, max.Y, 0);
v4.Position = new Vector3(max.X, max.Y, 0);
vlist.Add(v1);
vlist.Add(v2);
vlist.Add(v3);
vlist.Add(v3);
vlist.Add(v2);
vlist.Add(v4);
}
}
if (vlist.Count > 0)
{
TriangleVerts = vlist.ToArray();
}
else
{
TriangleVerts = null;
}
}
}
public class PopZone
{
public string NameLabel { get; set; }
public string Name { get; set; } //lookup from gxt2 with label..?
public List<PopZoneBox> Boxes { get; set; } = new List<PopZoneBox>();
public override string ToString()
{
return NameLabel + ": " + Name;
}
}
public class PopZoneBox
{
public string ID { get; set; }
public BoundingBox Box { get; set; }
public string NameLabel { get; set; }
public float UnkVal { get; set; }
public void Init(string iplline)
{
var parts = iplline.Split(',');
if (parts.Length >= 9)
{
ID = parts[0].Trim();
BoundingBox b = new BoundingBox();
b.Minimum.X = FloatUtil.Parse(parts[1].Trim());
b.Minimum.Y = FloatUtil.Parse(parts[2].Trim());
b.Minimum.Z = FloatUtil.Parse(parts[3].Trim());
b.Maximum.X = FloatUtil.Parse(parts[4].Trim());
b.Maximum.Y = FloatUtil.Parse(parts[5].Trim());
b.Maximum.Z = FloatUtil.Parse(parts[6].Trim());
Box = b;
NameLabel = parts[7].Trim();
UnkVal = FloatUtil.Parse(parts[8].Trim());
}
}
public override string ToString()
{
return ID + ": " + NameLabel + ": " + Box.ToString();
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,124 @@
using CodeWalker.GameFiles;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.World
{
public class Timecycle
{
public volatile bool Inited = false;
public float sun_roll { get; set; }
public float sun_yaw { get; set; }
public float moon_roll { get; set; }
public float moon_wobble_freq { get; set; }
public float moon_wobble_amp { get; set; }
public float moon_wobble_offset { get; set; }
public List<TimecycleSample> Samples { get; set; } = new List<TimecycleSample>();
public List<string> Regions { get; set; } = new List<string>();
public float CurrentHour { get; set; } = 0;
public int CurrentSampleIndex { get; set; } = 0;
public float CurrentSampleBlend { get; set; } = 1.0f;
public float NextSampleBlend { get; set; } = 0.0f;
public Vector3 CurrentSunDirection { get; set; } = new Vector3(0, 0, 1);
public Vector3 CurrentMoonDirection { get; set; } = new Vector3(0, 0, -1);
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
{
var rpfman = gameFileCache.RpfMan;
string filename = "common.rpf\\data\\levels\\gta5\\time.xml";
XmlDocument timexml = rpfman.GetFileXml(filename);
XmlElement time = timexml.DocumentElement;
XmlNode suninfo = time.SelectSingleNode("suninfo");
XmlNode mooninfo = time.SelectSingleNode("mooninfo");
XmlNodeList samples = time.SelectNodes("sample");
XmlNodeList regions = time.SelectNodes("region");
sun_roll = Xml.GetFloatAttribute(suninfo, "sun_roll");
sun_yaw = Xml.GetFloatAttribute(suninfo, "sun_yaw");
moon_roll = Xml.GetFloatAttribute(mooninfo, "moon_roll");
moon_wobble_freq = Xml.GetFloatAttribute(mooninfo, "moon_wobble_freq");
moon_wobble_amp = Xml.GetFloatAttribute(mooninfo, "moon_wobble_amp");
moon_wobble_offset = Xml.GetFloatAttribute(mooninfo, "moon_wobble_offset");
Samples.Clear();
for (int i = 0; i < samples.Count; i++)
{
TimecycleSample tcs = new TimecycleSample();
tcs.Init(samples[i]);
Samples.Add(tcs);
}
Regions.Clear();
for (int i = 0; i < regions.Count; i++)
{
Regions.Add(Xml.GetStringAttribute(regions[i], "name"));
}
Inited = true;
}
public void SetTime(float hour)
{
float day = Math.Max(hour / 24.0f, 0.0f);
float h = hour - ((float)Math.Floor(day) * 24.0f);
CurrentHour = h;
for (int i = 0; i < Samples.Count; i++)
{
bool lasti = (i >= Samples.Count - 1);
var cur = Samples[i];
var nxt = Samples[lasti ? 0 : i+1];
var nxth = lasti ? nxt.hour + 24.0f : nxt.hour;
if (((h >= cur.hour) && (h < nxth)) || lasti)
{
float blendrange = (nxth - cur.hour) - cur.duration;
float blendstart = cur.hour + cur.duration;
float blendrel = h - blendstart;
float blendval = blendrel / blendrange;
float blend = Math.Min(Math.Max(blendval, 0.0f), 1.0f);
NextSampleBlend = blend;
CurrentSampleBlend = 1.0f - blend;
CurrentSampleIndex = i;
break;
}
}
}
public bool IsNightTime
{
get
{
return (CurrentHour < 6.0f) || (CurrentHour > 20.0f);
}
}
}
public class TimecycleSample
{
public string name { get; set; }
public float hour { get; set; }
public float duration { get; set; }
public string uw_tc_mod { get; set; }
public void Init(XmlNode node)
{
name = Xml.GetStringAttribute(node, "name");
hour = Xml.GetFloatAttribute(node, "hour");
duration = Xml.GetFloatAttribute(node, "duration");
uw_tc_mod = Xml.GetStringAttribute(node, "uw_tc_mod");
}
}
}

View File

@ -0,0 +1,148 @@
using CodeWalker.GameFiles;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.World
{
public class TimecycleMods
{
public Dictionary<uint, TimecycleMod> Dict = new Dictionary<uint, TimecycleMod>();
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
{
Dict.Clear();
var rpfman = gameFileCache.RpfMan;
LoadXml(rpfman.GetFileXml("common.rpf\\data\\timecycle\\timecycle_mods_1.xml"));
LoadXml(rpfman.GetFileXml("common.rpf\\data\\timecycle\\timecycle_mods_2.xml"));
LoadXml(rpfman.GetFileXml("common.rpf\\data\\timecycle\\timecycle_mods_3.xml"));
LoadXml(rpfman.GetFileXml("common.rpf\\data\\timecycle\\timecycle_mods_4.xml"));
LoadXml(rpfman.GetFileXml("update\\update.rpf\\common\\data\\timecycle\\timecycle_mods_1.xml"));
LoadXml(rpfman.GetFileXml("update\\update.rpf\\common\\data\\timecycle\\timecycle_mods_2.xml"));//doesn't exist, but try anyway
LoadXml(rpfman.GetFileXml("update\\update.rpf\\common\\data\\timecycle\\timecycle_mods_3.xml"));
LoadXml(rpfman.GetFileXml("update\\update.rpf\\common\\data\\timecycle\\timecycle_mods_4.xml"));
if (gameFileCache.EnableDlc)
{
foreach (var dlcrpf in gameFileCache.DlcActiveRpfs)
{
foreach (var file in dlcrpf.AllEntries)
{
if (file.NameLower.EndsWith(".xml") && file.NameLower.StartsWith("timecycle_mods_"))
{
LoadXml(rpfman.GetFileXml(file.Path));
}
}
}
}
gameFileCache.TimeCycleModsDict = Dict;
}
private void LoadXml(XmlDocument doc)
{
var root = doc.DocumentElement;
if (root == null)
{ return; }
float version = Xml.GetFloatAttribute(root, "version");
var modnodes = root.SelectNodes("modifier");
foreach (XmlNode modnode in modnodes)
{
if (!(modnode is XmlElement)) continue;
TimecycleMod mod = new TimecycleMod();
mod.Init(modnode);
Dict[mod.nameHash] = mod;
}
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class TimecycleMod
{
public string name { get; set; }
public uint nameHash { get; set; }
public int numMods { get; set; }
public int userFlags { get; set; }
public TimecycleModValue[] Values { get; set; }
public Dictionary<string, TimecycleModValue> Dict { get; set; }
public void Init(XmlNode node)
{
Dict = new Dictionary<string, TimecycleModValue>();
name = Xml.GetStringAttribute(node, "name");
numMods = Xml.GetIntAttribute(node, "numMods");
userFlags = Xml.GetIntAttribute(node, "userFlags");
string namel = name.ToLowerInvariant();
JenkIndex.Ensure(namel);
nameHash = JenkHash.GenHash(namel);
List<TimecycleModValue> vals = new List<TimecycleModValue>();
foreach (XmlNode valnode in node.ChildNodes)
{
if (!(valnode is XmlElement)) continue;
TimecycleModValue val = new TimecycleModValue();
val.Init(valnode);
vals.Add(val);
Dict[val.name] = val;
}
Values = vals.ToArray();
}
public override string ToString()
{
return name + " (" + numMods.ToString() + " mods, userFlags: " + userFlags.ToString() + ")";
}
}
[TypeConverter(typeof(ExpandableObjectConverter))]
public class TimecycleModValue
{
public string name { get; set; }
public float value1 { get; set; }
public float value2 { get; set; }
public void Init(XmlNode node)
{
name = node.Name;
string valstr = node.InnerText;
string[] valstrs = valstr.Split(' ');
if (valstrs.Length == 2)
{
value1 = FloatUtil.Parse(valstrs[0]);
value2 = FloatUtil.Parse(valstrs[1]);
}
else
{ }
}
public override string ToString()
{
return name + ": " + FloatUtil.ToString(value1) + ", " + FloatUtil.ToString(value2);
}
}
}

View File

@ -0,0 +1,433 @@
using CodeWalker.GameFiles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using SharpDX;
namespace CodeWalker.World
{
public class Trains
{
public volatile bool Inited = false;
public GameFileCache GameFileCache;
public List<TrainTrack> TrainTracks { get; set; } = new List<TrainTrack>();
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
{
GameFileCache = gameFileCache;
var rpfman = gameFileCache.RpfMan;
string trainsfilename = "common.rpf\\data\\levels\\gta5\\trains.xml";
XmlDocument trainsxml = rpfman.GetFileXml(trainsfilename);
XmlElement trainsdata = trainsxml.DocumentElement;
//TODO: parse train_configs
string tracksfilename = "common.rpf\\data\\levels\\gta5\\traintracks.xml";
XmlDocument tracksxml = rpfman.GetFileXml(tracksfilename);
XmlElement tracksdata = tracksxml.DocumentElement;
XmlNodeList tracks = tracksdata.SelectNodes("train_track");
TrainTracks.Clear();
for (int i = 0; i < tracks.Count; i++)
{
var trackxml = tracks[i];
TrainTrack tt = new TrainTrack();
tt.Load(gameFileCache, trackxml);
TrainTracks.Add(tt);
}
Inited = true;
}
}
public class TrainTrack : BasePathData
{
public string filename { get; set; }
public string trainConfigName { get; set; }
public bool isPingPongTrack { get; set; }
public bool stopsAtStations { get; set; }
public bool MPstopsAtStations { get; set; }
public float speed { get; set; }
public float brakingDist { get; set; }
public List<TrainTrackNode> Nodes { get; set; }
public int NodeCount { get; set; }
public int StationCount
{
get
{
int sc = 0;
foreach (var node in Nodes)
{
if ((node.NodeType == 1) || (node.NodeType == 2) || (node.NodeType == 5))
{
sc++;
}
}
return sc;
}
}
public EditorVertex[] LinkedVerts { get; set; }
public Vector4[] NodePositions { get; set; }
public EditorVertex[] GetPathVertices()
{
return LinkedVerts;
}
public EditorVertex[] GetTriangleVertices()
{
return null;
}
public Vector4[] GetNodePositions()
{
return NodePositions;
}
public PathBVH BVH { get; set; }
public string NodesString { get; set; }
public RpfFileEntry RpfFileEntry { get; set; }
public string Name { get; set; }
public string FilePath { get; set; }
public bool HasChanged { get; set; }
public bool Loaded { get; set; }
public void Load(GameFileCache gameFileCache, XmlNode node)
{
//load from game file cache
filename = Xml.GetStringAttribute(node, "filename");
trainConfigName = Xml.GetStringAttribute(node, "trainConfigName");
isPingPongTrack = Xml.GetBoolAttribute(node, "isPingPongTrack");
stopsAtStations = Xml.GetBoolAttribute(node, "stopsAtStations");
MPstopsAtStations = Xml.GetBoolAttribute(node, "MPstopsAtStations");
speed = Xml.GetFloatAttribute(node, "speed");
brakingDist = Xml.GetFloatAttribute(node, "brakingDist");
RpfFileEntry = gameFileCache.RpfMan.GetEntry(filename) as RpfFileEntry;
NodesString = gameFileCache.RpfMan.GetFileUTF8Text(filename);
SetNameFromFilename();
FilePath = Name;
Load(NodesString);
BuildVertices();
BuildBVH();
Loaded = true;
}
public void Load(byte[] data)
{
filename = string.Empty;
trainConfigName = string.Empty;
RpfFileEntry = new RpfBinaryFileEntry();
string str = Encoding.UTF8.GetString(data);
Load(str);
BuildVertices();
BuildBVH();
Loaded = true;
}
public byte[] Save()
{
NodeCount = Nodes.Count;
StringBuilder sb = new StringBuilder();
sb.AppendLine(Nodes.Count.ToString());
foreach (var node in Nodes)
{
var nstr = FloatUtil.GetVector3String(node.Position).Replace(",","") + " " + node.NodeType.ToString();
sb.AppendLine(nstr);
}
string str = sb.ToString();
return Encoding.UTF8.GetBytes(str);
}
public void SetNameFromFilename()
{
string[] fparts = filename.Replace('\\', '/').Split('/');
if ((fparts == null) || (fparts.Length == 0))
{
Name = filename;
}
else
{
Name = fparts[fparts.Length - 1];
}
}
public void Load(string trackstr)
{
//load nodes from a text string...
NodesString = trackstr;
if (!string.IsNullOrEmpty(trackstr))
{
string[] trackstrs = trackstr.Split(new[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
if (trackstrs.Length > 1)
{
int nodecount;
int.TryParse(trackstrs[0], out nodecount);
NodeCount = nodecount;
List<TrainTrackNode> nodes = new List<TrainTrackNode>();
for (int i = 1; i < trackstrs.Length; i++)
{
var nodestr = trackstrs[i].Trim();
var nodevals = nodestr.Split(' ');
if (nodevals.Length == 4)
{
TrainTrackNode ttnode = new TrainTrackNode();
var x = FloatUtil.Parse(nodevals[0]);
var y = FloatUtil.Parse(nodevals[1]);
var z = FloatUtil.Parse(nodevals[2]);
int nodetype;
int.TryParse(nodevals[3], out nodetype);
ttnode.Position = new Vector3(x, y, z);
ttnode.NodeType = nodetype;
ttnode.Track = this;
ttnode.Index = nodes.Count;
ttnode.Links[0] = (nodes.Count > 0) ? nodes[nodes.Count - 1] : null;
if (ttnode.Links[0] != null)
{
ttnode.Links[0].Links[1] = ttnode;
}
nodes.Add(ttnode);
}
else
{ }
}
Nodes = nodes;
}
else
{ }
}
else
{ }
if (Nodes == null)
{
Nodes = new List<TrainTrackNode>();
}
}
public void BuildVertices()
{
if ((Nodes != null) && (Nodes.Count > 0))
{
var nc = Nodes.Count;
var lc = nc - 1;
var lvc = lc * 2;
var np = new Vector4[nc];
var lv = new EditorVertex[lvc];
for (int i = 0; i < nc; i++)
{
np[i] = new Vector4(Nodes[i].Position, 1.0f);
if (i > 0)
{
var l = i - 1;
var li = l * 2;
var ni = li + 1;
lv[li].Position = Nodes[l].Position;
lv[ni].Position = Nodes[i].Position;
lv[li].Colour = (uint)Nodes[l].GetColour();
lv[ni].Colour = (uint)Nodes[i].GetColour();
}
}
NodePositions = np;
LinkedVerts = lv;
}
}
public void UpdateBvhForNode(TrainTrackNode node)
{
//this needs to be called when a node's position changes...
//need to recalc the BVH for mouse intersection optimisation purposes.
//if (BVH == null) return;
//BVH.UpdateForNode(node);
BuildBVH();
//also updates the NodePositions for the visible vertex
if (Nodes != null)
{
for (int i = 0; i < Nodes.Count; i++)
{
if (Nodes[i] == node)
{
NodePositions[i] = new Vector4(node.Position, 1.0f);
break;
}
}
}
}
public void BuildBVH()
{
BVH = new PathBVH(Nodes, 10, 10);
}
public TrainTrackNode AddNode(TrainTrackNode afternode = null)
{
int cnt = Nodes?.Count ?? 0;
TrainTrackNode tn = new TrainTrackNode();
tn.Track = this;
tn.Index = (afternode != null) ? afternode.Index + 1 : cnt;
if (Nodes == null)
{
Nodes = new List<TrainTrackNode>();
}
if (afternode != null)
{
TrainTrackNode aln = afternode.Links[1];
if (aln != null) aln.Links[0] = tn;
afternode.Links[1] = tn;
tn.Links[0] = afternode;
tn.Links[1] = aln;
int idx = tn.Index;
Nodes.Insert(idx, tn);
for (int i = 0; i < Nodes.Count; i++)
{
Nodes[i].Index = i;
}
}
else
{
if (cnt > 0)
{
TrainTrackNode ln = Nodes[cnt - 1];
tn.Links[0] = ln;
ln.Links[1] = tn;
}
Nodes.Add(tn);
}
NodeCount = Nodes.Count;
return tn;
}
public bool RemoveNode(TrainTrackNode node)
{
bool r = false;
r = Nodes.Remove(node);
NodeCount = Nodes.Count;
if (r)
{
var l0 = node.Links[0];
var l1 = node.Links[1];
if (l0 != null)
{
l0.Links[1] = l1;
}
if (l1 != null)
{
l1.Links[0] = l0;
}
for (int i = 0; i < Nodes.Count; i++)
{
Nodes[i].Index = i;
}
BuildVertices();
}
return r;
}
public override string ToString()
{
return Name + ": " + filename + " (" + NodeCount.ToString() + " nodes)";
}
}
public class TrainTrackNode : BasePathNode
{
public Vector3 Position { get; set; }
public int NodeType { get; set; }
public TrainTrack Track { get; set; }
public int Index { get; set; }
public TrainTrackNode[] Links { get; set; } = new TrainTrackNode[2];
public int GetColour()
{
switch (NodeType)
{
case 0: return new Color4(1.0f, 0.0f, 0.0f, 1.0f).ToRgba();
case 1: return new Color4(1.0f, 1.0f, 0.0f, 1.0f).ToRgba();
case 2: return new Color4(0.0f, 1.0f, 0.0f, 1.0f).ToRgba();
case 3: return new Color4(0.0f, 1.0f, 1.0f, 1.0f).ToRgba();
case 4: return new Color4(0.0f, 0.0f, 1.0f, 1.0f).ToRgba();
case 5: return new Color4(1.0f, 0.0f, 1.0f, 1.0f).ToRgba();
default: return new Color4(1.0f, 1.0f, 1.0f, 1.0f).ToRgba();
}
}
public void SetPosition(Vector3 pos)
{
Position = pos;
}
public override string ToString()
{
return Index.ToString() + ": " + NodeType.ToString();// + ": " + FloatUtil.GetVector3String(Position);
}
}
}

View File

@ -0,0 +1,213 @@
using CodeWalker.GameFiles;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.World
{
public class Water
{
public volatile bool Inited = false;
public GameFileCache GameFileCache;
public List<WaterQuad> WaterQuads = new List<WaterQuad>();
public List<WaterCalmingQuad> CalmingQuads = new List<WaterCalmingQuad>();
public List<WaterWaveQuad> WaveQuads = new List<WaterWaveQuad>();
public void Init(GameFileCache gameFileCache, Action<string> updateStatus)
{
GameFileCache = gameFileCache;
var rpfman = gameFileCache.RpfMan;
string filename = "common.rpf\\data\\levels\\gta5\\water.xml";
XmlDocument waterxml = rpfman.GetFileXml(filename);
XmlElement waterdata = waterxml.DocumentElement;
XmlNodeList waterquads = waterdata.SelectNodes("WaterQuads/Item");
WaterQuads.Clear();
for (int i = 0; i < waterquads.Count; i++)
{
var waterquad = new WaterQuad();
waterquad.Init(waterquads[i]);
WaterQuads.Add(waterquad);
}
XmlNodeList calmingquads = waterdata.SelectNodes("CalmingQuads/Item");
CalmingQuads.Clear();
for (int i = 0; i < calmingquads.Count; i++)
{
var calmingquad = new WaterCalmingQuad();
calmingquad.Init(calmingquads[i]);
CalmingQuads.Add(calmingquad);
}
XmlNodeList wavequads = waterdata.SelectNodes("WaveQuads/Item");
WaveQuads.Clear();
for (int i = 0; i < wavequads.Count; i++)
{
var wavequad = new WaterWaveQuad();
wavequad.Init(wavequads[i]);
WaveQuads.Add(wavequad);
}
Inited = true;
}
public void GetVisibleQuads(Camera camera, List<WaterQuad> quads)
{
if (!Inited) return;
var vf = camera.ViewFrustum;
for (int i = 0; i < WaterQuads.Count; i++)
{
var quad = WaterQuads[i];
Vector3 camrel = quad.BSCenter - camera.Position;
if (vf.ContainsSphereNoClipNoOpt(ref camrel, quad.BSRadius))
{
quads.Add(quad);
}
}
}
}
public class WaterQuad
{
public float minX { get; set; }
public float maxX { get; set; }
public float minY { get; set; }
public float maxY { get; set; }
public int Type { get; set; }
public bool IsInvisible { get; set; }
public bool HasLimitedDepth { get; set; }
public float z { get; set; }
public float a1 { get; set; }
public float a2 { get; set; }
public float a3 { get; set; }
public float a4 { get; set; }
public bool NoStencil { get; set; }
public Vector3 BSCenter;
public float BSRadius;
public void Init(XmlNode node)
{
minX = Xml.GetChildFloatAttribute(node, "minX", "value");
maxX = Xml.GetChildFloatAttribute(node, "maxX", "value");
minY = Xml.GetChildFloatAttribute(node, "minY", "value");
maxY = Xml.GetChildFloatAttribute(node, "maxY", "value");
Type = Xml.GetChildIntAttribute(node, "Type", "value");
IsInvisible = Xml.GetChildBoolAttribute(node, "IsInvisible", "value");
HasLimitedDepth = Xml.GetChildBoolAttribute(node, "HasLimitedDepth", "value");
z = Xml.GetChildFloatAttribute(node, "z", "value");
a1 = Xml.GetChildFloatAttribute(node, "a1", "value");
a2 = Xml.GetChildFloatAttribute(node, "a2", "value");
a3 = Xml.GetChildFloatAttribute(node, "a3", "value");
a4 = Xml.GetChildFloatAttribute(node, "a4", "value");
NoStencil = Xml.GetChildBoolAttribute(node, "NoStencil", "value");
/*
<minX value="-1592" />
<maxX value="-1304" />
<minY value="-1744" />
<maxY value="-1624" />
<Type value="0" />
<IsInvisible value="false" />
<HasLimitedDepth value="false" />
<z value="0.0" />
<a1 value="26" />
<a2 value="26" />
<a3 value="26" />
<a4 value="26" />
<NoStencil value="false" />
*/
BSCenter = new Vector3((minX + maxX) * 0.5f, (minY + maxY) * 0.5f, z);
BSRadius = new Vector2(maxX - minX, maxY - minY).Length() * 0.5f;
}
public override string ToString()
{
return string.Format("{0}, {1}, {2}", FloatUtil.ToString(minX), FloatUtil.ToString(minY), FloatUtil.ToString(z), FloatUtil.ToString(maxX), FloatUtil.ToString(maxY));
}
}
public class WaterCalmingQuad
{
public float minX { get; set; }
public float maxX { get; set; }
public float minY { get; set; }
public float maxY { get; set; }
public float fDampening { get; set; }
public void Init(XmlNode node)
{
minX = Xml.GetChildFloatAttribute(node, "minX", "value");
maxX = Xml.GetChildFloatAttribute(node, "maxX", "value");
minY = Xml.GetChildFloatAttribute(node, "minY", "value");
maxY = Xml.GetChildFloatAttribute(node, "maxY", "value");
fDampening = Xml.GetChildFloatAttribute(node, "fDampening", "value");
/*
<minX value="1752" />
<maxX value="2076" />
<minY value="216" />
<maxY value="800" />
<fDampening value="0.05" />
*/
}
}
public class WaterWaveQuad
{
public float minX { get; set; }
public float maxX { get; set; }
public float minY { get; set; }
public float maxY { get; set; }
public float Amplitude { get; set; }
public float XDirection { get; set; }
public float YDirection { get; set; }
public void Init(XmlNode node)
{
minX = Xml.GetChildFloatAttribute(node, "minX", "value");
maxX = Xml.GetChildFloatAttribute(node, "maxX", "value");
minY = Xml.GetChildFloatAttribute(node, "minY", "value");
maxY = Xml.GetChildFloatAttribute(node, "maxY", "value");
Amplitude = Xml.GetChildFloatAttribute(node, "Amplitude", "value");
XDirection = Xml.GetChildFloatAttribute(node, "XDirection", "value");
YDirection = Xml.GetChildFloatAttribute(node, "YDirection", "value");
/*
<minX value="1664" />
<maxX value="1988" />
<minY value="-120" />
<maxY value="132" />
<Amplitude value="0.1" />
<XDirection value="-0.603208" />
<YDirection value="-0.797584" />
*/
}
}
}

View File

@ -0,0 +1,569 @@
using CodeWalker.GameFiles;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
namespace CodeWalker.World
{
public class Weather
{
public Dictionary<string, WeatherGpuFx> WeatherGpuFx { get; set; } = new Dictionary<string, WeatherGpuFx>();
public Dictionary<string, WeatherType> WeatherTypes { get; set; } = new Dictionary<string, WeatherType>();
public List<WeatherCycle> WeatherCycles { get; set; } = new List<WeatherCycle>();
public WeatherValues CurrentValues;
public volatile bool Inited = false;
public WeatherType CurrentWeatherType;
public WeatherType NextWeatherType;
public float WeatherChangeTime = 0.33f;
public float CurrentWeatherChangeTime = 0.0f;
public float CurrentWeatherChangeBlend = 0.0f;
public string Region = "GLOBAL"; //URBAN or GLOBAL..
public WeatherCycleKeyframeRegion CurrentWeatherRegion;
public WeatherCycleKeyframeRegion NextWeatherRegion;
public Timecycle Timecycle;
public TimecycleMods TimecycleMods;
public void Init(GameFileCache gameFileCache, Action<string> updateStatus, Timecycle timecycle)
{
Timecycle = timecycle;
var rpfman = gameFileCache.RpfMan;
//TODO: RpfMan should be able to get the right version? or maybe let gameFileCache do it!
string filename = "common.rpf\\data\\levels\\gta5\\weather.xml";
if (gameFileCache.EnableDlc)
{
filename = "update\\update.rpf\\common\\data\\levels\\gta5\\weather.xml";
}
XmlDocument weatherxml = rpfman.GetFileXml(filename);
XmlElement weather = weatherxml.DocumentElement;
XmlNodeList weathergpufx = weather.SelectNodes("WeatherGpuFx/Item");
WeatherGpuFx.Clear();
for (int i = 0; i < weathergpufx.Count; i++)
{
var weathergpufxi = new WeatherGpuFx();
weathergpufxi.Init(weathergpufx[i]);
WeatherGpuFx[weathergpufxi.Name] = weathergpufxi;
}
XmlNodeList weathertypes = weather.SelectNodes("WeatherTypes/Item");
WeatherTypes.Clear();
for (int i = 0; i < weathertypes.Count; i++)
{
var weathertype = new WeatherType();
weathertype.Init(gameFileCache, weathertypes[i]);
WeatherTypes[weathertype.Name] = weathertype;
}
XmlNodeList weathercycles = weather.SelectNodes("WeatherCycles/Item");
WeatherCycles.Clear();
for (int i = 0; i < weathercycles.Count; i++)
{
var weathercycle = new WeatherCycle();
weathercycle.Init(weathercycles[i]);
WeatherCycles.Add(weathercycle);
}
if (WeatherTypes.Count > 0)
{
CurrentWeatherType = WeatherTypes.Values.First();
CurrentWeatherRegion = CurrentWeatherType.GetRegion(Region);
NextWeatherType = CurrentWeatherType;
NextWeatherRegion = NextWeatherType.GetRegion(Region);
}
TimecycleMods = new TimecycleMods();
TimecycleMods.Init(gameFileCache, updateStatus);
Inited = true;
}
public void Update(float elapsed)
{
if (!Inited) return;
if (CurrentWeatherType != NextWeatherType)
{
CurrentWeatherChangeTime += elapsed;
if (CurrentWeatherChangeTime >= WeatherChangeTime)
{
CurrentWeatherType = NextWeatherType;
CurrentWeatherChangeTime = 0.0f;
}
CurrentWeatherChangeBlend = Math.Min(CurrentWeatherChangeTime / WeatherChangeTime, 1.0f);
}
if (CurrentWeatherType != null)
{
CurrentWeatherRegion = CurrentWeatherType.GetRegion(Region);
}
if (NextWeatherType != null)
{
NextWeatherRegion = NextWeatherType.GetRegion(Region);
}
CurrentValues.Update(this);
}
public void SetNextWeather(string name)
{
WeatherTypes.TryGetValue(name, out NextWeatherType);
if (NextWeatherType == null)
{
NextWeatherType = CurrentWeatherType;
}
else
{
CurrentWeatherChangeTime = 0.0f;
}
}
public float GetDynamicValue(string name)
{
int csi = Timecycle.CurrentSampleIndex;
float csb = Timecycle.CurrentSampleBlend;
if ((CurrentWeatherRegion != null) && (NextWeatherRegion != null))
{
float cv = CurrentWeatherRegion.GetCurrentValue(name, csi, csb);
float nv = NextWeatherRegion.GetCurrentValue(name, csi, csb);
return cv * (1.0f - CurrentWeatherChangeBlend) + nv * CurrentWeatherChangeBlend;
}
else if (CurrentWeatherRegion != null)
{
return CurrentWeatherRegion.GetCurrentValue(name, csi, csb);
}
//throw new Exception("CurrentWeatherRegion was null.");
return 0.0f;
}
public Vector3 GetDynamicRGB(string rname, string gname, string bname)
{
int csi = Timecycle.CurrentSampleIndex;
float csb = Timecycle.CurrentSampleBlend;
if ((CurrentWeatherRegion != null) && (NextWeatherRegion != null))
{
float cvr = CurrentWeatherRegion.GetCurrentValue(rname, csi, csb);
float cvg = CurrentWeatherRegion.GetCurrentValue(gname, csi, csb);
float cvb = CurrentWeatherRegion.GetCurrentValue(bname, csi, csb);
float nvr = NextWeatherRegion.GetCurrentValue(rname, csi, csb);
float nvg = NextWeatherRegion.GetCurrentValue(gname, csi, csb);
float nvb = NextWeatherRegion.GetCurrentValue(bname, csi, csb);
Vector3 cv = new Vector3(cvr, cvg, cvb);
Vector3 nv = new Vector3(nvr, nvg, nvb);
return cv * (1.0f - CurrentWeatherChangeBlend) + nv * CurrentWeatherChangeBlend;
}
else if (CurrentWeatherRegion != null)
{
float cvr = CurrentWeatherRegion.GetCurrentValue(rname, csi, csb);
float cvg = CurrentWeatherRegion.GetCurrentValue(gname, csi, csb);
float cvb = CurrentWeatherRegion.GetCurrentValue(bname, csi, csb);
return new Vector3(cvr, cvg, cvb);
}
//throw new Exception("CurrentWeatherRegion was null.");
return Vector3.Zero;
}
public Vector4 GetDynamicRGBA(string rname, string gname, string bname, string aname)
{
int csi = Timecycle.CurrentSampleIndex;
float csb = Timecycle.CurrentSampleBlend;
if ((CurrentWeatherRegion != null) && (NextWeatherRegion != null))
{
float cvr = CurrentWeatherRegion.GetCurrentValue(rname, csi, csb);
float cvg = CurrentWeatherRegion.GetCurrentValue(gname, csi, csb);
float cvb = CurrentWeatherRegion.GetCurrentValue(bname, csi, csb);
float cva = CurrentWeatherRegion.GetCurrentValue(aname, csi, csb);
float nvr = NextWeatherRegion.GetCurrentValue(rname, csi, csb);
float nvg = NextWeatherRegion.GetCurrentValue(gname, csi, csb);
float nvb = NextWeatherRegion.GetCurrentValue(bname, csi, csb);
float nva = NextWeatherRegion.GetCurrentValue(aname, csi, csb);
Vector4 cv = new Vector4(cvr, cvg, cvb, cva);
Vector4 nv = new Vector4(nvr, nvg, nvb, nva);
return cv * (1.0f - CurrentWeatherChangeBlend) + nv * CurrentWeatherChangeBlend;
}
else if (CurrentWeatherRegion != null)
{
float cvr = CurrentWeatherRegion.GetCurrentValue(rname, csi, csb);
float cvg = CurrentWeatherRegion.GetCurrentValue(gname, csi, csb);
float cvb = CurrentWeatherRegion.GetCurrentValue(bname, csi, csb);
float cva = CurrentWeatherRegion.GetCurrentValue(aname, csi, csb);
return new Vector4(cvr, cvg, cvb, cva);
}
//throw new Exception("CurrentWeatherRegion was null.");
return Vector4.Zero;
}
}
public class WeatherGpuFx
{
public string Name { get; set; }
public string SystemType { get; set; }
public string diffuseName { get; set; }
public string distortionTexture { get; set; }
public string diffuseSplashName { get; set; }
public string driveType { get; set; }
public float windInfluence { get; set; }
public float gravity { get; set; }
public string emitterSettingsName { get; set; }
public string renderSettingsName { get; set; }
public void Init(XmlNode node)
{
Name = Xml.GetChildInnerText(node, "Name");
SystemType = Xml.GetChildInnerText(node, "SystemType");
diffuseName = Xml.GetChildInnerText(node, "diffuseName");
distortionTexture = Xml.GetChildInnerText(node, "distortionTexture");
diffuseSplashName = Xml.GetChildInnerText(node, "diffuseSplashName");
driveType = Xml.GetChildInnerText(node, "driveType");
windInfluence = Xml.GetChildFloatAttribute(node, "windInfluence", "value");
gravity = Xml.GetChildFloatAttribute(node, "gravity", "value");
emitterSettingsName = Xml.GetChildInnerText(node, "emitterSettingsName");
renderSettingsName = Xml.GetChildInnerText(node, "renderSettingsName");
}
public override string ToString()
{
return Name;
}
}
public class WeatherType
{
public MetaHash NameHash { get; set; }
public string Name { get; set; }
public float Sun { get; set; }
public float Cloud { get; set; }
public float WindMin { get; set; }
public float WindMax { get; set; }
public float Rain { get; set; }
public float Snow { get; set; }
public float SnowMist { get; set; }
public float Fog { get; set; }
public float RippleBumpiness { get; set; }
public float RippleMinBumpiness { get; set; }
public float RippleMaxBumpiness { get; set; }
public float RippleBumpinessWindScale { get; set; }
public float RippleScale { get; set; }
public float RippleSpeed { get; set; }
public float RippleVelocityTransfer { get; set; }
public float OceanBumpiness { get; set; }
public float DeepOceanScale { get; set; }
public float OceanNoiseMinAmplitude { get; set; }
public float OceanWaveAmplitude { get; set; }
public float ShoreWaveAmplitude { get; set; }
public float OceanWaveWindScale { get; set; }
public float ShoreWaveWindScale { get; set; }
public float OceanWaveMinAmplitude { get; set; }
public float ShoreWaveMinAmplitude { get; set; }
public float OceanWaveMaxAmplitude { get; set; }
public float ShoreWaveMaxAmplitude { get; set; }
public float OceanFoamIntensity { get; set; }
public float OceanFoamScale { get; set; }
public float RippleDisturb { get; set; }
public float Lightning { get; set; }
public float Sandstorm { get; set; }
public string OldSettingName { get; set; }
public string DropSettingName { get; set; }
public string MistSettingName { get; set; }
public string GroundSettingName { get; set; }
public string TimeCycleFilename { get; set; }
public string CloudSettingsName { get; set; }
public WeatherCycleKeyframeData TimeCycleData;
public void Init(GameFileCache gameFileCache, XmlNode node)
{
Name = Xml.GetChildInnerText(node, "Name");
NameHash = new MetaHash(JenkHash.GenHash(Name.ToLowerInvariant()));
Sun = Xml.GetChildFloatAttribute(node, "Sun", "value");
Cloud = Xml.GetChildFloatAttribute(node, "Cloud", "value");
WindMin = Xml.GetChildFloatAttribute(node, "WindMin", "value");
WindMax = Xml.GetChildFloatAttribute(node, "WindMax", "value");
Rain = Xml.GetChildFloatAttribute(node, "Rain", "value");
Snow = Xml.GetChildFloatAttribute(node, "Snow", "value");
SnowMist = Xml.GetChildFloatAttribute(node, "SnowMist", "value");
Fog = Xml.GetChildFloatAttribute(node, "Fog", "value");
RippleBumpiness = Xml.GetChildFloatAttribute(node, "RippleBumpiness", "value");
RippleMinBumpiness = Xml.GetChildFloatAttribute(node, "RippleMinBumpiness", "value");
RippleMaxBumpiness = Xml.GetChildFloatAttribute(node, "RippleMaxBumpiness", "value");
RippleBumpinessWindScale = Xml.GetChildFloatAttribute(node, "RippleBumpinessWindScale", "value");
RippleScale = Xml.GetChildFloatAttribute(node, "RippleScale", "value");
RippleSpeed = Xml.GetChildFloatAttribute(node, "RippleSpeed", "value");
RippleVelocityTransfer = Xml.GetChildFloatAttribute(node, "RippleVelocityTransfer", "value");
OceanBumpiness = Xml.GetChildFloatAttribute(node, "OceanBumpiness", "value");
DeepOceanScale = Xml.GetChildFloatAttribute(node, "DeepOceanScale", "value");
OceanNoiseMinAmplitude = Xml.GetChildFloatAttribute(node, "OceanNoiseMinAmplitude", "value");
OceanWaveAmplitude = Xml.GetChildFloatAttribute(node, "OceanWaveAmplitude", "value");
ShoreWaveAmplitude = Xml.GetChildFloatAttribute(node, "ShoreWaveAmplitude", "value");
OceanWaveWindScale = Xml.GetChildFloatAttribute(node, "OceanWaveWindScale", "value");
ShoreWaveWindScale = Xml.GetChildFloatAttribute(node, "ShoreWaveWindScale", "value");
OceanWaveMinAmplitude = Xml.GetChildFloatAttribute(node, "OceanWaveMinAmplitude", "value");
ShoreWaveMinAmplitude = Xml.GetChildFloatAttribute(node, "ShoreWaveMinAmplitude", "value");
OceanWaveMaxAmplitude = Xml.GetChildFloatAttribute(node, "OceanWaveMaxAmplitude", "value");
ShoreWaveMaxAmplitude = Xml.GetChildFloatAttribute(node, "ShoreWaveMaxAmplitude", "value");
OceanFoamIntensity = Xml.GetChildFloatAttribute(node, "OceanFoamIntensity", "value");
OceanFoamScale = Xml.GetChildFloatAttribute(node, "OceanFoamScale", "value");
RippleDisturb = Xml.GetChildFloatAttribute(node, "RippleDisturb", "value");
Lightning = Xml.GetChildFloatAttribute(node, "Lightning", "value");
Sandstorm = Xml.GetChildFloatAttribute(node, "Sandstorm", "value");
OldSettingName = Xml.GetChildInnerText(node, "OldSettingName");
DropSettingName = Xml.GetChildInnerText(node, "DropSettingName");
MistSettingName = Xml.GetChildInnerText(node, "MistSettingName");
GroundSettingName = Xml.GetChildInnerText(node, "GroundSettingName");
TimeCycleFilename = Xml.GetChildInnerText(node, "TimeCycleFilename");
CloudSettingsName = Xml.GetChildInnerText(node, "CloudSettingsName");
if (!string.IsNullOrEmpty(TimeCycleFilename))
{
//TODO: RpfMan should be able to get the right version? or maybe let gameFileCache do it!
string fname = TimeCycleFilename.ToLowerInvariant();
bool useupd = gameFileCache.EnableDlc;
if (useupd)
{
fname = fname.Replace("common:", "update/update.rpf/common");
}
XmlDocument tcxml = gameFileCache.RpfMan.GetFileXml(fname);
if (useupd && !tcxml.HasChildNodes)
{
fname = TimeCycleFilename.ToLowerInvariant();
tcxml = gameFileCache.RpfMan.GetFileXml(fname);
}
foreach (XmlNode cycle in tcxml.DocumentElement.ChildNodes)
{
TimeCycleData = new WeatherCycleKeyframeData();
TimeCycleData.Init(cycle);
}
}
}
public WeatherCycleKeyframeRegion GetRegion(string name)
{
if ((TimeCycleData != null) && (TimeCycleData.Regions != null))
{
WeatherCycleKeyframeRegion r;
if (TimeCycleData.Regions.TryGetValue(name, out r))
{
return r;
}
return TimeCycleData.Regions.Values.FirstOrDefault();
}
return null;
}
public override string ToString()
{
return Name;
}
}
public class WeatherCycle
{
public string CycleName { get; set; }
public float TimeMult { get; set; }
public void Init(XmlNode node)
{
CycleName = Xml.GetChildInnerText(node, "CycleName");
TimeMult = Xml.GetChildFloatAttribute(node, "TimeMult", "value");
}
public override string ToString()
{
return CycleName + ", " + TimeMult.ToString();
}
}
public class WeatherCycleKeyframeData
{
public string Name { get; set; }
public int RegionCount { get; set; }
public Dictionary<string, WeatherCycleKeyframeRegion> Regions { get; set; }
public void Init(XmlNode node)
{
//read cycle node
Name = Xml.GetStringAttribute(node, "name");
RegionCount = Xml.GetIntAttribute(node, "regions");
Regions = new Dictionary<string, WeatherCycleKeyframeRegion>();
foreach (XmlNode child in node.ChildNodes)
{
WeatherCycleKeyframeRegion r = new WeatherCycleKeyframeRegion();
r.Init(child);
Regions[r.Name] = r;
}
}
public override string ToString()
{
return Name;
}
}
public class WeatherCycleKeyframeRegion
{
public string Name { get; set; }
public Dictionary<string, WeatherCycleKeyframeDataEntry> Data { get; set; }
public void Init(XmlNode node)
{
//read region node
Name = Xml.GetStringAttribute(node, "name");
Data = new Dictionary<string, WeatherCycleKeyframeDataEntry>();
foreach (XmlNode child in node.ChildNodes)
{
if (child != null)
{
WeatherCycleKeyframeDataEntry d = new WeatherCycleKeyframeDataEntry();
d.Init(child);
Data[d.Name] = d;
}
}
}
public float GetCurrentValue(string name, int sample, float curblend)
{
WeatherCycleKeyframeDataEntry e;
if (Data.TryGetValue(name, out e))
{
if (sample >= e.Values.Length)
{
//System.Windows.Forms.MessageBox.Show("Sample index was out of range: " + sample.ToString());
sample = e.Values.Length - 1;
}
int nxtsample = (sample < e.Values.Length - 1) ? sample + 1 : 0;
float cv = e.Values[sample];
float nv = e.Values[nxtsample];
return cv * curblend + nv * (1.0f - curblend);
}
//throw new Exception("WeatherCycleKeyframeDataEntry " + name + " not found in region " + Name + ".");
return 0.0f;
}
public override string ToString()
{
return Name;
}
}
public class WeatherCycleKeyframeDataEntry
{
public string Name { get; set; }
public float[] Values { get; set; }
public void Init(XmlNode node)
{
//read data node
Name = node.Name;
string[] strvals = node.InnerText.Trim().Split(' ');
Values = new float[strvals.Length];
for (int i = 0; i < strvals.Length; i++)
{
if (!FloatUtil.TryParse(strvals[i], out Values[i]))
{
//System.Windows.Forms.MessageBox.Show("Error parsing float value: " + strvals[i] + "\n" +
// "Node: " + node.OuterXml.ToString());
//throw new Exception();
}
}
}
public override string ToString()
{
return Name;
}
}
public struct WeatherValues
{
public Vector3 sunDirection;
public Vector3 moonDirection;
public Vector4 skyZenithCol;
public Vector4 skyZenithTransitionCol;
public Vector4 skyZenithTransition;
public Vector4 skyAzimuthEastCol;
public Vector4 skyAzimuthWestCol;
public Vector4 skyAzimuthTransitionCol;
public float skyAzimuthTransition;
public float skyHdr;
public Vector4 skyPlane;
public Vector3 skySunCol;
public Vector3 skySunDiscCol;
public float skySunDiscSize;
public float skySunHdr;
public Vector3 skySunMie;
public float skySunInfluenceRadius;
public float skySunScatterInten;
public Vector3 skyMoonCol;
public float skyMoonDiscSize;
public float skyMoonIten;
public float skyMoonInfluenceRadius;
public float skyMoonScatterInten;
public float skyStarsIten;
public Vector4 lightDirCol;
public Vector4 lightDirAmbCol;
public float lightDirAmbIntensityMult;
public float lightDirAmbBounce;
public Vector4 lightNaturalAmbDown;
public Vector4 lightNaturalAmbUp;
public float lightNaturalAmbUpIntensityMult;
public Vector4 lightArtificialIntDown;
public Vector4 lightArtificialIntUp;
public Vector4 lightArtificialExtDown;
public Vector4 lightArtificialExtUp;
public void Update(Weather w)
{
sunDirection = w.GetDynamicRGB("sun_direction_x", "sun_direction_y", "sun_direction_z");
moonDirection = w.GetDynamicRGB("moon_direction_x", "moon_direction_y", "moon_direction_z");
skyZenithCol = w.GetDynamicRGBA("sky_zenith_col_r", "sky_zenith_col_g", "sky_zenith_col_b", "sky_zenith_col_inten");
skyZenithTransitionCol = w.GetDynamicRGBA("sky_zenith_transition_col_r", "sky_zenith_transition_col_g", "sky_zenith_transition_col_b", "sky_zenith_transition_col_inten");
//skyZenithTransition = w.GetDynamicRGBA("sky_zenith_transition_position", "sky_zenith_transition_east_blend", "sky_zenith_transition_west_blend", "sky_zenith_blend_start");
skyZenithTransition = w.GetDynamicRGBA("sky_zenith_blend_start", "sky_zenith_transition_east_blend", "sky_zenith_transition_west_blend", "sky_zenith_transition_position");
skyAzimuthEastCol = w.GetDynamicRGBA("sky_azimuth_east_col_r", "sky_azimuth_east_col_g", "sky_azimuth_east_col_b", "sky_azimuth_east_col_inten");
skyAzimuthWestCol = w.GetDynamicRGBA("sky_azimuth_west_col_r", "sky_azimuth_west_col_g", "sky_azimuth_west_col_b", "sky_azimuth_west_col_inten");
skyAzimuthTransitionCol = w.GetDynamicRGBA("sky_azimuth_transition_col_r", "sky_azimuth_transition_col_g", "sky_azimuth_transition_col_b", "sky_azimuth_transition_col_inten");
skyAzimuthTransition = w.GetDynamicValue("sky_azimuth_transition_position");
skyHdr = w.GetDynamicValue("sky_hdr");
skyPlane = w.GetDynamicRGBA("sky_plane_r", "sky_plane_g", "sky_plane_b", "sky_plane_inten");
skySunCol = w.GetDynamicRGB("sky_sun_col_r", "sky_sun_col_g", "sky_sun_col_b");
skySunDiscCol = w.GetDynamicRGB("sky_sun_disc_col_r", "sky_sun_disc_col_g", "sky_sun_disc_col_b");
skySunDiscSize = w.GetDynamicValue("sky_sun_disc_size");
skySunHdr = w.GetDynamicValue("sky_sun_hdr");
skySunMie = w.GetDynamicRGB("sky_sun_miephase", "sky_sun_miescatter", "sky_sun_mie_intensity_mult");
skySunInfluenceRadius = w.GetDynamicValue("sky_sun_influence_radius");
skySunScatterInten = w.GetDynamicValue("sky_sun_scatter_inten");
skyMoonCol = w.GetDynamicRGB("sky_moon_col_r", "sky_moon_col_g", "sky_moon_col_b");
skyMoonDiscSize = w.GetDynamicValue("sky_moon_disc_size");
skyMoonIten = w.GetDynamicValue("sky_moon_iten");
skyMoonInfluenceRadius = w.GetDynamicValue("sky_moon_influence_radius");
skyMoonScatterInten = w.GetDynamicValue("sky_moon_scatter_inten");
skyStarsIten = w.GetDynamicValue("sky_stars_iten");
lightDirCol = w.GetDynamicRGBA("light_dir_col_r", "light_dir_col_g", "light_dir_col_b", "light_dir_mult");
lightDirAmbCol = w.GetDynamicRGBA("light_directional_amb_col_r", "light_directional_amb_col_g", "light_directional_amb_col_b", "light_directional_amb_intensity");
lightDirAmbIntensityMult = w.GetDynamicValue("light_directional_amb_intensity_mult");
lightDirAmbBounce = w.GetDynamicValue("light_directional_amb_bounce_enabled");
lightNaturalAmbDown = w.GetDynamicRGBA("light_natural_amb_down_col_r", "light_natural_amb_down_col_g", "light_natural_amb_down_col_b", "light_natural_amb_down_intensity");
lightNaturalAmbUp = w.GetDynamicRGBA("light_natural_amb_up_col_r", "light_natural_amb_up_col_g", "light_natural_amb_up_col_b", "light_natural_amb_up_intensity");
lightNaturalAmbUpIntensityMult = w.GetDynamicValue("light_natural_amb_up_intensity_mult");
lightArtificialIntDown = w.GetDynamicRGBA("light_artificial_int_down_col_r", "light_artificial_int_down_col_g", "light_artificial_int_down_col_b", "light_artificial_int_down_intensity");
lightArtificialIntUp = w.GetDynamicRGBA("light_artificial_int_up_col_r", "light_artificial_int_up_col_g", "light_artificial_int_up_col_b", "light_artificial_int_up_intensity");
lightArtificialExtDown = w.GetDynamicRGBA("light_artificial_ext_down_col_r", "light_artificial_ext_down_col_g", "light_artificial_ext_down_col_b", "light_artificial_ext_down_intensity");
lightArtificialExtUp = w.GetDynamicRGBA("light_artificial_ext_up_col_r", "light_artificial_ext_up_col_g", "light_artificial_ext_up_col_b", "light_artificial_ext_up_intensity");
}
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="SharpDX" version="4.0.1" targetFramework="net461" />
<package id="SharpDX.Mathematics" version="4.0.1" targetFramework="net461" />
</packages>

View File

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<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>{9702C58D-F52F-45CF-9456-9CE5AF40F5C3}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>CodeWalker.WinForms</RootNamespace>
<AssemblyName>CodeWalker.WinForms</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<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' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<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="WeifenLuo.WinFormsUI.Docking, Version=3.0.4.0, Culture=neutral, PublicKeyToken=5cded1a1a0a7b481, processorArchitecture=MSIL">
<HintPath>..\packages\DockPanelSuite.3.0.4\lib\net40\WeifenLuo.WinFormsUI.Docking.dll</HintPath>
</Reference>
<Reference Include="WeifenLuo.WinFormsUI.Docking.ThemeVS2015, Version=3.0.4.0, Culture=neutral, PublicKeyToken=5cded1a1a0a7b481, processorArchitecture=MSIL">
<HintPath>..\packages\DockPanelSuite.ThemeVS2015.3.0.4\lib\net40\WeifenLuo.WinFormsUI.Docking.ThemeVS2015.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="MenuStripFix.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="MenuStripFix.Designer.cs">
<DependentUpon>MenuStripFix.cs</DependentUpon>
</Compile>
<Compile Include="ProjectPanel.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PropertyGridFix.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="PropertyGridFix.Designer.cs">
<DependentUpon>PropertyGridFix.cs</DependentUpon>
</Compile>
<Compile Include="ReadOnlyPropertyGrid.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ReadOnlyPropertyGrid.Designer.cs">
<DependentUpon>ReadOnlyPropertyGrid.cs</DependentUpon>
</Compile>
<Compile Include="TextBoxFix.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="TextBoxFix.Designer.cs">
<DependentUpon>TextBoxFix.cs</DependentUpon>
</Compile>
<Compile Include="TextBoxScrollSyncFix.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="TextBoxScrollSyncFix.Designer.cs">
<DependentUpon>TextBoxScrollSyncFix.cs</DependentUpon>
</Compile>
<Compile Include="ToolStripFix.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ToolStripFix.Designer.cs">
<DependentUpon>ToolStripFix.cs</DependentUpon>
</Compile>
<Compile Include="ToolStripSplitButtonFix.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ToolStripSplitButtonFix.Designer.cs">
<DependentUpon>ToolStripSplitButtonFix.cs</DependentUpon>
</Compile>
<Compile Include="ToolStripSpringTextBox.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="ToolStripSpringTextBox.Designer.cs">
<DependentUpon>ToolStripSpringTextBox.cs</DependentUpon>
</Compile>
<Compile Include="TreeViewFix.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="TreeViewFix.Designer.cs">
<DependentUpon>TreeViewFix.cs</DependentUpon>
</Compile>
<Compile Include="FormUtils.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,459 @@
using CodeWalker.WinForms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
using Point = System.Drawing.Point;
namespace CodeWalker
{
////public static class Utils
////{
//// //unused
//// //public static Bitmap ResizeImage(Image image, int width, int height)
//// //{
//// // var destRect = new Rectangle(0, 0, width, height);
//// // var destImage = new Bitmap(width, height);
//// // destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);
//// // using (var graphics = Graphics.FromImage(destImage))
//// // {
//// // graphics.CompositingMode = CompositingMode.SourceCopy;
//// // graphics.CompositingQuality = CompositingQuality.HighQuality;
//// // graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
//// // graphics.SmoothingMode = SmoothingMode.HighQuality;
//// // graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
//// // using (var wrapMode = new ImageAttributes())
//// // {
//// // wrapMode.SetWrapMode(WrapMode.TileFlipXY);
//// // graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
//// // }
//// // }
//// // return destImage;
//// //}
////}
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ListViewExtensions
{
//from stackoverflow:
//https://stackoverflow.com/questions/254129/how-to-i-display-a-sort-arrow-in-the-header-of-a-list-view-column-using-c
[StructLayout(LayoutKind.Sequential)]
public struct HDITEM
{
public Mask mask;
public int cxy;
[MarshalAs(UnmanagedType.LPTStr)] public string pszText;
public IntPtr hbm;
public int cchTextMax;
public Format fmt;
public IntPtr lParam;
// _WIN32_IE >= 0x0300
public int iImage;
public int iOrder;
// _WIN32_IE >= 0x0500
public uint type;
public IntPtr pvFilter;
// _WIN32_WINNT >= 0x0600
public uint state;
[Flags]
public enum Mask
{
Format = 0x4, // HDI_FORMAT
};
[Flags]
public enum Format
{
SortDown = 0x200, // HDF_SORTDOWN
SortUp = 0x400, // HDF_SORTUP
};
};
public const int LVM_FIRST = 0x1000;
public const int LVM_GETHEADER = LVM_FIRST + 31;
public const int HDM_FIRST = 0x1200;
public const int HDM_GETITEM = HDM_FIRST + 11;
public const int HDM_SETITEM = HDM_FIRST + 12;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SendMessage(IntPtr hWnd, UInt32 msg, IntPtr wParam, ref HDITEM lParam);
public static void SetSortIcon(this ListView listViewControl, int columnIndex, SortOrder order)
{
IntPtr columnHeader = SendMessage(listViewControl.Handle, LVM_GETHEADER, IntPtr.Zero, IntPtr.Zero);
for (int columnNumber = 0; columnNumber <= listViewControl.Columns.Count - 1; columnNumber++)
{
var columnPtr = new IntPtr(columnNumber);
var item = new HDITEM
{
mask = HDITEM.Mask.Format
};
if (SendMessage(columnHeader, HDM_GETITEM, columnPtr, ref item) == IntPtr.Zero)
{
throw new Win32Exception();
}
if (order != SortOrder.None && columnNumber == columnIndex)
{
switch (order)
{
case SortOrder.Ascending:
item.fmt &= ~HDITEM.Format.SortDown;
item.fmt |= HDITEM.Format.SortUp;
break;
case SortOrder.Descending:
item.fmt &= ~HDITEM.Format.SortUp;
item.fmt |= HDITEM.Format.SortDown;
break;
}
}
else
{
item.fmt &= ~HDITEM.Format.SortDown & ~HDITEM.Format.SortUp;
}
if (SendMessage(columnHeader, HDM_SETITEM, columnPtr, ref item) == IntPtr.Zero)
{
throw new Win32Exception();
}
}
}
//private const int LVM_FIRST = 0x1000;
private const int LVM_SETITEMSTATE = LVM_FIRST + 43;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct LVITEM
{
public int mask;
public int iItem;
public int iSubItem;
public int state;
public int stateMask;
[MarshalAs(UnmanagedType.LPTStr)]
public string pszText;
public int cchTextMax;
public int iImage;
public IntPtr lParam;
public int iIndent;
public int iGroupId;
public int cColumns;
public IntPtr puColumns;
};
[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessageLVItem(IntPtr hWnd, int msg, int wParam, ref LVITEM lvi);
/// <summary>
/// Select all rows on the given listview
/// </summary>
/// <param name="list">The listview whose items are to be selected</param>
public static void SelectAllItems(this ListView list)
{
SetItemState(list, -1, 2, 2);
}
/// <summary>
/// Deselect all rows on the given listview
/// </summary>
/// <param name="list">The listview whose items are to be deselected</param>
public static void DeselectAllItems(this ListView list)
{
SetItemState(list, -1, 2, 0);
}
/// <summary>
/// Set the item state on the given item
/// </summary>
/// <param name="list">The listview whose item's state is to be changed</param>
/// <param name="itemIndex">The index of the item to be changed</param>
/// <param name="mask">Which bits of the value are to be set?</param>
/// <param name="value">The value to be set</param>
public static void SetItemState(ListView list, int itemIndex, int mask, int value)
{
LVITEM lvItem = new LVITEM();
lvItem.stateMask = mask;
lvItem.state = value;
SendMessageLVItem(list.Handle, LVM_SETITEMSTATE, itemIndex, ref lvItem);
}
}
public static class TextBoxExtension
{
private const int EM_SETTABSTOPS = 0x00CB;
[DllImport("User32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(IntPtr h, int msg, int wParam, int[] lParam);
public static Point GetCaretPosition(this TextBox textBox)
{
Point point = new Point(0, 0);
if (textBox.Focused)
{
point.X = textBox.SelectionStart - textBox.GetFirstCharIndexOfCurrentLine() + 1;
point.Y = textBox.GetLineFromCharIndex(textBox.SelectionStart) + 1;
}
return point;
}
public static void SetTabStopWidth(this TextBox textbox, int width)
{
SendMessage(textbox.Handle, EM_SETTABSTOPS, 1, new int[] { width * 4 });
}
}
public static class Prompt
{
//handy utility to get a string from the user...
public static string ShowDialog(IWin32Window owner, string text, string caption, ThemeBase theme, string defaultvalue = "")
{
Form prompt = new Form()
{
Width = 450,
Height = 150,
FormBorderStyle = FormBorderStyle.FixedDialog,
Text = caption,
StartPosition = FormStartPosition.CenterParent,
MaximizeBox = false,
MinimizeBox = false
};
FormTheme.SetTheme(prompt, theme);
var textLabel = new Label() { Left = 30, Top = 20, Width = 370, Height = 20, Text = text, };
var textBox = new TextBox() { Left = 30, Top = 40, Width = 370, Text = defaultvalue };
var cancel = new Button() { Text = "Cancel", Left = 230, Width = 80, Top = 70, DialogResult = DialogResult.Cancel };
var confirmation = new Button() { Text = "Ok", Left = 320, Width = 80, Top = 70, DialogResult = DialogResult.OK };
cancel.Click += (sender, e) => { prompt.Close(); };
confirmation.Click += (sender, e) => { prompt.Close(); };
prompt.Controls.Add(textBox);
prompt.Controls.Add(confirmation);
prompt.Controls.Add(cancel);
prompt.Controls.Add(textLabel);
prompt.AcceptButton = confirmation;
return prompt.ShowDialog(owner) == DialogResult.OK ? textBox.Text : "";
}
}
public static class FormTheme
{
public static void SetTheme(Control form, ThemeBase theme)
{
form.BackColor = SystemColors.Control;
form.ForeColor = SystemColors.ControlText;
var txtback = SystemColors.Window;
var wndback = SystemColors.Window;
var disback = SystemColors.Control;
var disfore = form.ForeColor;
var btnback = Color.Transparent;
var fStyle = FlatStyle.System;
var panelC = SystemColors.Control;
var dropdwn = SystemColors.Control;
var dropdwntxt = form.ForeColor;
if (theme is VS2015DarkTheme)
{
form.BackColor = theme.ColorPalette.MainWindowActive.Background;
form.ForeColor = Color.White;
txtback = Color.FromArgb(72, 75, 82);// form.BackColor;
wndback = theme.ColorPalette.MainWindowActive.Background;
disback = form.BackColor;// Color.FromArgb(32,32,32);
disfore = Color.DarkGray;
btnback = form.BackColor;
fStyle = FlatStyle.Flat;
panelC = form.BackColor;
dropdwn = form.BackColor;
dropdwntxt = form.ForeColor;
}
if (theme is VS2015BlueTheme)
{
panelC = theme.ColorPalette.MainWindowActive.Background;
dropdwn = panelC;
dropdwntxt = Color.White;
}
var allcontrols = new List<Control>();
RecurseControls(form, allcontrols);
foreach (var c in allcontrols)
{
if (c is TabPage)
{
c.ForeColor = form.ForeColor;
c.BackColor = wndback;
}
else if ((c is CheckedListBox) || (c is ListBox))
{
c.ForeColor = form.ForeColor;
c.BackColor = txtback;
}
else if ((c is ListView))
{
c.ForeColor = form.ForeColor;
c.BackColor = wndback;
}
else if ((c is TextBox))
{
var txtbox = c as TextBox;
c.ForeColor = txtbox.ReadOnly ? disfore : form.ForeColor;
c.BackColor = txtbox.ReadOnly ? disback : txtback;
}
else if ((c is Button) || (c is GroupBox))
{
c.ForeColor = form.ForeColor;
c.BackColor = btnback;
}
else if (c is TreeView)
{
c.ForeColor = form.ForeColor;
c.BackColor = wndback;
(c as TreeView).LineColor = form.ForeColor;
}
else if (c is Panel)
{
c.BackColor = panelC;
}
else if (c is TrackBar)
{
c.BackColor = form.BackColor;
}
else if (c is ReadOnlyPropertyGrid)
{
var rpd = (ReadOnlyPropertyGrid)c;
rpd.ViewBackColor = txtback;
rpd.ViewForeColor = form.ForeColor;
}
else if (c is PropertyGridFix)
{
var rpd = (PropertyGridFix)c;
rpd.ViewBackColor = form.BackColor;
rpd.ViewForeColor = form.ForeColor;
}
else if (c is ComboBox)
{
var cb = (ComboBox)c;
cb.BackColor = dropdwn;
cb.FlatStyle = fStyle;
cb.ForeColor = dropdwntxt;
}
else if (c is ContextMenuStrip)
{
c.BackColor = form.BackColor;
c.ForeColor = form.ForeColor;
}
else if (c is StatusStrip)
{
var ss = (StatusStrip)c;
VisualStudioToolStripExtender ve = new VisualStudioToolStripExtender();
var version = VisualStudioToolStripExtender.VsVersion.Vs2015;
ve.SetStyle(ss, version, theme);
}
else if (c is MenuStrip)
{
var ms = (MenuStrip)c;
VisualStudioToolStripExtender ve = new VisualStudioToolStripExtender();
var version = VisualStudioToolStripExtender.VsVersion.Vs2015;
ve.SetStyle(ms, version, theme);
}
else if (c is ToolStrip)
{
var ts = (ToolStrip)c;
VisualStudioToolStripExtender ve = new VisualStudioToolStripExtender();
var version = VisualStudioToolStripExtender.VsVersion.Vs2015;
ve.SetStyle(ts, version, theme);
}
else if (c is ToolStripFix)
{
var tsf = (ToolStripFix)c;
VisualStudioToolStripExtender ve = new VisualStudioToolStripExtender();
var version = VisualStudioToolStripExtender.VsVersion.Vs2015;
ve.SetStyle(tsf, version, theme);
}
}
}
private static void RecurseControls(Control c, List<Control> l)
{
foreach (Control cc in c.Controls)
{
l.Add(cc);
RecurseControls(cc, l);
}
}
}
//unused
//public class AccurateTimer
//{
// private delegate void TimerEventDel(int id, int msg, IntPtr user, int dw1, int dw2);
// private const int TIME_PERIODIC = 1;
// private const int EVENT_TYPE = TIME_PERIODIC;// + 0x100; // TIME_KILL_SYNCHRONOUS causes a hang ?!
// [DllImport("winmm.dll")]
// private static extern int timeBeginPeriod(int msec);
// [DllImport("winmm.dll")]
// private static extern int timeEndPeriod(int msec);
// [DllImport("winmm.dll")]
// private static extern int timeSetEvent(int delay, int resolution, TimerEventDel handler, IntPtr user, int eventType);
// [DllImport("winmm.dll")]
// private static extern int timeKillEvent(int id);
// Action mAction;
// Form mForm;
// private int mTimerId;
// private TimerEventDel mHandler; // NOTE: declare at class scope so garbage collector doesn't release it!!!
// public AccurateTimer(Form form, Action action, int delay)
// {
// mAction = action;
// mForm = form;
// timeBeginPeriod(1);
// mHandler = new TimerEventDel(TimerCallback);
// mTimerId = timeSetEvent(delay, 0, mHandler, IntPtr.Zero, EVENT_TYPE);
// }
// public void Stop()
// {
// int err = timeKillEvent(mTimerId);
// timeEndPeriod(1);
// System.Threading.Thread.Sleep(100);// Ensure callbacks are drained
// }
// private void TimerCallback(int id, int msg, IntPtr user, int dw1, int dw2)
// {
// if (mTimerId != 0) mForm.BeginInvoke(mAction);
// }
//}
}

View File

@ -0,0 +1,36 @@
namespace CodeWalker.WinForms
{
partial class MenuStripFix
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CodeWalker.WinForms
{
public partial class MenuStripFix : MenuStrip
{
public MenuStripFix()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
base.OnPaint(pe);
}
const uint WM_LBUTTONDOWN = 0x201;
const uint WM_LBUTTONUP = 0x202;
static private bool down = false;
protected override void WndProc(ref Message m)
{
//fix to properly handle the mouse down event when the form isn't currently focused...
if (m.Msg == WM_LBUTTONUP && !down)
{
m.Msg = (int)WM_LBUTTONDOWN;
base.WndProc(ref m);
m.Msg = (int)WM_LBUTTONUP;
}
if (m.Msg == WM_LBUTTONDOWN) down = true;
if (m.Msg == WM_LBUTTONUP) down = false;
base.WndProc(ref m);
}
}
}

View File

@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WeifenLuo.WinFormsUI.Docking;
namespace CodeWalker.Project
{
public class ProjectPanel : DockContent
{
public virtual void SetTheme(ThemeBase theme)
{
FormTheme.SetTheme(this, theme);
}
}
public class ProjectFloatWindow : FloatWindow
{
public ProjectFloatWindow(DockPanel dockPanel, DockPane pane)
: base(dockPanel, pane)
{
Init(dockPanel, pane);
}
public ProjectFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds)
: base(dockPanel, pane, bounds)
{
Init(dockPanel, pane);
}
private void Init(DockPanel dockPanel, DockPane pane)
{
FormBorderStyle = FormBorderStyle.Sizable;
//trying to set float window tab strip location to the top... for some reason it defaults to bottom!
//var t = this;
//if (pane != null)
//{
// pane.DockState = DockState.Document;
//}
//if (dockPanel != null)
//{
// dockPanel.DocumentTabStripLocation = DocumentTabStripLocation.Top;
//}
//if (DockPanel != null)
//{
// DockPanel.DocumentTabStripLocation = DocumentTabStripLocation.Top;
//}
}
}
public class ProjectFloatWindowFactory : DockPanelExtender.IFloatWindowFactory
{
public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane, Rectangle bounds)
{
return new ProjectFloatWindow(dockPanel, pane, bounds);
}
public FloatWindow CreateFloatWindow(DockPanel dockPanel, DockPane pane)
{
return new ProjectFloatWindow(dockPanel, pane);
}
}
}

Some files were not shown because too many files have changed in this diff Show More