Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic setup switching for the tournament client #9256

Merged
merged 65 commits into from
Oct 19, 2020
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
17cd956
Introduce new storage class and manager
MiraiSubject Jun 7, 2020
9a20ffa
Rename to TournamentStorage
MiraiSubject Jun 7, 2020
ba5a747
Implement migration for TournamentStorage
MiraiSubject Jun 8, 2020
f01a86f
Fix styling issues and move StorageManager to Configuration Folder
MiraiSubject Jun 8, 2020
ce66b72
Refactor paths
MiraiSubject Jun 8, 2020
d2ae146
Remove unnecessary parameters and implement delete
MiraiSubject Jun 8, 2020
2f15d7f
Code styling fixes
MiraiSubject Jun 8, 2020
4179193
change namespace to osu.Game.Tournament.IO
MiraiSubject Jun 9, 2020
c2e01e1
Rename tournamentStorage to storage
MiraiSubject Jun 11, 2020
b69ff30
Fixed migration logic
MiraiSubject Jun 11, 2020
18a9e5a
Add NonVisual tests for custom tournaments
MiraiSubject Jun 11, 2020
a317b85
Remove misleading log
MiraiSubject Jun 11, 2020
5d49b70
Change access modifier public -> internal
MiraiSubject Jun 11, 2020
2964b45
Rename VideoStorage to VideoStore
MiraiSubject Jun 11, 2020
af1bbe7
move TournamentVideoResourceStore to separate file
MiraiSubject Jun 11, 2020
883185d
Add a comment to describe what's going on before the headless game st…
MiraiSubject Jun 11, 2020
603054f
Remove unused property and reuse tournamentBasePath
MiraiSubject Jun 11, 2020
222ac86
Add newlines at the end of the file
MiraiSubject Jun 11, 2020
1d4d749
Undo blank line removal
MiraiSubject Jun 11, 2020
c9dc17f
Introduce migrations for drawings
MiraiSubject Jun 11, 2020
327795b
Switch drawing storage to tournamentstorage
MiraiSubject Jun 11, 2020
32d86d6
Create storage for config files of a tournament
MiraiSubject Jun 11, 2020
592e3bf
Implement migrations for the drawings config file
MiraiSubject Jun 11, 2020
56a40e6
Add drawings to the migration test
MiraiSubject Jun 11, 2020
5ef3a3f
Merge branch 'master' into tourney-asset-refactor
peppy Jun 12, 2020
5041c74
Fix merge issue
peppy Jun 12, 2020
29ae1c4
TournamentStorage now takes in a parent storage
MiraiSubject Jun 16, 2020
b75fd7b
Refactor moving logic (1/2)
MiraiSubject Jun 16, 2020
02d66c4
Refactor moving (2/2)
MiraiSubject Jun 16, 2020
dd96970
Introduce new class MigratableStorage
MiraiSubject Jun 16, 2020
21774b8
Move static properties to parent class and inherit OsuStorage from it
MiraiSubject Jun 22, 2020
f878388
Fix TestMigrationToSeeminglyNestedTarget failing
MiraiSubject Jun 22, 2020
291dadf
Merge branch 'master' of https://github.com/ppy/osu into tourney-asse…
MiraiSubject Jun 22, 2020
eec1e9e
Remove unnecessary comments and added file check for tournament.ini o…
MiraiSubject Jun 22, 2020
08759da
Move drawings.ini out of config subfolder
MiraiSubject Jun 22, 2020
6b14079
InspectCode changes
MiraiSubject Jun 22, 2020
a94dcc4
Add xmldoc to MigratableStorage
MiraiSubject Jun 22, 2020
e0d5a91
make tournament migration private
MiraiSubject Jun 22, 2020
a899c75
Remove whitespace at the end of xmldoc line
MiraiSubject Jun 22, 2020
a47d34f
make ignore properties protected virtual get-only in base
MiraiSubject Jun 23, 2020
8b9cf6f
Remove default value in Storagemgr
MiraiSubject Jun 23, 2020
8e8458a
make migrate public abstract in base and override
MiraiSubject Jun 23, 2020
7a3315d
invert and early return
MiraiSubject Jun 23, 2020
0ca8c96
Remove string interpolation & unnecessary test setup
MiraiSubject Jun 23, 2020
e5851be
change accessor from internal readonly to public get-only
MiraiSubject Jun 23, 2020
9d2392b
Cache TournamentStorage as Storage and only cast when necessary
MiraiSubject Jun 23, 2020
c32ef5e
Address formatting issues
MiraiSubject Jun 23, 2020
af11340
Fix nullref exceptions and redundant explicit type
MiraiSubject Jun 24, 2020
839f197
Change type from TournamentStorage to Storage in tests
MiraiSubject Jun 24, 2020
c94f95c
Check if the file exists before reading
MiraiSubject Jun 24, 2020
063503f
Move null check outside of the loop
MiraiSubject Jun 24, 2020
47a732e
Address review comments
MiraiSubject Jun 24, 2020
d82d901
Reuse custom_tournament where it was still used as a literal
MiraiSubject Jun 25, 2020
9639ebd
Merge branch 'master' into tourney-asset-refactor
MiraiSubject Jun 28, 2020
0cddb85
Move storageconfig set and saving to migrate method
MiraiSubject Jun 28, 2020
c3cd2a7
Move general purpose migration to MigratableStorage
MiraiSubject Jul 1, 2020
66e61aa
Logger now shows the actual path of the destination
MiraiSubject Jul 1, 2020
c167727
Merge branch 'master' into tourney-asset-refactor
MiraiSubject Aug 8, 2020
1989141
Merge branch 'master' into tourney-asset-refactor
peppy Oct 7, 2020
f218a32
Merge branch 'master' into tourney-asset-refactor
peppy Oct 19, 2020
7ed862e
Add comment about migration code
peppy Oct 19, 2020
9c566e7
Update tests to use correct parameters of CleanRunGameHost
peppy Oct 19, 2020
31f6051
Add missing xmldoc
peppy Oct 19, 2020
3f41003
Move video store out of TournamentStorage
peppy Oct 19, 2020
daceb0c
Fix texture store not being initialised correctly
peppy Oct 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions osu.Game.Tests/NonVisual/CustomDataDirectoryTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public void TestMigration()

var osu = LoadOsuIntoHost(host);
var storage = osu.Dependencies.Get<Storage>();
var osuStorage = storage as MigratableStorage;

// Store the current storage's path. We'll need to refer to this for assertions in the original directory after the migration completes.
string originalDirectory = storage.GetFullPath(".");
Expand All @@ -137,13 +138,15 @@ public void TestMigration()
Assert.That(!Directory.Exists(Path.Combine(originalDirectory, "test-nested", "cache")));
Assert.That(storage.ExistsDirectory(Path.Combine("test-nested", "cache")));

foreach (var file in OsuStorage.IGNORE_FILES)
Assert.That(osuStorage, Is.Not.Null);

foreach (var file in osuStorage.IgnoreFiles)
{
Assert.That(File.Exists(Path.Combine(originalDirectory, file)));
Assert.That(storage.Exists(file), Is.False);
}

foreach (var dir in OsuStorage.IGNORE_DIRECTORIES)
foreach (var dir in osuStorage.IgnoreDirectories)
{
Assert.That(Directory.Exists(Path.Combine(originalDirectory, dir)));
Assert.That(storage.ExistsDirectory(dir), Is.False);
Expand Down
171 changes: 171 additions & 0 deletions osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Platform;
using osu.Game.Tournament.Configuration;
using osu.Game.Tests;

namespace osu.Game.Tournament.Tests.NonVisual
{
[TestFixture]
public class CustomTourneyDirectoryTest
{
[Test]
public void TestDefaultDirectory()
{
using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestDefaultDirectory)))
{
try
{
var osu = loadOsu(host);
var storage = osu.Dependencies.Get<Storage>();
var defaultStorage = Path.Combine(tournamentBasePath(nameof(TestDefaultDirectory)), "default");
Assert.That(storage.GetFullPath("."), Is.EqualTo(defaultStorage));
}
finally
{
host.Exit();
}
}
}

[Test]
public void TestCustomDirectory()
{
using (HeadlessGameHost host = new HeadlessGameHost(nameof(TestCustomDirectory)))
{
string osuDesktopStorage = basePath(nameof(TestCustomDirectory));
const string custom_tournament = "custom";

// need access before the game has constructed its own storage yet.
Storage storage = new DesktopStorage(osuDesktopStorage, host);
// manual cleaning so we can prepare a config file.
storage.DeleteDirectory(string.Empty);

using (var storageConfig = new TournamentStorageManager(storage))
storageConfig.Set(StorageConfig.CurrentTournament, custom_tournament);

try
{
var osu = loadOsu(host);

storage = osu.Dependencies.Get<Storage>();

Assert.That(storage.GetFullPath("."), Is.EqualTo(Path.Combine(tournamentBasePath(nameof(TestCustomDirectory)), custom_tournament)));
}
finally
{
host.Exit();
}
}
}

[Test]
public void TestMigration()
{
using (HeadlessGameHost host = new HeadlessGameHost(nameof(TestMigration)))
{
string osuRoot = basePath(nameof(TestMigration));
string configFile = Path.Combine(osuRoot, "tournament.ini");

if (File.Exists(configFile))
File.Delete(configFile);

// Recreate the old setup that uses "tournament" as the base path.
string oldPath = Path.Combine(osuRoot, "tournament");

string videosPath = Path.Combine(oldPath, "videos");
string modsPath = Path.Combine(oldPath, "mods");
string flagsPath = Path.Combine(oldPath, "flags");

Directory.CreateDirectory(videosPath);
Directory.CreateDirectory(modsPath);
Directory.CreateDirectory(flagsPath);

// Define testing files corresponding to the specific file migrations that are needed
string bracketFile = Path.Combine(osuRoot, "bracket.json");

string drawingsConfig = Path.Combine(osuRoot, "drawings.ini");
string drawingsFile = Path.Combine(osuRoot, "drawings.txt");
string drawingsResult = Path.Combine(osuRoot, "drawings_results.txt");

// Define sample files to test recursive copying
string videoFile = Path.Combine(videosPath, "video.mp4");
string modFile = Path.Combine(modsPath, "mod.png");
string flagFile = Path.Combine(flagsPath, "flag.png");

File.WriteAllText(bracketFile, "{}");
File.WriteAllText(drawingsConfig, "test");
File.WriteAllText(drawingsFile, "test");
File.WriteAllText(drawingsResult, "test");
File.WriteAllText(videoFile, "test");
File.WriteAllText(modFile, "test");
File.WriteAllText(flagFile, "test");

try
{
var osu = loadOsu(host);

var storage = osu.Dependencies.Get<Storage>();

var migratedPath = Path.Combine(tournamentBasePath(nameof(TestMigration)), "default");

videosPath = Path.Combine(migratedPath, "videos");
modsPath = Path.Combine(migratedPath, "mods");
flagsPath = Path.Combine(migratedPath, "flags");

videoFile = Path.Combine(videosPath, "video.mp4");
modFile = Path.Combine(modsPath, "mod.png");
flagFile = Path.Combine(flagsPath, "flag.png");

Assert.That(storage.GetFullPath("."), Is.EqualTo(migratedPath));

Assert.True(storage.Exists("bracket.json"));
Assert.True(storage.Exists("drawings.txt"));
Assert.True(storage.Exists("drawings_results.txt"));

Assert.True(storage.Exists("drawings.ini"));

Assert.True(storage.Exists(videoFile));
Assert.True(storage.Exists(modFile));
Assert.True(storage.Exists(flagFile));
}
finally
{
host.Storage.Delete("tournament.ini");
host.Storage.DeleteDirectory("tournaments");
host.Exit();
}
}
}

private TournamentGameBase loadOsu(GameHost host)
{
var osu = new TournamentGameBase();
Task.Run(() => host.Run(osu));
waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
return osu;
}

private static void waitForOrAssert(Func<bool> result, string failureMessage, int timeout = 90000)
{
Task task = Task.Run(() =>
{
while (!result()) Thread.Sleep(200);
});

Assert.IsTrue(task.Wait(timeout), failureMessage);
}

private string basePath(string testInstance) => Path.Combine(RuntimeInfo.StartupDirectory, "headless", testInstance);

private string tournamentBasePath(string testInstance) => Path.Combine(basePath(testInstance), "tournaments");
}
}
7 changes: 4 additions & 3 deletions osu.Game.Tournament/Components/TourneyVideo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Video;
using osu.Framework.Platform;
using osu.Framework.Timing;
using osu.Game.Graphics;
using osu.Game.Tournament.IO;

namespace osu.Game.Tournament.Components
{
Expand All @@ -17,7 +19,6 @@ public class TourneyVideo : CompositeDrawable
private readonly string filename;
private readonly bool drawFallbackGradient;
private Video video;

private ManualClock manualClock;

public TourneyVideo(string filename, bool drawFallbackGradient = false)
Expand All @@ -27,9 +28,9 @@ public TourneyVideo(string filename, bool drawFallbackGradient = false)
}

[BackgroundDependencyLoader]
private void load(TournamentStorage storage)
private void load(Storage storage)
{
var stream = storage.GetStream($@"videos/{filename}");
var stream = (storage as TournamentStorage)?.VideoStore.GetStream(filename);

if (stream != null)
{
Expand Down
23 changes: 23 additions & 0 deletions osu.Game.Tournament/Configuration/TournamentStorageManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Configuration;
using osu.Framework.Platform;

namespace osu.Game.Tournament.Configuration
{
public class TournamentStorageManager : IniConfigManager<StorageConfig>
{
protected override string Filename => "tournament.ini";

public TournamentStorageManager(Storage storage)
: base(storage)
{
}
}

public enum StorageConfig
{
CurrentTournament,
}
}
69 changes: 69 additions & 0 deletions osu.Game.Tournament/IO/TournamentStorage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.IO;
using System.IO;
using osu.Game.Tournament.Configuration;

namespace osu.Game.Tournament.IO
{
public class TournamentStorage : MigratableStorage
{
private const string default_tournament = "default";
private readonly Storage storage;
private readonly TournamentStorageManager storageConfig;
public TournamentVideoResourceStore VideoStore { get; }

public TournamentStorage(Storage storage)
: base(storage.GetStorageForDirectory("tournaments"), string.Empty)
{
this.storage = storage;

storageConfig = new TournamentStorageManager(storage);

if (storage.Exists("tournament.ini"))
{
ChangeTargetStorage(UnderlyingStorage.GetStorageForDirectory(storageConfig.Get<string>(StorageConfig.CurrentTournament)));
}
else
Migrate(UnderlyingStorage.GetStorageForDirectory(default_tournament));

VideoStore = new TournamentVideoResourceStore(this);
Logger.Log("Using tournament storage: " + GetFullPath(string.Empty));
}

public override void Migrate(Storage newStorage)
{
var source = new DirectoryInfo(storage.GetFullPath("tournament"));
var destination = new DirectoryInfo(newStorage.GetFullPath("."));

if (source.Exists)
{
Logger.Log("Migrating tournament assets to default tournament storage.");
CopyRecursive(source, destination);
DeleteRecursive(source);
}

moveFileIfExists("bracket.json", destination);
moveFileIfExists("drawings.txt", destination);
moveFileIfExists("drawings_results.txt", destination);
moveFileIfExists("drawings.ini", destination);
ChangeTargetStorage(newStorage);
storageConfig.Set(StorageConfig.CurrentTournament, default_tournament);
storageConfig.Save();
}

private void moveFileIfExists(string file, DirectoryInfo destination)
{
if (!storage.Exists(file))
return;

Logger.Log($"Migrating {file} to default tournament storage.");
var fileInfo = new System.IO.FileInfo(storage.GetFullPath(file));
AttemptOperation(() => fileInfo.CopyTo(Path.Combine(destination.FullName, fileInfo.Name), true));
fileInfo.Delete();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
using osu.Framework.IO.Stores;
using osu.Framework.Platform;

namespace osu.Game.Tournament
namespace osu.Game.Tournament.IO
{
internal class TournamentStorage : NamespacedResourceStore<byte[]>
public class TournamentVideoResourceStore : NamespacedResourceStore<byte[]>
{
public TournamentStorage(Storage storage)
: base(new StorageBackedResourceStore(storage), "tournament")
public TournamentVideoResourceStore(Storage storage)
: base(new StorageBackedResourceStore(storage), "videos")
{
AddExtension("m4v");
AddExtension("avi");
Expand Down
18 changes: 6 additions & 12 deletions osu.Game.Tournament/TournamentGameBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input;
using osu.Framework.IO.Stores;
using osu.Framework.Platform;
using osu.Framework.IO.Stores;
using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests;
using osu.Game.Tournament.IPC;
using osu.Game.Tournament.IO;
using osu.Game.Tournament.Models;
using osu.Game.Users;
using osuTK.Input;
Expand All @@ -23,13 +24,8 @@ namespace osu.Game.Tournament
public class TournamentGameBase : OsuGameBase
{
private const string bracket_filename = "bracket.json";

private LadderInfo ladder;

private Storage storage;

private TournamentStorage tournamentStorage;

private TournamentStorage storage;
private DependencyContainer dependencies;
private FileBasedIPC ipc;

Expand All @@ -39,15 +35,13 @@ protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnl
}

[BackgroundDependencyLoader]
private void load(Storage storage)
private void load(Storage baseStorage)
{
Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly));

dependencies.CacheAs(tournamentStorage = new TournamentStorage(storage));

Textures.AddStore(new TextureLoaderStore(tournamentStorage));
dependencies.CacheAs<Storage>(storage = new TournamentStorage(baseStorage));

this.storage = storage;
Textures.AddStore(new TextureLoaderStore(storage.VideoStore));

readBracket();

Expand Down
Loading