Skip to content

Commit

Permalink
[3D] Added lazy MPQ loading and an error messagebox when mpq files ar…
Browse files Browse the repository at this point in the history
…e corrupted
  • Loading branch information
BAndysc committed Nov 19, 2021
1 parent 55d5dcd commit 3b167d1
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Rendering/TheEngine/IGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ namespace TheEngine
{
public interface IGame
{
public void Initialize(Engine engine);
public bool Initialize(Engine engine);
public void Update(float diff);
public void Render(float delta);
public event Action RequestDispose;
Expand Down
1 change: 1 addition & 0 deletions Rendering/TheEngine/Managers/MeshManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public IMesh CreateManagedOnlyMesh(Vector3[] vertices, int[] indices)
var mesh = new Mesh(engine, handle, true);
mesh.SetVertices(vertices);
mesh.SetIndices(indices, 0);
mesh.BuildBoundingBox();

meshes.Add(mesh);
#if TRACK_ALLOCATIONS
Expand Down
19 changes: 16 additions & 3 deletions Rendering/TheEngine/TheEnginePanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,9 @@ protected override void OnOpenGlDeinit(GlInterface gl, int fb)

protected override void OnOpenGlRender(GlInterface gl, int fb)
{
if (engine == null || delayedDispose)
return;

engine.statsManager.PixelSize = new Vector2(PixelSize.Item1, PixelSize.Item2);
engine.statsManager.Counters.PresentTime.Add(PresentTime);
renderStopwatch.Restart();
Expand Down Expand Up @@ -194,12 +197,14 @@ protected override void OnOpenGlRender(GlInterface gl, int fb)
private bool gameInitialized;
public static readonly DirectProperty<TheEnginePanel, IGame?> GameProperty = AvaloniaProperty.RegisterDirect<TheEnginePanel, IGame?>(nameof(Game), o => o.Game, (o, v) => o.Game = v);

private System.IDisposable? globalKeyDownDisposable;
private System.IDisposable? globalKeyUpDisposable;
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
sw.Restart();
((IControl)e.Root).AddDisposableHandler(KeyDownEvent, GlobalKeyDown, RoutingStrategies.Tunnel);
((IControl)e.Root).AddDisposableHandler(KeyUpEvent, GlobalKeyUp, RoutingStrategies.Tunnel);
globalKeyDownDisposable = ((IControl)e.Root).AddDisposableHandler(KeyDownEvent, GlobalKeyDown, RoutingStrategies.Tunnel);
globalKeyUpDisposable = ((IControl)e.Root).AddDisposableHandler(KeyUpEvent, GlobalKeyUp, RoutingStrategies.Tunnel);
}

private bool IsModifierKey(Key key) => key is Key.LeftShift or Key.LeftCtrl or Key.LeftAlt or Key.LWin;
Expand All @@ -221,6 +226,10 @@ protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e
//if (delayedDispose)
// base.OnDetachedFromVisualTree(e);
//delayedDispose = false;
globalKeyUpDisposable?.Dispose();
globalKeyDownDisposable?.Dispose();
globalKeyUpDisposable = null;
globalKeyDownDisposable = null;
sw.Stop();
}

Expand All @@ -230,7 +239,11 @@ protected virtual void Update(float delta)
{
gameInitialized = true;
game.RequestDispose += GameOnRequestDispose;
game.Initialize(engine!);
if (!game.Initialize(engine!))
{
GameOnRequestDispose();
game = null;
}
}
game?.Update(delta);
}
Expand Down
4 changes: 4 additions & 0 deletions Rendering/TheMaths/Vector3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1922,5 +1922,9 @@ public override bool Equals(object value)
// {
// return *(Vector3*)&value;
// }
public Vector3 WithY(float y)
{
return new Vector3(X, y, Z);
}
}
}
15 changes: 14 additions & 1 deletion WDE.MPQ/Services/MpqService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,20 @@ public IMpqArchive Open()
if (settings.Path == null)
return new EmptyMpqArchive();
var files = Directory.EnumerateFiles(Path.Join(settings.Path, "Data"), "*.mpq", SearchOption.AllDirectories).ToList();
return new MpqArchiveSet(files.Select(MpqArchive.Open).ToArray());
List<IMpqArchive> archives = new();
foreach (var file in files)
{
try
{
var archive = MpqArchive.Open(file);
archives.Add(archive);
}
catch (Exception e)
{
throw new Exception("Couldn't open MPQ file " + Path.GetFileName(file) + ": " + e.Message, e);
}
}
return new MpqArchiveSet(archives.ToArray());
}

private class EmptyMpqArchive : IMpqArchive
Expand Down
57 changes: 49 additions & 8 deletions WDE.MapRenderer/GameManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,68 @@
using TheEngine.PhysicsSystem;
using WDE.Common.DBC;
using WDE.Common.MPQ;
using WDE.Common.Services.MessageBox;
using WDE.MapRenderer.Managers;
using WDE.Module.Attributes;
using WDE.MpqReader;
using WDE.MpqReader.Structures;

namespace WDE.MapRenderer
{
[AutoRegister]
public class GameManager : IGame, IGameContext
{
private IMpqArchive mpq;
private readonly IMpqService mpqService;
private readonly IGameView gameView;
private readonly IMessageBoxService messageBoxService;
private readonly IDatabaseClientFileOpener databaseClientFileOpener;
private AsyncMonitor monitor = new AsyncMonitor();
private Engine engine;
public event Action? OnInitialized;
public event Action? OnFailedInitialize;

public GameManager(IMpqArchive mpq, IGameView gameView, IDatabaseClientFileOpener databaseClientFileOpener)
public GameManager(IMpqService mpqService,
IGameView gameView,
IMessageBoxService messageBoxService,
IDatabaseClientFileOpener databaseClientFileOpener)
{
this.mpq = mpq;
this.mpqService = mpqService;
this.gameView = gameView;
this.messageBoxService = messageBoxService;
this.databaseClientFileOpener = databaseClientFileOpener;
UpdateLoop = new UpdateManager(this);
}

public void Initialize(Engine engine)
private bool TryOpenMpq(out IMpqArchive m)
{
try
{
m = mpqService.Open();
return true;
}
catch (Exception e)
{
messageBoxService.ShowDialog(new MessageBoxFactory<bool>()
.SetTitle("Invalid MPQ")
.SetMainInstruction("Couldn't parse game MPQ.")
.SetContent(e.Message + "\n\nAre you using modified game files?")
.WithButton("Ok", false)
.Build());
m = null;
return false;
}
}

public bool Initialize(Engine engine)
{
this.engine = engine;
if (!TryOpenMpq(out mpq))
{
OnFailedInitialize?.Invoke();
waitForInitialized.SetResult(false);
waitForInitialized = new();
return false;
}
coroutineManager = new();
TimeManager = new TimeManager(this);
ScreenSpaceSelector = new ScreenSpaceSelector(this);
Expand All @@ -51,16 +87,17 @@ public void Initialize(Engine engine)

OnInitialized?.Invoke();
IsInitialized = true;
waitForInitialized.SetResult();
waitForInitialized.SetResult(true);
return true;
}

public void StartCoroutine(IEnumerator coroutine)
{
coroutineManager.Start(coroutine);
}

private TaskCompletionSource waitForInitialized = new();
public Task WaitForInitialized => waitForInitialized.Task;
private TaskCompletionSource<bool> waitForInitialized = new();
public Task<bool> WaitForInitialized => waitForInitialized.Task;

private Material? prevMaterial;
public void Update(float delta)
Expand Down Expand Up @@ -108,7 +145,8 @@ public void SetMap(int mapId)

public void DoDispose()
{
RequestDispose?.Invoke();
if (IsInitialized)
RequestDispose?.Invoke();
Debug.Assert(!IsInitialized);
}

Expand All @@ -125,6 +163,8 @@ public void DisposeGame()
MdxManager.Dispose();
TextureManager.Dispose();
MeshManager.Dispose();
mpq.Dispose();
mpq = null!;
coroutineManager = null!;
TimeManager = null!;
ScreenSpaceSelector = null!;
Expand All @@ -143,6 +183,7 @@ public void DisposeGame()

public Engine Engine => engine;

private IMpqArchive mpq;
private CoroutineManager coroutineManager;
public TimeManager TimeManager { get; private set; }
public ScreenSpaceSelector ScreenSpaceSelector { get; private set; }
Expand Down
8 changes: 0 additions & 8 deletions WDE.MapRenderer/GameView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,4 @@ public async Task<IGameContext> Open()
return tool.Game;
}
}

public class GemView : OpenGlControlBase
{
protected override void OnOpenGlRender(GlInterface gl, int fb)
{

}
}
}
7 changes: 6 additions & 1 deletion WDE.MapRenderer/GameViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,18 @@ public GameViewModel(IMpqService mpqService,
IMessageBoxService messageBoxService,
IDatabaseClientFileOpener databaseClientFileOpener,
IGameView gameView,
GameManager gameManager,
GameViewSettings settings)
{
this.mpqService = mpqService;
this.messageBoxService = messageBoxService;
this.settings = settings;
MapData = mapData;
Game = new GameManager(mpqService.Open(), gameView, databaseClientFileOpener);
Game = gameManager;
Game.OnFailedInitialize += () =>
{
Dispatcher.UIThread.Post(() => Visibility = false, DispatcherPriority.Background);
};
Game.OnInitialized += () =>
{
Game.LightingManager.OverrideLighting = settings.OverrideLighting;
Expand Down
2 changes: 1 addition & 1 deletion WDE.MapRenderer/Managers/IGameContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ public interface IGameContext
Map CurrentMap { get; }
void SetMap(int id);
void StartCoroutine(IEnumerator coroutine);
Task WaitForInitialized { get; }
Task<bool> WaitForInitialized { get; }
}
}
12 changes: 8 additions & 4 deletions WDE.MapRenderer/Managers/MdxManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,18 @@ public IEnumerator LoadM2Mesh(string path, TaskCompletionSource<MdxInstance?> re
material.SetTexture("texture2", th2 ?? gameContext.TextureManager.EmptyTexture);

var trans = 1.0f;
if (batch.colorIndex != -1)
if (batch.colorIndex != -1 && m2.colors.Length < batch.colorIndex)
{
trans = m2.colors[batch.colorIndex].alpha.values[0][0].Value;
if (m2.colors[batch.colorIndex].alpha.values.Length == 0 || m2.colors[batch.colorIndex].alpha.values[0].Length == 0)
trans = 1;
else
trans = m2.colors[batch.colorIndex].alpha.values[0][0].Value;
}

if (batch.transparencyIndex != -1)
if (batch.transparencyIndex != -1 && m2.texture_weights.Length < batch.transparencyIndex)
{
trans *= m2.texture_weights[batch.transparencyIndex].weight.values[0][0].Value;
if (m2.texture_weights[batch.transparencyIndex].weight.values.Length > 0 && m2.texture_weights[batch.transparencyIndex].weight.values[0].Length > 0)
trans *= m2.texture_weights[batch.transparencyIndex].weight.values[0][0].Value;
}

Vector4 mesh_color = new Vector4(1.0f, 1.0f, 1.0f, trans);
Expand Down
14 changes: 7 additions & 7 deletions WDE.MapRenderer/Utils/Gizmo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@ public HitType HitTest(IGameContext context, out Vector3 intersectionPoint)

public void Render(IGameContext context)
{
InternalRender(context, 0.5f);
InternalRender(context, 1);
InternalRender(context, true);
InternalRender(context, false);
}

private void InternalRender(IGameContext context, float alpha)
private void InternalRender(IGameContext context, bool transparent)
{
if (alpha < 1)
if (transparent)
{
material.BlendingEnabled = true;
material.SourceBlending = Blending.SrcAlpha;
Expand All @@ -105,22 +105,22 @@ private void InternalRender(IGameContext context, float alpha)
t.Scale = Vector3.One * (float)Math.Sqrt(Math.Clamp(dist, 0.5f, 500) / 15);
// +X (wow)
t.Rotation = ArrowX;
material.SetUniform("objectColor", new Vector4(0, 0, 1, alpha));
material.SetUniform("objectColor", new Vector4(0, 0, 1, transparent ? 0.5f : 1f));
context.Engine.RenderManager.Render(arrowMesh, material, 0, t);
t.Rotation = PlaneX;
context.Engine.RenderManager.Render(dragPlaneMesh, material, 0, t);


// +Y (wow)
t.Rotation = ArrowY;
material.SetUniform("objectColor", new Vector4(0, 1, 0, alpha));
material.SetUniform("objectColor", new Vector4(0, 1, 0, transparent ? 0.5f : 1f));
context.Engine.RenderManager.Render(arrowMesh, material, 0, t);
t.Rotation = PlaneY;
context.Engine.RenderManager.Render(dragPlaneMesh, material, 0, t);

// +Z (wow)
t.Rotation = ArrowZ;
material.SetUniform("objectColor", new Vector4(1, 0, 0, alpha));
material.SetUniform("objectColor", new Vector4(1, 0, 0, transparent ? 0.5f : 1f));
context.Engine.RenderManager.Render(arrowMesh, material, 0, t);
t.Rotation = PlaneZ;
context.Engine.RenderManager.Render(dragPlaneMesh, material, 0, t);
Expand Down
2 changes: 2 additions & 0 deletions WDE.MpqReader/Structures/Light.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ public T GetAtTime(Time time)
{
if (Count == 1)
return Values[0];
if (Count == 0)
return default;

int higherThan = -1;
int lowerThan = -1;
Expand Down
6 changes: 4 additions & 2 deletions WDE.WorldMap/WoWMapRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,10 @@ private void LoadIfNeeded()
++i;
}

TopLeftVirtual = new Point(minX, minY);
BottomRightVirtual = new Point(maxX, maxY);
(minX, minY) = CoordsUtils.WorldToEditor(CoordsUtils.MinCoord, CoordsUtils.MinCoord);
(maxX, maxY) = CoordsUtils.WorldToEditor(CoordsUtils.MaxCoord, CoordsUtils.MaxCoord);
TopLeftVirtual = new Point(Math.Min(minX, maxX), Math.Min(minY, maxY));
BottomRightVirtual = new Point(Math.Max(minX, maxX), Math.Max(minY, maxY));
}
}
}
11 changes: 11 additions & 0 deletions WoWDatabaseEditor.Common/WDE.Common/Utils/ListExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,5 +63,16 @@ public static int IndexIf<T>(this IList<T> list, Func<T, bool> pred)

return default;
}

public static int IndexOf<T>(this IReadOnlyList<T> list, T item)
{
for (int i = 0; i < list.Count; ++i)
{
if (EqualityComparer<T>.Default.Equals(list[i], item))
return i;
}

return -1;
}
}
}

0 comments on commit 3b167d1

Please sign in to comment.