Skip to content

Commit

Permalink
implement singleplayer resource
Browse files Browse the repository at this point in the history
fix drawables with skin generating  ydd as _u
  • Loading branch information
grzybeek committed Mar 31, 2024
1 parent 77bcb1f commit d875f08
Show file tree
Hide file tree
Showing 10 changed files with 786 additions and 126 deletions.
2 changes: 2 additions & 0 deletions CodeWalker/CodeWalker.Core/GameFiles/MetaTypes/Rbf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ namespace CodeWalker.GameFiles
public List<RbfEntryDescription> descriptors { get; set; }
public Dictionary<string, int> outDescriptors { get; private set; } = new Dictionary<string, int>();

public string SingleplayerFileName { get; set; }


public void Load(byte[] data)
{
Expand Down
169 changes: 165 additions & 4 deletions CodeWalker/CodeWalker.Core/GameFiles/RpfFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -967,18 +967,154 @@ public static byte[] CompressBytes(byte[] data) //TODO: refactor this with Resou
}
}

public static RpfFileEntry CreateFile(RpfDirectoryEntry dir, string name, byte[] data, bool overwrite = true)
{
string namel = name.ToLowerInvariant();
if (overwrite)
{
foreach (var exfile in dir.Files)
{
if (exfile.NameLower == namel)
{
//file already exists. delete the existing one first!
//this should probably be optimised to just replace the existing one...
//TODO: investigate along with ExploreForm.ReplaceSelected()
DeleteEntry(exfile);
break;
}
}
}
//else fail if already exists..? items with the same name allowed?

RpfFile parent = dir.File;
string fpath = parent.GetPhysicalFilePath();
string rpath = dir.Path + "\\" + namel;
if (!File.Exists(fpath))
{
throw new Exception("Root RPF file " + fpath + " does not exist!");
}


RpfFileEntry entry = null;
uint len = (uint)data.Length;


bool isrpf = false;
bool isawc = false;
uint hdr = 0;
if (len >= 16)
{
hdr = BitConverter.ToUInt32(data, 0);
}

if (hdr == 0x37435352) //'RSC7'
{
//RSC header is present... import as resource
var rentry = new RpfResourceFileEntry();
var version = BitConverter.ToUInt32(data, 4);
rentry.SystemFlags = BitConverter.ToUInt32(data, 8);
rentry.GraphicsFlags = BitConverter.ToUInt32(data, 12);
rentry.FileSize = len;
if (len >= 0xFFFFFF)
{
//just....why
//FileSize = (buf[7] << 0) | (buf[14] << 8) | (buf[5] << 16) | (buf[2] << 24);
data[7] = (byte)((len >> 0) & 0xFF);
data[14] = (byte)((len >> 8) & 0xFF);
data[5] = (byte)((len >> 16) & 0xFF);
data[2] = (byte)((len >> 24) & 0xFF);
}

entry = rentry;
}

if (namel.EndsWith(".rpf") && (hdr == 0x52504637)) //'RPF7'
{
isrpf = true;
}
if (namel.EndsWith(".awc"))
{
isawc = true;
}

if (entry == null)
{
//no RSC7 header present, import as a binary file.
var compressed = (isrpf || isawc) ? data : CompressBytes(data);
var bentry = new RpfBinaryFileEntry();
bentry.EncryptionType = 0;//TODO: binary encryption
bentry.IsEncrypted = false;
bentry.FileUncompressedSize = (uint)data.Length;
bentry.FileSize = (isrpf || isawc) ? 0 : (uint)compressed.Length;
if (bentry.FileSize > 0xFFFFFF)
{
bentry.FileSize = 0;
compressed = data;
//can't compress?? since apparently FileSize>0 means compressed...
}
data = compressed;
entry = bentry;
}

entry.Parent = dir;
entry.File = parent;
entry.Path = rpath;
entry.Name = name;
entry.NameLower = name.ToLowerInvariant();
entry.NameHash = JenkHash.GenHash(name);
entry.ShortNameHash = JenkHash.GenHash(entry.GetShortNameLower());




foreach (var exfile in dir.Files)
{
if (exfile.NameLower == entry.NameLower)
{
throw new Exception("File \"" + entry.Name + "\" already exists!");
}
}



dir.Files.Add(entry);


using (var fstream = File.Open(fpath, FileMode.Open, FileAccess.ReadWrite))
{
using (var bw = new BinaryWriter(fstream))
{
parent.InsertFileSpace(bw, entry);
long bbeg = parent.StartPos + (entry.FileOffset * 512);
long bend = bbeg + (GetBlockCount(entry.GetFileSize()) * 512);
fstream.Position = bbeg;
fstream.Write(data, 0, data.Length);
WritePadding(fstream, bend); //write 0's until the end of the block.
}
}


if (isrpf)
{
//importing a raw RPF archive. create the new RpfFile object, and read its headers etc.
RpfFile file = new RpfFile(name, rpath, data.LongLength);
file.Parent = parent;
file.ParentFileEntry = entry as RpfBinaryFileEntry;
file.StartPos = parent.StartPos + (entry.FileOffset * 512);
parent.Children.Add(file);

using (var fstream = File.OpenRead(fpath))
{
using (var br = new BinaryReader(fstream))
{
fstream.Position = file.StartPos;
file.ScanStructure(br, null, null);
}
}
}

return entry;
}

private void WriteHeader(BinaryWriter bw)
{
Expand Down Expand Up @@ -1506,10 +1642,11 @@ public static RpfFile CreateNew(string gtafolder, string relpath, RpfEncryption
fpath = fpath.EndsWith("\\") ? fpath : fpath + "\\";
fpath = fpath + relpath;

if (File.Exists(fpath))
{
throw new Exception("File " + fpath + " already exists!");
}
//if (File.Exists(fpath))
//{

// throw new Exception("File " + fpath + " already exists!");
//}

File.Create(fpath).Dispose(); //just write a placeholder, will fill it out later

Expand All @@ -1526,6 +1663,30 @@ public static RpfFile CreateNew(string gtafolder, string relpath, RpfEncryption
return file;
}

public static RpfDirectoryEntry CreateDirectory(RpfDirectoryEntry rpfRoot, string directoryName)
{
RpfDirectoryEntry newDirectory = new RpfDirectoryEntry
{
Name = directoryName,
NameLower = directoryName.ToLowerInvariant(),
Path = rpfRoot.Path + "\\" + directoryName.ToLowerInvariant(),
File = rpfRoot.File,
Parent = rpfRoot
};

rpfRoot.Directories.Add(newDirectory);

using (var fstream = File.Open(rpfRoot.File.GetPhysicalFilePath(), FileMode.Open, FileAccess.ReadWrite))
{
using (var bw = new BinaryWriter(fstream))
{
rpfRoot.File.EnsureAllEntries();
rpfRoot.File.WriteHeader(bw);
}
}
return newDirectory;
}

public static RpfFile CreateNew(RpfDirectoryEntry dir, string name, RpfEncryption encryption = RpfEncryption.OPEN)
{
//create a new empty RPF inside the given parent RPF directory.
Expand Down
56 changes: 56 additions & 0 deletions grzyClothTool/Controls/ModernLabel/ModernLabelRadioButton.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<UserControl x:Class="grzyClothTool.Controls.ModernLabelRadioButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:grzyClothTool.Controls"
x:Name="MyModernLabelRadioButton">

<RadioButton x:Name="MyRadioButton"
GroupName="{Binding GroupName, ElementName=MyModernLabelRadioButton}"
IsChecked="{Binding IsChecked, ElementName=MyModernLabelRadioButton, Mode=TwoWay}"
Content="{Binding Label, ElementName=MyModernLabelRadioButton}"
Checked="RadioButton_Change"
Unchecked="RadioButton_Change"
VerticalContentAlignment="Center"
HorizontalContentAlignment="Left"
Padding="5,0"
Margin="5">
<RadioButton.Template>
<ControlTemplate TargetType="RadioButton">
<Border x:Name="border"
Height="40"
CornerRadius="5"
Background="{StaticResource ButtonBackground}"
BorderBrush="{StaticResource ButtonBorder}"
BorderThickness="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Ellipse x:Name="Indicator"
Width="12"
Height="12"
Fill="Transparent"
Stroke="{StaticResource ButtonFocus}"
StrokeThickness="2"
VerticalAlignment="Center"
Margin="5,0"/>
<ContentPresenter Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,0"
Content="{TemplateBinding Content}"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="Indicator" Property="Fill" Value="{StaticResource ButtonFocus}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource ButtonHover}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</RadioButton.Template>
</RadioButton>
</UserControl>
63 changes: 63 additions & 0 deletions grzyClothTool/Controls/ModernLabel/ModernLabelRadioButton.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using System.Windows;
using System.Windows.Controls;

namespace grzyClothTool.Controls
{
public partial class ModernLabelRadioButton : UserControl
{
public ModernLabelRadioButton()
{
InitializeComponent();
}

public static readonly DependencyProperty GroupNameProperty =
DependencyProperty.Register("GroupName", typeof(string), typeof(ModernLabelRadioButton), new PropertyMetadata(string.Empty));

public static readonly DependencyProperty LabelProperty =
DependencyProperty.Register("Label", typeof(string), typeof(ModernLabelRadioButton), new PropertyMetadata(string.Empty));

public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof(bool?), typeof(ModernLabelRadioButton), new PropertyMetadata(false));

public static readonly RoutedEvent RadioBtnSelectEvent = EventManager.RegisterRoutedEvent(
"BtnSelectEvent",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(ModernLabelRadioButton)
);

public event RoutedEventHandler MyBtnSelectEvent
{
add { AddHandler(RadioBtnSelectEvent, value); }
remove { RemoveHandler(RadioBtnSelectEvent, value); }
}

public string GroupName
{
get { return (string)GetValue(GroupNameProperty); }
set { SetValue(GroupNameProperty, value); }
}

public bool? IsChecked
{
get { return (bool?)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}

public string Label
{
get { return (string)GetValue(LabelProperty); }
set { SetValue(LabelProperty, value); }
}

private void RadioButton_Change(object sender, RoutedEventArgs e)
{
BtnSelectEventArgs args = new(RadioBtnSelectEvent);
RaiseEvent(args);
}

private class BtnSelectEventArgs(RoutedEvent routedEvent) : RoutedEventArgs(routedEvent)
{
}
}
}
Loading

0 comments on commit d875f08

Please sign in to comment.