added DrawStats + Flat Spellbreak icons, fixed DBD textures + challenges

This commit is contained in:
iAmAsval 2020-10-07 23:53:00 +02:00
parent 78d49f9d06
commit 1c1a3edc9c
19 changed files with 171 additions and 54 deletions

View File

@ -14,6 +14,9 @@ namespace FModel.Creator.Bases
public SKBitmap IconImage;
public SKColor[] RarityBackgroundColors;
public SKColor[] RarityBorderColor;
public SKBitmap RarityBackgroundImage1;
public SKBitmap RarityBackgroundImage2;
public string RarityDisplayName;
public string DisplayName;
public string Description;
public int Width = 512; // keep it 512 (or a multiple of 512) if you don't want blurry icons
@ -26,6 +29,9 @@ namespace FModel.Creator.Bases
IconImage = FallbackImage;
RarityBackgroundColors = new SKColor[2] { SKColor.Parse("FFFFFF"), SKColor.Parse("636363") };
RarityBorderColor = new SKColor[2] { SKColor.Parse("D0D0D0"), SKColor.Parse("FFFFFF") };
RarityBackgroundImage1 = null;
RarityBackgroundImage2 = null;
RarityDisplayName = "";
DisplayName = "";
Description = "";
Width = exportType switch
@ -43,7 +49,9 @@ namespace FModel.Creator.Bases
public BaseGCosmetic(IUExport export, string exportType) : this(exportType)
{
// rarity
Rarity.GetInGameRarity(this, export.GetExport<EnumProperty>("Rarity"));
EnumProperty r = export.GetExport<EnumProperty>("Rarity");
Rarity.GetInGameRarity(this, r);
this.RarityDisplayName = r != null ? r?.Value.String["EXRarity::".Length..] : "Common";
// image
if (export.GetExport<SoftObjectProperty>("IconTexture") is SoftObjectProperty previewImage)
@ -56,6 +64,33 @@ namespace FModel.Creator.Bases
DisplayName = Text.GetTextPropertyBase(displayName);
if (export.GetExport<TextProperty>("Description") is TextProperty description)
Description = Text.GetTextPropertyBase(description);
RarityBackgroundImage1 = Utils.GetTexture("/Game/UI/Textures/assets/HUDAccentFillBox.HUDAccentFillBox");
RarityBackgroundImage2 = Utils.GetTexture("/Game/UI/Textures/assets/store/ItemBGStatic_UIT.ItemBGStatic_UIT");
}
public void Draw(SKCanvas c)
{
if (this.RarityBackgroundImage1 != null)
c.DrawBitmap(this.RarityBackgroundImage1, new SKRect(0, 0, Width, Height),
new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true });
if (this.RarityBackgroundImage2 != null)
c.DrawBitmap(this.RarityBackgroundImage2, new SKRect(0, 0, Width, Height),
new SKPaint { FilterQuality = SKFilterQuality.High, IsAntialias = true, Color = SKColors.Transparent.WithAlpha(75) });
int x = this.Margin * (int)2.5;
int radi = 15;
c.DrawCircle(x + radi, x + radi, radi, new SKPaint
{
IsAntialias = true,
FilterQuality = SKFilterQuality.High,
Shader = SKShader.CreateRadialGradient(
new SKPoint(radi, radi),
(radi * 2) / 5 * 4,
this.RarityBackgroundColors,
SKShaderTileMode.Clamp)
});
}
SKBitmap IBase.FallbackImage => FallbackImage;

View File

@ -129,16 +129,16 @@ namespace FModel.Creator.Bases
else if (export.GetExport<ObjectProperty>("cosmetic_item") is ObjectProperty cosmeticItem) // variants
CosmeticSource = cosmeticItem.Value.Resource.ObjectName.String;
if (export.GetExport<SoftObjectProperty>("AmmoData") is SoftObjectProperty ammoData)
if (Properties.Settings.Default.DrawStats && export.GetExport<SoftObjectProperty>("AmmoData") is SoftObjectProperty ammoData)
Statistics.GetAmmoData(this, ammoData);
if (export.GetExport<StructProperty>("WeaponStatHandle") is StructProperty weaponStatHandle &&
if (Properties.Settings.Default.DrawStats && export.GetExport<StructProperty>("WeaponStatHandle") is StructProperty weaponStatHandle &&
(exportType.Equals("FortWeaponMeleeItemDefinition") ||
(export.GetExport<SoftObjectProperty>("StatList") is SoftObjectProperty statList &&
!statList.Value.AssetPathName.String.StartsWith("/Game/UI/Tooltips/NoTooltipStats"))))
{
Statistics.GetWeaponStats(this, weaponStatHandle);
}
if (export.GetExport<ObjectProperty>("HeroGameplayDefinition") is ObjectProperty heroGameplayDefinition)
if (Properties.Settings.Default.DrawStats && export.GetExport<ObjectProperty>("HeroGameplayDefinition") is ObjectProperty heroGameplayDefinition)
Statistics.GetHeroStats(this, heroGameplayDefinition);
/* Please do not add Schematics support because it takes way too much memory */

View File

@ -34,13 +34,12 @@ namespace FModel.Creator.Bundles
string[] parts = assetName.Split(':');
if (parts[0].Equals("HomebaseBannerIcon", StringComparison.CurrentCultureIgnoreCase))
{
PakPackage p = Utils.GetPropertyPakPackage("/Game/Banners/BannerIcons");
PakPackage p = Utils.GetPropertyPakPackage($"/Game/Items/BannerIcons/{parts[1]}.{parts[1]}");
if (p.HasExport() && !p.Equals(default))
{
var c = p.GetExport<UDataTable>();
if (c != null && c.TryGetCaseInsensitiveValue(parts[1], out var s) && s is UObject banner)
if (p.GetExport<UObject>() is UObject banner)
{
RewardIcon = new BaseIcon(banner, "BannerIcons.uasset", false).IconImage.Resize(64, 64);
RewardIcon = new BaseIcon(banner, $"{parts[1]}.uasset", false).IconImage.Resize(64, 64);
}
}
}

View File

@ -312,9 +312,16 @@ namespace FModel.Creator
using (var ret = new SKBitmap(icon.Width, icon.Height, SKColorType.Rgba8888, SKAlphaType.Premul))
using (var c = new SKCanvas(ret))
{
if ((EIconDesign)Properties.Settings.Default.AssetsIconDesign != EIconDesign.NoBackground)
if ((EIconDesign)Properties.Settings.Default.AssetsIconDesign == EIconDesign.Flat)
{
Rarity.DrawRarity(c, icon);
icon.Draw(c);
}
else
{
if ((EIconDesign)Properties.Settings.Default.AssetsIconDesign != EIconDesign.NoBackground)
{
Rarity.DrawRarity(c, icon);
}
}
LargeSmallImage.DrawPreviewImage(c, icon);

View File

@ -36,7 +36,7 @@ namespace FModel.Creator.Texts
if (p.HasExport() && !p.Equals(default))
{
var d = p.GetExport<UDataTable>();
if (d != null && d.TryGetValue(setName, out var obj) && obj is UObject o)
if (d != null && d.TryGetCaseInsensitiveValue(setName, out var obj) && obj is UObject o)
{
if (o.TryGetValue("DisplayName", out var displayName) && displayName is TextProperty t)
{

View File

@ -237,8 +237,8 @@ namespace FModel.Creator.Texts
{
IsAntialias = true,
FilterQuality = SKFilterQuality.High,
Typeface = side == ETextSide.Left ? TypeFaces.DisplayNameTypeface : TypeFaces.DefaultTypeface,
TextSize = 15,
Typeface = side == ETextSide.Left ? TypeFaces.BottomDefaultTypeface ?? TypeFaces.DisplayNameTypeface : TypeFaces.BottomDefaultTypeface ?? TypeFaces.DefaultTypeface,
TextSize = TypeFaces.BottomDefaultTypeface == null ? 15 : 13,
Color = SKColors.White,
TextAlign = side == ETextSide.Left ? SKTextAlign.Left : SKTextAlign.Right,
};

View File

@ -60,6 +60,7 @@ namespace FModel.Creator.Texts
public SKTypeface DefaultTypeface; // used as default font for all untranslated strings (item source, ...)
public SKTypeface BundleDefaultTypeface; // used for the last folder string
public SKTypeface BottomDefaultTypeface;
public SKTypeface DisplayNameTypeface;
public SKTypeface DescriptionTypeface;
public SKTypeface BundleDisplayNameTypeface;
@ -90,6 +91,17 @@ namespace FModel.Creator.Texts
}
else DisplayNameTypeface = DefaultTypeface;
string bottomPath = _FORTNITE_BASE_PATH + (
Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Korean ? string.Empty :
Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Japanese ? string.Empty :
Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Arabic ? string.Empty :
Properties.Settings.Default.AssetsLanguage == (long)ELanguage.TraditionalChinese ? string.Empty :
Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Chinese ? string.Empty :
_BURBANK_SMALL_BOLD);
t = Utils.GetPropertyArraySegmentByte(bottomPath);
if (t != null && t.Length == 3 && t[2].Array != null)
BottomDefaultTypeface = SKTypeface.FromStream(t[2].AsStream());
string descriptionPath = _FORTNITE_BASE_PATH + (
Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Korean ? _NOTO_SANS_KR_REGULAR :
Properties.Settings.Default.AssetsLanguage == (long)ELanguage.Japanese ? _NOTO_SANS_JP_BOLD :

View File

@ -25,7 +25,7 @@ namespace FModel.Creator
{
string path = Strings.FixPath(value);
foreach (var fileReader in Globals.CachedPakFiles.Values)
if (fileReader.TryGetValue(path, out var entry))
if (fileReader.TryGetCaseInsensiteveValue(path, out var entry))
{
// kinda sad to use Globals.CachedPakFileMountPoint when the mount point is already in the path ¯\_(ツ)_/¯
string mount = path.Substring(0, path.Length - entry.Name.Substring(0, entry.Name.LastIndexOf(".")).Length);
@ -38,7 +38,7 @@ namespace FModel.Creator
{
string path = Strings.FixPath(value);
foreach (var fileReader in Globals.CachedPakFiles.Values)
if (fileReader.TryGetValue(path, out var entry))
if (fileReader.TryGetCaseInsensiteveValue(path, out var entry))
{
// kinda sad to use Globals.CachedPakFileMountPoint when the mount point is already in the path ¯\_(ツ)_/¯
string mount = path.Substring(0, path.Length - entry.Name.Substring(0, entry.Name.LastIndexOf(".")).Length);

View File

@ -131,13 +131,13 @@
<ItemGroup>
<PackageReference Include="Autoupdater.NET.Official" Version="1.6.3" />
<PackageReference Include="AvalonEdit" Version="6.1.0-preview1" />
<PackageReference Include="AvalonEdit" Version="6.0.1" />
<PackageReference Include="CSCore" Version="1.2.1.2" />
<PackageReference Include="DiscordRichPresence" Version="1.0.150" />
<PackageReference Include="DotNetZip" Version="1.13.8" />
<PackageReference Include="EpicManifestParser" Version="1.2.0" />
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.0.1" />
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.2.8-beta" />
<PackageReference Include="K4os.Compression.LZ4.Streams" Version="1.2.6" />
<PackageReference Include="LZMA-SDK" Version="19.0.0" />
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />

View File

@ -480,6 +480,20 @@ namespace PakReader.Pak
key = string.Empty;
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetCaseInsensiteveValue(string key, out FPakEntry value)
{
foreach (var r in Entries)
{
if (r.Key.Equals(key, StringComparison.CurrentCultureIgnoreCase))
{
value = r.Value;
return true;
}
}
value = null;
return false;
}
FPakEntry IReadOnlyDictionary<string, FPakEntry>.this[string key] => Entries[key];

View File

@ -5,37 +5,50 @@
*/
public enum EBulkDataFlags : uint
{
/** Empty flag set. */
BULKDATA_None = 0,
/** If set, payload is stored at the end of the file and not inline */
BULKDATA_PayloadAtEndOfFile = 1 << 0,
/** If set, payload should be [un]compressed using ZLIB during serialization. */
BULKDATA_SerializeCompressedZLIB = 1 << 1,
/** Force usage of SerializeElement over bulk serialization. */
BULKDATA_ForceSingleElementSerialization = 1 << 2,
/** Bulk data is only used once at runtime in the game. */
BULKDATA_SingleUse = 1 << 3,
/** Bulk data won't be used and doesn't need to be loaded */
BULKDATA_Unused = 1 << 5,
/** Forces the payload to be saved inline, regardless of its size */
BULKDATA_ForceInlinePayload = 1 << 6,
/** Flag to check if either compression mode is specified */
BULKDATA_SerializeCompressed = (BULKDATA_SerializeCompressedZLIB),
/** Forces the payload to be always streamed, regardless of its size */
BULKDATA_ForceStreamPayload = 1 << 7,
/** If set, payload is stored in a .upack file alongside the uasset */
BULKDATA_PayloadInSeperateFile = 1 << 8,
/** DEPRECATED: If set, payload is compressed using platform specific bit window */
BULKDATA_SerializeCompressedBitWindow = 1 << 9,
/** There is a new default to inline unless you opt out */
BULKDATA_Force_NOT_InlinePayload = 1 << 10,
/** This payload is optional and may not be on device */
BULKDATA_OptionalPayload = 1 << 11,
/** This payload will be memory mapped, this requires alignment, no compression etc. */
BULKDATA_MemoryMappedPayload = 1 << 12,
/** Bulk data size is 64 bits long */
BULKDATA_Size64Bit = 1 << 13,
/** Duplicate non-optional payload in optional bulk data. */
BULKDATA_DuplicateNonOptionalPayload = 1 << 14
}
/** Empty flag set. */
BULKDATA_None = 0,
/** If set, payload is stored at the end of the file and not inline. */
BULKDATA_PayloadAtEndOfFile = 1 << 0,
/** If set, payload should be [un]compressed using ZLIB during serialization. */
BULKDATA_SerializeCompressedZLIB = 1 << 1,
/** Force usage of SerializeElement over bulk serialization. */
BULKDATA_ForceSingleElementSerialization = 1 << 2,
/** Bulk data is only used once at runtime in the game. */
BULKDATA_SingleUse = 1 << 3,
/** Bulk data won't be used and doesn't need to be loaded. */
BULKDATA_Unused = 1 << 5,
/** Forces the payload to be saved inline, regardless of its size. */
BULKDATA_ForceInlinePayload = 1 << 6,
/** Flag to check if either compression mode is specified. */
BULKDATA_SerializeCompressed = (BULKDATA_SerializeCompressedZLIB),
/** Forces the payload to be always streamed, regardless of its size. */
BULKDATA_ForceStreamPayload = 1 << 7,
/** If set, payload is stored in a .upack file alongside the uasset. */
BULKDATA_PayloadInSeperateFile = 1 << 8,
/** DEPRECATED: If set, payload is compressed using platform specific bit window. */
BULKDATA_SerializeCompressedBitWindow = 1 << 9,
/** There is a new default to inline unless you opt out. */
BULKDATA_Force_NOT_InlinePayload = 1 << 10,
/** This payload is optional and may not be on device. */
BULKDATA_OptionalPayload = 1 << 11,
/** This payload will be memory mapped, this requires alignment, no compression etc. */
BULKDATA_MemoryMappedPayload = 1 << 12,
/** Bulk data size is 64 bits long. */
BULKDATA_Size64Bit = 1 << 13,
/** Duplicate non-optional payload in optional bulk data. */
BULKDATA_DuplicateNonOptionalPayload = 1 << 14,
/** Indicates that an old ID is present in the data, at some point when the DDCs are flushed we can remove this. */
BULKDATA_BadDataVersion = 1 << 15,
/** BulkData did not have it's offset changed during the cook and does not need the fix up at load time */
BULKDATA_NoOffsetFixUp = 1 << 16,
/* Runtime only flags below this point! Note that they take the high bits in reverse order! */
/** Assigned at runtime to indicate that the BulkData allocation is a memory mapped region of a file and not raw data. */
BULKDATA_DataIsMemoryMapped = 1 << 30,
/** Assigned at runtime to indicate that the BulkData object has an async loading request in flight and will need to wait on it. */
BULKDATA_HasAsyncReadPending = 1 << 29,
/** Assigned at runtime to indicate that the BulkData object should be considered for discard even if it cannot load from disk. */
BULKDATA_AlwaysAllowDiscard = 1 << 28,
}
}

View File

@ -36,7 +36,10 @@ namespace PakReader.Parsers.Objects
else if ((BulkDataFlags & (uint)EBulkDataFlags.BULKDATA_PayloadInSeperateFile) != 0 &&
ubulk != null && BulkDataOffsetInFile + ubulkOffset >= 0) //.ubulk
{
ubulk.Position = BulkDataOffsetInFile + ubulkOffset;
if ((BulkDataFlags & (uint)EBulkDataFlags.BULKDATA_NoOffsetFixUp) == 0) // UE4.26 flag
{
ubulk.Position = BulkDataOffsetInFile + ubulkOffset;
}
Data = new byte[ElementCount];
ubulk.Read(Data, 0, (int)ElementCount);
}

View File

@ -3,20 +3,20 @@ using System;
namespace PakReader.Parsers.PropertyTagData
{
public sealed class ByteProperty : BaseProperty<byte>
public sealed class ByteProperty : BaseProperty<object>
{
internal ByteProperty(PackageReader reader, FPropertyTag tag, ReadType readType)
{
Position = reader.Position;
Value = readType switch
{
ReadType.NORMAL => tag.EnumName.IsNone ? reader.ReadByte() : (byte)reader.ReadFName().Index,
ReadType.NORMAL => tag.EnumName.IsNone ? reader.ReadByte().ToString() : reader.ReadFName().String,
ReadType.MAP => (byte)reader.ReadUInt32(),
ReadType.ARRAY => reader.ReadByte(),
_ => throw new ArgumentOutOfRangeException(nameof(readType)),
};
}
public byte GetValue() => Value;
public object GetValue() => Value;
}
}

View File

@ -792,6 +792,15 @@ namespace FModel.Properties {
}
}
/// <summary>
/// Recherche une chaîne localisée semblable à Show statistics.
/// </summary>
public static string DrawStats {
get {
return ResourceManager.GetString("DrawStats", resourceCulture);
}
}
/// <summary>
/// Recherche une chaîne localisée semblable à Duration.
/// </summary>

View File

@ -828,4 +828,7 @@ C'est maintenant le logiciel gratuit le plus utilisé pour leak sur Fortnite.</v
<data name="SkipThisVersion" xml:space="preserve">
<value>Ignorer cette version</value>
</data>
<data name="DrawStats" xml:space="preserve">
<value>Afficher les statistiques</value>
</data>
</root>

View File

@ -1082,4 +1082,7 @@ It's now the most used free software to leak on Fortnite.</value>
<data name="SkipThisVersion" xml:space="preserve">
<value>Skip this Version</value>
</data>
<data name="DrawStats" xml:space="preserve">
<value>Show statistics</value>
</data>
</root>

View File

@ -538,5 +538,17 @@ namespace FModel.Properties {
this["LauncherExpiration"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool DrawStats {
get {
return ((bool)(this["DrawStats"]));
}
set {
this["DrawStats"] = value;
}
}
}
}

View File

@ -131,5 +131,8 @@
<Setting Name="LauncherExpiration" Type="System.Int64" Scope="User">
<Value Profile="(Default)">0</Value>
</Setting>
<Setting Name="DrawStats" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -78,6 +78,7 @@
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<CheckBox x:Name="UseGameColor_CkBox" Grid.Row="0" Margin="5"
@ -86,6 +87,9 @@
<CheckBox Grid.Row="1" Margin="5"
Content="{x:Static properties:Resources.UseItemShopIcon}"
IsChecked="{Binding Source={x:Static properties:Settings.Default}, Path=UseItemShopIcon, Mode=TwoWay}"/>
<CheckBox Grid.Row="2" Margin="5"
Content="{x:Static properties:Resources.DrawStats}"
IsChecked="{Binding Source={x:Static properties:Settings.Default}, Path=DrawStats, Mode=TwoWay}"/>
</Grid>
</Grid>