mirror of
https://github.com/4sval/FModel.git
synced 2026-03-22 01:34:37 -05:00
1014 lines
48 KiB
C#
1014 lines
48 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Media.Imaging;
|
|
using CUE4Parse.UE4.Assets.Exports;
|
|
using CUE4Parse.UE4.Assets.Exports.Engine;
|
|
using CUE4Parse.UE4.Assets.Exports.Material;
|
|
using CUE4Parse.UE4.Assets.Exports.Texture;
|
|
using CUE4Parse.UE4.Assets.Objects;
|
|
using CUE4Parse.UE4.Objects.Core.i18N;
|
|
using CUE4Parse.UE4.Objects.Core.Math;
|
|
using CUE4Parse.UE4.Objects.UObject;
|
|
using FModel.Creator;
|
|
using FModel.Extensions;
|
|
using FModel.Framework;
|
|
using FModel.Services;
|
|
using SkiaSharp;
|
|
using SkiaSharp.HarfBuzz;
|
|
|
|
namespace FModel.ViewModels
|
|
{
|
|
public class MapLayer
|
|
{
|
|
public SKBitmap Layer;
|
|
public bool IsEnabled;
|
|
}
|
|
|
|
public enum EWaypointType
|
|
{
|
|
Parkour,
|
|
TimeTrials
|
|
}
|
|
|
|
public class MapViewerViewModel : ViewModel
|
|
{
|
|
private ThreadWorkerViewModel _threadWorkerView => ApplicationService.ThreadWorkerView;
|
|
private DiscordHandler _discordHandler => DiscordService.DiscordHandler;
|
|
|
|
#region BINDINGS
|
|
|
|
private bool _brPois;
|
|
public bool BrPois
|
|
{
|
|
get => _brPois;
|
|
set => SetProperty(ref _brPois, value, "ApolloGameplay_MapPois");
|
|
}
|
|
|
|
private bool _brLandmarks;
|
|
public bool BrLandmarks
|
|
{
|
|
get => _brLandmarks;
|
|
set => SetProperty(ref _brLandmarks, value, "ApolloGameplay_MapLandmarks");
|
|
}
|
|
|
|
private bool _brTagsLocation;
|
|
public bool BrTagsLocation
|
|
{
|
|
get => _brTagsLocation;
|
|
set => SetProperty(ref _brTagsLocation, value, "ApolloGameplay_TagsLocation");
|
|
}
|
|
|
|
private bool _brPatrolsPath;
|
|
public bool BrPatrolsPath
|
|
{
|
|
get => _brPatrolsPath;
|
|
set => SetProperty(ref _brPatrolsPath, value, "ApolloGameplay_PatrolsPath");
|
|
}
|
|
|
|
private bool _brUpgradeBenches;
|
|
public bool BrUpgradeBenches
|
|
{
|
|
get => _brUpgradeBenches;
|
|
set => SetProperty(ref _brUpgradeBenches, value, "ApolloGameplay_UpgradeBenches");
|
|
}
|
|
|
|
private bool _brPhonebooths;
|
|
public bool BrPhonebooths
|
|
{
|
|
get => _brPhonebooths;
|
|
set => SetProperty(ref _brPhonebooths, value, "ApolloGameplay_Phonebooths");
|
|
}
|
|
|
|
private bool _brVendingMachines;
|
|
public bool BrVendingMachines
|
|
{
|
|
get => _brVendingMachines;
|
|
set => SetProperty(ref _brVendingMachines, value, "ApolloGameplay_VendingMachines");
|
|
}
|
|
|
|
private bool _brFireflies;
|
|
public bool BrFireflies
|
|
{
|
|
get => _brFireflies;
|
|
set => SetProperty(ref _brFireflies, value, "ApolloGameplay_Fireflies");
|
|
}
|
|
|
|
private bool _brCorruptionZones;
|
|
public bool BrCorruptionZones
|
|
{
|
|
get => _brCorruptionZones;
|
|
set => SetProperty(ref _brCorruptionZones, value, "ApolloGameplay_CorruptionZones");
|
|
}
|
|
|
|
private bool _brCubeMovements;
|
|
public bool BrCubeMovements
|
|
{
|
|
get => _brCubeMovements;
|
|
set => SetProperty(ref _brCubeMovements, value, "ApolloGameplay_CubeMovements");
|
|
}
|
|
|
|
private bool _prLandmarks;
|
|
public bool PrLandmarks
|
|
{
|
|
get => _prLandmarks;
|
|
set => SetProperty(ref _prLandmarks, value, "PapayaGameplay_MapLandmarks");
|
|
}
|
|
|
|
private bool _prCannonball;
|
|
public bool PrCannonball
|
|
{
|
|
get => _prCannonball;
|
|
set => SetProperty(ref _prCannonball, value, "PapayaGameplay_CannonballGame");
|
|
}
|
|
|
|
private bool _prSkydive;
|
|
public bool PrSkydive
|
|
{
|
|
get => _prSkydive;
|
|
set => SetProperty(ref _prSkydive, value, "PapayaGameplay_SkydiveGame");
|
|
}
|
|
|
|
private bool _prShootingTargets;
|
|
public bool PrShootingTargets
|
|
{
|
|
get => _prShootingTargets;
|
|
set => SetProperty(ref _prShootingTargets, value, "PapayaGameplay_ShootingTargets");
|
|
}
|
|
|
|
private bool _prParkour;
|
|
public bool PrParkour
|
|
{
|
|
get => _prParkour;
|
|
set => SetProperty(ref _prParkour, value, "PapayaGameplay_ParkourGame");
|
|
}
|
|
|
|
private bool _prTimeTrials;
|
|
public bool PrTimeTrials
|
|
{
|
|
get => _prTimeTrials;
|
|
set => SetProperty(ref _prTimeTrials, value, "PapayaGameplay_TimeTrials");
|
|
}
|
|
|
|
private bool _prVendingMachines;
|
|
public bool PrVendingMachines
|
|
{
|
|
get => _prVendingMachines;
|
|
set => SetProperty(ref _prVendingMachines, value, "PapayaGameplay_VendingMachines");
|
|
}
|
|
|
|
private bool _prMusicBlocks;
|
|
public bool PrMusicBlocks
|
|
{
|
|
get => _prMusicBlocks;
|
|
set => SetProperty(ref _prMusicBlocks, value, "PapayaGameplay_MusicBlocks");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region BITMAP IMAGES
|
|
|
|
private BitmapImage _brMiniMapImage;
|
|
private BitmapImage _prMiniMapImage;
|
|
private BitmapImage _mapImage;
|
|
public BitmapImage MapImage
|
|
{
|
|
get => _mapImage;
|
|
set => SetProperty(ref _mapImage, value);
|
|
}
|
|
|
|
private BitmapImage _brLayerImage;
|
|
private BitmapImage _prLayerImage;
|
|
private BitmapImage _layerImage;
|
|
public BitmapImage LayerImage
|
|
{
|
|
get => _layerImage;
|
|
set => SetProperty(ref _layerImage, value);
|
|
}
|
|
|
|
private const int _widthHeight = 2048;
|
|
private const int _brRadius = 135000;
|
|
private const int _prRadius = 51000;
|
|
private int _mapIndex;
|
|
public int MapIndex // 0 is BR, 1 is PR
|
|
{
|
|
get => _mapIndex;
|
|
set
|
|
{
|
|
SetProperty(ref _mapIndex, value);
|
|
TriggerChange();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
private const string _FIRST_BITMAP = "MapCheck";
|
|
private readonly Dictionary<string, MapLayer>[] _bitmaps; // first bitmap is the displayed map, others are overlays of the map
|
|
private readonly CUE4ParseViewModel _cue4Parse;
|
|
|
|
public MapViewerViewModel(CUE4ParseViewModel cue4Parse)
|
|
{
|
|
_bitmaps = new[]
|
|
{
|
|
new Dictionary<string, MapLayer>(),
|
|
new Dictionary<string, MapLayer>()
|
|
};
|
|
_cue4Parse = cue4Parse;
|
|
}
|
|
|
|
public async void Initialize()
|
|
{
|
|
Utils.Typefaces ??= new Typefaces(_cue4Parse);
|
|
_textPaint.Typeface = _fillPaint.Typeface = Utils.Typefaces.Bottom ?? Utils.Typefaces.DisplayName;
|
|
await LoadBrMiniMap();
|
|
await LoadPrMiniMap();
|
|
TriggerChange();
|
|
}
|
|
|
|
public BitmapImage GetImageToSave() => GetImageSource(GetLayerBitmap(true));
|
|
private SKBitmap GetLayerBitmap(bool withMap)
|
|
{
|
|
var ret = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(ret);
|
|
|
|
foreach (var (key, value) in _bitmaps[MapIndex])
|
|
{
|
|
if (!value.IsEnabled || !withMap && key == _FIRST_BITMAP)
|
|
continue;
|
|
|
|
SKPaint p = null;
|
|
if (key == "ApolloGameplay_CorruptionZones")
|
|
p = new SKPaint { BlendMode = SKBlendMode.Color };
|
|
|
|
c.DrawBitmap(value.Layer, new SKRect(0, 0, _widthHeight, _widthHeight), p);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
protected override bool SetProperty<T>(ref T storage, T value, string propertyName = null) // don't delete, else nothing will update for some reason
|
|
{
|
|
var ret = base.SetProperty(ref storage, value, propertyName);
|
|
if (bool.TryParse(value.ToString(), out var b)) GenericToggle(propertyName, b);
|
|
return ret;
|
|
}
|
|
|
|
private async void GenericToggle(string key, bool enabled)
|
|
{
|
|
if (_bitmaps[MapIndex].TryGetValue(key, out var layer) && layer.Layer != null)
|
|
{
|
|
layer.IsEnabled = enabled;
|
|
}
|
|
else if (enabled) // load layer
|
|
{
|
|
switch (key)
|
|
{
|
|
case "ApolloGameplay_MapPois":
|
|
case "ApolloGameplay_MapLandmarks":
|
|
case "PapayaGameplay_MapLandmarks":
|
|
await LoadQuestIndicatorData();
|
|
break;
|
|
case "ApolloGameplay_TagsLocation":
|
|
await LoadTagsLocation();
|
|
break;
|
|
case "ApolloGameplay_PatrolsPath":
|
|
await LoadPatrolsPath();
|
|
break;
|
|
case "ApolloGameplay_UpgradeBenches":
|
|
await LoadUpgradeBenches();
|
|
break;
|
|
case "ApolloGameplay_Phonebooths":
|
|
await LoadPhonebooths();
|
|
break;
|
|
case "ApolloGameplay_VendingMachines":
|
|
await LoadBrVendingMachines();
|
|
break;
|
|
case "ApolloGameplay_Fireflies":
|
|
await LoadFireflies();
|
|
break;
|
|
case "ApolloGameplay_CorruptionZones":
|
|
await LoadCorruptionZones();
|
|
break;
|
|
case "ApolloGameplay_CubeMovements":
|
|
await LoadCubeMovements();
|
|
break;
|
|
case "PapayaGameplay_CannonballGame":
|
|
await LoadCannonballGame();
|
|
break;
|
|
case "PapayaGameplay_SkydiveGame":
|
|
await LoadSkydiveGame();
|
|
break;
|
|
case "PapayaGameplay_ShootingTargets":
|
|
await LoadShootingTargets();
|
|
break;
|
|
case "PapayaGameplay_ParkourGame":
|
|
await LoadWaypoint(EWaypointType.Parkour);
|
|
break;
|
|
case "PapayaGameplay_TimeTrials":
|
|
await LoadWaypoint(EWaypointType.TimeTrials);
|
|
break;
|
|
case "PapayaGameplay_VendingMachines":
|
|
await LoadPrVendingMachines();
|
|
break;
|
|
case "PapayaGameplay_MusicBlocks":
|
|
await LoadMusicBlocks();
|
|
break;
|
|
}
|
|
_bitmaps[MapIndex][key].IsEnabled = true;
|
|
}
|
|
|
|
switch (MapIndex)
|
|
{
|
|
case 0:
|
|
_brLayerImage = GetImageSource(GetLayerBitmap(false));
|
|
break;
|
|
case 1:
|
|
_prLayerImage = GetImageSource(GetLayerBitmap(false));
|
|
break;
|
|
}
|
|
TriggerChange();
|
|
}
|
|
|
|
private BitmapImage GetImageSource(SKBitmap bitmap)
|
|
{
|
|
if (bitmap == null) return null;
|
|
using var stream = SKImage.FromBitmap(bitmap).Encode().AsStream();
|
|
var image = new BitmapImage();
|
|
image.BeginInit();
|
|
image.CacheOption = BitmapCacheOption.OnLoad;
|
|
image.StreamSource = stream;
|
|
image.EndInit();
|
|
image.Freeze();
|
|
return image;
|
|
}
|
|
|
|
private void TriggerChange()
|
|
{
|
|
var layerCount = _bitmaps[_mapIndex].Count(x => x.Value.IsEnabled);
|
|
var layerString = $"{layerCount} Layer{(layerCount > 1 ? "s" : "")}";
|
|
switch (_mapIndex)
|
|
{
|
|
case 0:
|
|
_discordHandler.UpdateButDontSavePresence(null, $"Map Viewer: Battle Royale ({layerString})");
|
|
_mapImage = _brMiniMapImage;
|
|
_layerImage = _brLayerImage;
|
|
break;
|
|
case 1:
|
|
_discordHandler.UpdateButDontSavePresence(null, $"Map Viewer: Party Royale ({layerString})");
|
|
_mapImage = _prMiniMapImage;
|
|
_layerImage = _prLayerImage;
|
|
break;
|
|
}
|
|
|
|
RaisePropertyChanged(nameof(MapImage));
|
|
RaisePropertyChanged(nameof(LayerImage));
|
|
}
|
|
|
|
private readonly SKPaint _textPaint = new()
|
|
{
|
|
IsAntialias = true, FilterQuality = SKFilterQuality.High,
|
|
Color = SKColors.White, TextAlign = SKTextAlign.Center, TextSize = 26
|
|
};
|
|
private readonly SKPaint _fillPaint = new()
|
|
{
|
|
IsAntialias = true, FilterQuality = SKFilterQuality.High,
|
|
IsStroke = true, Color = SKColors.Black, TextSize = 26,
|
|
TextAlign = SKTextAlign.Center
|
|
};
|
|
private readonly SKPaint _pathPaint = new()
|
|
{
|
|
IsAntialias = true, FilterQuality = SKFilterQuality.High, IsStroke = true,
|
|
Style = SKPaintStyle.Stroke, StrokeWidth = 5, Color = SKColors.Red,
|
|
ImageFilter = SKImageFilter.CreateDropShadow(4, 4, 8, 8, SKColors.Black)
|
|
};
|
|
|
|
private FVector2D GetMapPosition(FVector vector, int mapRadius)
|
|
{
|
|
var nx = (vector.Y + mapRadius) / (mapRadius * 2) * _widthHeight;
|
|
var ny = (1 - (vector.X + mapRadius) / (mapRadius * 2)) * _widthHeight;
|
|
return new FVector2D(nx, ny);
|
|
}
|
|
|
|
private async Task LoadBrMiniMap()
|
|
{
|
|
if (_bitmaps[0].TryGetValue(_FIRST_BITMAP, out var brMap) && brMap.Layer != null)
|
|
return; // if map already loaded
|
|
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
if (!Utils.TryLoadObject("FortniteGame/Content/UI/IngameMap/UIMapManagerBR.Default__UIMapManagerBR_C", out UObject mapManager) ||
|
|
!mapManager.TryGetValue(out UObject mapMaterial, "MapMaterial") ||
|
|
!mapMaterial.TryGetValue(out FStructFallback cachedExpressionData, "CachedExpressionData") ||
|
|
!cachedExpressionData.TryGetValue(out FStructFallback parameters, "Parameters") ||
|
|
!parameters.TryGetValue(out UTexture2D[] textureValues, "TextureValues")) return;
|
|
|
|
_bitmaps[0][_FIRST_BITMAP] = new MapLayer{Layer = Utils.GetBitmap(textureValues[0]), IsEnabled = true};
|
|
_brMiniMapImage = GetImageSource(_bitmaps[0][_FIRST_BITMAP].Layer);
|
|
});
|
|
}
|
|
|
|
private async Task LoadPrMiniMap()
|
|
{
|
|
if (_bitmaps[1].TryGetValue(_FIRST_BITMAP, out var prMap) && prMap.Layer != null)
|
|
return; // if map already loaded
|
|
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
if (!Utils.TryLoadObject("FortniteGame/Content/UI/IngameMap/UIMapManagerPapaya.Default__UIMapManagerPapaya_C", out UObject mapManager) ||
|
|
!mapManager.TryGetValue(out UMaterial mapMaterial, "MapMaterial") ||
|
|
mapMaterial.ReferencedTextures.Count < 1) return;
|
|
|
|
_bitmaps[1][_FIRST_BITMAP] = new MapLayer{Layer = Utils.GetBitmap(mapMaterial.ReferencedTextures[0] as UTexture2D), IsEnabled = true};
|
|
_prMiniMapImage = GetImageSource(_bitmaps[1][_FIRST_BITMAP].Layer);
|
|
});
|
|
}
|
|
|
|
private async Task LoadQuestIndicatorData()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
var poisBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
var brLandmarksBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
var prLandmarksBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var pois = new SKCanvas(poisBitmap);
|
|
using var brLandmarks = new SKCanvas(brLandmarksBitmap);
|
|
using var prLandmarks = new SKCanvas(prLandmarksBitmap);
|
|
|
|
if (Utils.TryLoadObject("FortniteGame/Content/Quests/QuestIndicatorData", out UObject indicatorData) &&
|
|
indicatorData.TryGetValue(out FStructFallback[] challengeMapPoiData, "ChallengeMapPoiData"))
|
|
{
|
|
foreach (var poiData in challengeMapPoiData)
|
|
{
|
|
if (!poiData.TryGetValue(out FSoftObjectPath discoveryQuest, "DiscoveryQuest") ||
|
|
!poiData.TryGetValue(out FText text, "Text") || string.IsNullOrEmpty(text.Text) ||
|
|
!poiData.TryGetValue(out FVector worldLocation, "WorldLocation") ||
|
|
!poiData.TryGetValue(out FName discoverBackend, "DiscoverObjectiveBackendName")) continue;
|
|
|
|
var shaper = new CustomSKShaper(_textPaint.Typeface);
|
|
var shapedText = shaper.Shape(text.Text, _textPaint);
|
|
|
|
if (discoverBackend.Text.Contains("papaya", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var vector = GetMapPosition(worldLocation, _prRadius);
|
|
prLandmarks.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
prLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _fillPaint);
|
|
prLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
else if (discoveryQuest.AssetPathName.Text.Contains("landmarks", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var vector = GetMapPosition(worldLocation, _brRadius);
|
|
brLandmarks.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
brLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _fillPaint);
|
|
brLandmarks.DrawShapedText(shaper, text.Text, vector.X - shapedText.Points[^1].X / 2, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
else
|
|
{
|
|
_fillPaint.StrokeWidth = 10;
|
|
var vector = GetMapPosition(worldLocation, _brRadius);
|
|
pois.DrawShapedText(shaper, text.Text.ToUpperInvariant(), vector.X - shapedText.Points[^1].X / 2, vector.Y, _fillPaint);
|
|
pois.DrawShapedText(shaper, text.Text.ToUpperInvariant(), vector.X - shapedText.Points[^1].X / 2, vector.Y, _textPaint);
|
|
}
|
|
}
|
|
}
|
|
|
|
_bitmaps[0]["ApolloGameplay_MapPois"] = new MapLayer {Layer = poisBitmap, IsEnabled = false};
|
|
_bitmaps[0]["ApolloGameplay_MapLandmarks"] = new MapLayer {Layer = brLandmarksBitmap, IsEnabled = false};
|
|
_bitmaps[1]["PapayaGameplay_MapLandmarks"] = new MapLayer {Layer = prLandmarksBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadPatrolsPath()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var patrolsPathBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(patrolsPathBitmap);
|
|
|
|
var exports = Utils.LoadExports("/NPCLibrary/LevelOverlays/Apollo_Terrain_NPCLibrary_Overlay_S18");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("FortAthenaPatrolPath", StringComparison.OrdinalIgnoreCase) ||
|
|
!export.TryGetValue(out FPackageIndex[] patrolPoints, "PatrolPoints")) continue;
|
|
|
|
if (!Utils.TryGetPackageIndexExport(patrolPoints[0], out UObject uObject) ||
|
|
!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var path = new SKPath();
|
|
var vector = GetMapPosition(relativeLocation, _brRadius);
|
|
var displayName = export.Name["FortAthenaPatrolPath_Tandem_S18_".Length..];
|
|
path.MoveTo(vector.X, vector.Y);
|
|
|
|
for (var i = 1; i < patrolPoints.Length; i++)
|
|
{
|
|
if (!Utils.TryGetPackageIndexExport(patrolPoints[i], out uObject) ||
|
|
!uObject.TryGetValue(out rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out uObject) ||
|
|
!uObject.TryGetValue(out relativeLocation, "RelativeLocation")) continue;
|
|
|
|
vector = GetMapPosition(relativeLocation, _brRadius);
|
|
path.LineTo(vector.X, vector.Y);
|
|
}
|
|
|
|
c.DrawPath(path, _pathPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[0]["ApolloGameplay_PatrolsPath"] = new MapLayer {Layer = patrolsPathBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadCannonballGame()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var cannonballBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(cannonballBitmap);
|
|
|
|
var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_CannonballGame");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("BP_CannonballGame_Target_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("CannonballGame_VehicleSpawner_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var displayName = Utils.GetLocalizedResource("", "D998BEF44F051E0885C6C58565934BEA", "Cannonball");
|
|
var vector = GetMapPosition(relativeLocation, _prRadius);
|
|
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[1]["PapayaGameplay_CannonballGame"] = new MapLayer {Layer = cannonballBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadSkydiveGame()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var skydiveBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(skydiveBitmap);
|
|
|
|
var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_SkydiveGame");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("BP_Waypoint_Papaya_Skydive_Start_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!export.TryGetValue(out FText minigameActivityName, "MinigameActivityName") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var vector = GetMapPosition(relativeLocation, _prRadius);
|
|
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
c.DrawText(minigameActivityName.Text, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(minigameActivityName.Text, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[1]["PapayaGameplay_SkydiveGame"] = new MapLayer {Layer = skydiveBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadShootingTargets()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var shootingTargetsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(shootingTargetsBitmap);
|
|
|
|
var bDone = false;
|
|
var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_ShootingTargets");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("PapayaShootingTarget_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var vector = GetMapPosition(relativeLocation, _prRadius);
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
if (bDone) continue;
|
|
|
|
bDone = true;
|
|
c.DrawText("Shooting Target", vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText("Shooting Target", vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[1]["PapayaGameplay_ShootingTargets"] = new MapLayer {Layer = shootingTargetsBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadWaypoint(EWaypointType type)
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var waypointBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(waypointBitmap);
|
|
|
|
string file;
|
|
string name;
|
|
switch (type)
|
|
{
|
|
case EWaypointType.Parkour:
|
|
file = "PapayaGameplay_ParkourGame";
|
|
name = "Parkour";
|
|
break;
|
|
case EWaypointType.TimeTrials:
|
|
file = "PapayaGameplay_TimeTrials";
|
|
name = "Time Trials";
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
|
}
|
|
|
|
var path = new SKPath();
|
|
var exports = Utils.LoadExports($"/PapayaGameplay/LevelOverlays/{file}");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("BP_Waypoint_Parent_Papaya_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject root) ||
|
|
!root.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var vector = GetMapPosition(relativeLocation, _prRadius);
|
|
if (path.IsEmpty || export.TryGetValue(out bool startsTrial, "StartsTrial") && startsTrial)
|
|
{
|
|
path.MoveTo(vector.X, vector.Y);
|
|
c.DrawText(name, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(name, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
else if (export.TryGetValue(out bool endsTrial, "EndsTrial") && endsTrial)
|
|
{
|
|
path.LineTo(vector.X, vector.Y);
|
|
c.DrawPath(path, _pathPaint);
|
|
path = new SKPath();
|
|
}
|
|
else path.LineTo(vector.X, vector.Y);
|
|
}
|
|
|
|
_bitmaps[1][file] = new MapLayer {Layer = waypointBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadPrVendingMachines()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var set = new HashSet<string>();
|
|
var timeTrialsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(timeTrialsBitmap);
|
|
|
|
var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_VendingMachines");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("B_Papaya_VendingMachine_Boat_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_BoogieBomb_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_Burger_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_CrashPad_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_FishingPole_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_Grappler_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_Jetpack_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_PaintGrenade_Blue_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_PaintGrenade_Red_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_PaintLauncher_Blue_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_PaintLauncher_Red_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_PlungerBow_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_Quad_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Papaya_VendingMachine_Tomato_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject root) ||
|
|
!root.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var name = export.ExportType.SubstringAfter("B_Papaya_VendingMachine_").SubstringBeforeLast("_C");
|
|
var vector = GetMapPosition(relativeLocation, _prRadius);
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
if (!set.Add(name)) continue;
|
|
|
|
c.DrawText(name, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(name, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[1]["PapayaGameplay_VendingMachines"] = new MapLayer {Layer = timeTrialsBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadMusicBlocks()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var shootingTargetsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(shootingTargetsBitmap);
|
|
|
|
var bDone = false;
|
|
var exports = Utils.LoadExports("/PapayaGameplay/LevelOverlays/PapayaGameplay_MusicBlocks");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("MusicBlock_Piano3_Papaya_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var vector = GetMapPosition(relativeLocation, _prRadius);
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
if (bDone) continue;
|
|
|
|
bDone = true;
|
|
c.DrawText("Music Blocks", vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText("Music Blocks", vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[1]["PapayaGameplay_MusicBlocks"] = new MapLayer {Layer = shootingTargetsBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadUpgradeBenches()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var upgradeBenchesBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(upgradeBenchesBitmap);
|
|
|
|
var exports = Utils.LoadExports("/NPCLibrary/LevelOverlays/Apollo_Terrain_NPCLibrary_Stations_UpgradeBenches");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("B_Athena_Spawner_UpgradeStation_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
var displayName = export.Name["B_Athena_Spawner_".Length..];
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var vector = GetMapPosition(relativeLocation, _brRadius);
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[0]["ApolloGameplay_UpgradeBenches"] = new MapLayer {Layer = upgradeBenchesBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadPhonebooths()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var phoneboothsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(phoneboothsBitmap);
|
|
|
|
var exports = Utils.LoadExports("/NPCLibrary/LevelOverlays/Apollo_Terrain_NPCLibrary_Stations_Phonebooths");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("B_Athena_Spawner_Payphone_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
var displayName = export.Name["B_Athena_Spawner_".Length..];
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var vector = GetMapPosition(relativeLocation, _brRadius);
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[0]["ApolloGameplay_Phonebooths"] = new MapLayer {Layer = phoneboothsBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadBrVendingMachines()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var vendingMachinesBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(vendingMachinesBitmap);
|
|
|
|
var exports = Utils.LoadExports("FortniteGame/Content/Athena/Apollo/Maps/Special/ItemCollections/Apollo_Item_VendingMachines");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("B_Athena_Spawner_VendingMachine_MendingOnly_C", StringComparison.OrdinalIgnoreCase) &&
|
|
!export.ExportType.Equals("B_Athena_Spawner_VendingMachine_Random_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
var displayName = $"{(export.ExportType.Contains("Mending") ? "MM" : "WOM")}_{export.Name["B_Athena_Spawner_VendingMachine_Random".Length..]}";
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var vector = GetMapPosition(relativeLocation, _brRadius);
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[0]["ApolloGameplay_VendingMachines"] = new MapLayer {Layer = vendingMachinesBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadFireflies()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var firefliesBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(firefliesBitmap);
|
|
|
|
var exports = Utils.LoadExports("FortniteGame/Content/Athena/Apollo/Maps/Special/ItemCollections/Apollo_Item_Fireflies");
|
|
foreach (var export in exports)
|
|
{
|
|
if (!export.ExportType.Equals("BP_BGACSpawner_Fireflies_C", StringComparison.OrdinalIgnoreCase)) continue;
|
|
var displayName = $"FF_{export.Name["BP_BGACSpawnerFireFlies".Length..]}";
|
|
|
|
if (!export.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out UObject uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
var vector = GetMapPosition(relativeLocation, _brRadius);
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[0]["ApolloGameplay_Fireflies"] = new MapLayer {Layer = firefliesBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadTagsLocation()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
if (!Utils.TryLoadObject("FortniteGame/Content/Quests/QuestTagToLocationDataRows.QuestTagToLocationDataRows", out UDataTable locationData))
|
|
return;
|
|
|
|
var tagsLocationBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(tagsLocationBitmap);
|
|
|
|
foreach (var (key, uObject) in locationData.RowMap)
|
|
{
|
|
if (key.Text.StartsWith("Athena.Location.POI", StringComparison.OrdinalIgnoreCase) ||
|
|
key.Text.StartsWith("Athena.Location.Unnamed", StringComparison.OrdinalIgnoreCase) ||
|
|
key.Text.Contains(".Tandem.", StringComparison.OrdinalIgnoreCase) ||
|
|
!uObject.TryGetValue(out FVector worldLocation, "WorldLocation")) continue;
|
|
|
|
var parts = key.Text.Split('.');
|
|
var displayName = parts[^2];
|
|
if (!int.TryParse(parts[^1], out var _))
|
|
displayName += " " + parts[^1];
|
|
|
|
var vector = GetMapPosition(worldLocation, _brRadius);
|
|
c.DrawPoint(vector.X, vector.Y, _pathPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _fillPaint);
|
|
c.DrawText(displayName, vector.X, vector.Y - 12.5F, _textPaint);
|
|
}
|
|
|
|
_bitmaps[0]["ApolloGameplay_TagsLocation"] = new MapLayer {Layer = tagsLocationBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private async Task LoadCorruptionZones()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
if (!Utils.TryLoadObject("FortniteGame/Content/Athena/Apollo/Environments/Landscape/Materials/Corruption/T_InitialCorruptionAreas.T_InitialCorruptionAreas", out UTexture2D corruption))
|
|
return;
|
|
|
|
var overlay = Utils.GetBitmap(corruption);
|
|
var width = overlay.Width;
|
|
var height = overlay.Height;
|
|
var rotatedBitmap = new SKBitmap(width, height, SKColorType.Rgba8888, SKAlphaType.Opaque);
|
|
|
|
using var c = new SKCanvas(rotatedBitmap);
|
|
c.Clear();
|
|
c.Translate(0, width);
|
|
c.RotateDegrees(-90);
|
|
c.DrawRect(0, 0, width, height, new SKPaint
|
|
{
|
|
IsAntialias = true, FilterQuality = SKFilterQuality.High,
|
|
Shader = SKShader.CreateCompose(SKShader.CreateSweepGradient(new SKPoint(width / 2f, height / 2f),new [] {
|
|
SKColor.Parse("#352176"), SKColor.Parse("#fd78fa"), SKColor.Parse("#f0b843"), SKColor.Parse("#e54a21")
|
|
}, null), SKShader.CreatePerlinNoiseTurbulence(0.05f, 0.05f, 4, 0), SKBlendMode.SrcOver)
|
|
});
|
|
c.DrawBitmap(overlay, 0, 0, new SKPaint { BlendMode = SKBlendMode.Darken });
|
|
rotatedBitmap.ClearToTransparent();
|
|
|
|
_bitmaps[0]["ApolloGameplay_CorruptionZones"] = new MapLayer {Layer = rotatedBitmap.Resize(_widthHeight, _widthHeight), IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// FortniteGame/Plugins/GameFeatures/CorruptionGameplay/Content/CorruptionGameplay_LevelOverlay.uasset
|
|
/// too lazy to filters
|
|
/// </summary>
|
|
private async Task LoadCubeMovements()
|
|
{
|
|
await _threadWorkerView.Begin(_ =>
|
|
{
|
|
_fillPaint.StrokeWidth = 5;
|
|
var cubeMovementsBitmap = new SKBitmap(_widthHeight, _widthHeight, SKColorType.Rgba8888, SKAlphaType.Premul);
|
|
using var c = new SKCanvas(cubeMovementsBitmap);
|
|
|
|
if (!Utils.TryLoadObject("/CorruptionGameplay/Levels/CorruptionGameplay_ApolloTerrain_Overlay.BP_CubeMovementGradient_2", out UObject overlay) ||
|
|
!overlay.TryGetValue(out FSoftObjectPath[] cubeMovementStaticPaths, "cubeMovementStaticPaths") || cubeMovementStaticPaths.Length < 1)
|
|
return;
|
|
|
|
var oldColor = _pathPaint.Color;
|
|
_pathPaint.Color = SKColors.Purple;
|
|
foreach (var cubeMovementStaticPath in cubeMovementStaticPaths)
|
|
{
|
|
var objectPath = cubeMovementStaticPath.AssetPathName.Text.SubstringBeforeLast(".");
|
|
var objectName = cubeMovementStaticPath.SubPathString.SubstringAfterLast(".");
|
|
if (!Utils.TryLoadObject($"{objectPath}.{objectName}", out UObject staticPath))
|
|
return;
|
|
|
|
DrawCubeMovements(c, staticPath, true);
|
|
}
|
|
|
|
if (Utils.TryLoadObject("/CorruptionGameplay/Levels/CubeMovement/Apollo_CM_Gold_Overlay.CM_Spline_Gold", out UObject goldPath))
|
|
{
|
|
_pathPaint.Color = SKColors.Gold;
|
|
DrawCubeMovements(c, goldPath, false);
|
|
}
|
|
|
|
_pathPaint.Color = oldColor;
|
|
_bitmaps[0]["ApolloGameplay_CubeMovements"] = new MapLayer {Layer = cubeMovementsBitmap, IsEnabled = false};
|
|
});
|
|
}
|
|
|
|
private void DrawCubeMovements(SKCanvas c, UObject staticPath, bool fixLocation)
|
|
{
|
|
if (!staticPath.TryGetValue(out FStructFallback[] pathTravelers, "PathTravelers") || pathTravelers.Length < 1 ||
|
|
!pathTravelers[0].TryGetValue(out FPackageIndex[] generatedSplinesArray, "GeneratedSplinesArray") || generatedSplinesArray.Length < 1 ||
|
|
!pathTravelers[0].TryGetValue(out FStructFallback[] stepMetaData, "StepMetaData") || stepMetaData.Length < 1)
|
|
return;
|
|
|
|
UObject uObject;
|
|
var parentRelativeLocation = new FVector();
|
|
if (fixLocation)
|
|
{
|
|
if (!pathTravelers[0].TryGetValue(out FPackageIndex pathTraveler, "PathTraveler") ||
|
|
!Utils.TryGetPackageIndexExport(pathTraveler, out uObject) ||
|
|
!uObject.TryGetValue(out FPackageIndex rootComponent, "RootComponent") ||
|
|
!Utils.TryGetPackageIndexExport(rootComponent, out uObject) ||
|
|
!uObject.TryGetValue(out parentRelativeLocation, "RelativeLocation"))
|
|
return;
|
|
}
|
|
|
|
var bDone = false;
|
|
var path = new SKPath();
|
|
for (var i = 0; i < generatedSplinesArray.Length; i++)
|
|
{
|
|
if (!stepMetaData[i].TryGetValue(out bool bSkipStep, "bSkipStep") || bSkipStep ||
|
|
!Utils.TryGetPackageIndexExport(generatedSplinesArray[i], out uObject) ||
|
|
!uObject.TryGetValue(out FVector relativeLocation, "RelativeLocation")) continue;
|
|
|
|
if (!uObject.TryGetValue(out FStructFallback splineCurves, "SplineCurves") ||
|
|
!splineCurves.TryGetValue(out FStructFallback positions, "Position") ||
|
|
!positions.TryGetValue(out FStructFallback[] positionPoints, "Points")) continue;
|
|
|
|
for (var j = 0; j < positionPoints.Length; j++)
|
|
{
|
|
if (!positionPoints[j].TryGetValue(out FVector position, "OutVal")) continue;
|
|
|
|
var vector = GetMapPosition(parentRelativeLocation + relativeLocation + position, _brRadius);
|
|
if (!bDone)
|
|
{
|
|
path.MoveTo(vector.X, vector.Y);
|
|
bDone = true;
|
|
}
|
|
else
|
|
{
|
|
path.LineTo(vector.X, vector.Y);
|
|
}
|
|
}
|
|
}
|
|
|
|
c.DrawPath(path, _pathPaint);
|
|
}
|
|
}
|
|
}
|