mirror of
https://github.com/ppy/osu.git
synced 2026-05-15 07:02:36 +08:00
Compare commits
9704 Commits
v2017.216.0
...
0.7.2v
@@ -7,3 +7,21 @@ insert_final_newline = true
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
#Roslyn naming styles
|
||||
|
||||
#PascalCase for public and protected members
|
||||
dotnet_naming_style.pascalcase.capitalization = pascal_case
|
||||
dotnet_naming_symbols.public_members.applicable_accessibilities = public,internal,protected,protected_internal
|
||||
dotnet_naming_symbols.public_members.applicable_kinds = property,method,field,event,delegate
|
||||
dotnet_naming_rule.public_members_pascalcase.severity = suggestion
|
||||
dotnet_naming_rule.public_members_pascalcase.symbols = public_members
|
||||
dotnet_naming_rule.public_members_pascalcase.style = pascalcase
|
||||
|
||||
#camelCase for private members
|
||||
dotnet_naming_style.camelcase.capitalization = camel_case
|
||||
dotnet_naming_symbols.private_members.applicable_accessibilities = private
|
||||
dotnet_naming_symbols.private_members.applicable_kinds = property,method,field,event,delegate
|
||||
dotnet_naming_rule.private_members_camelcase.severity = suggestion
|
||||
dotnet_naming_rule.private_members_camelcase.symbols = private_members
|
||||
dotnet_naming_rule.private_members_camelcase.style = camelcase
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
bin/[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
|
||||
Vendored
+52
-22
@@ -1,36 +1,66 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch VisualTests",
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Desktop.VisualTests/bin/Debug/osu!.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "build",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"externalConsole": false
|
||||
},
|
||||
{
|
||||
"name": "Launch Desktop",
|
||||
"configurations": [{
|
||||
"name": "osu! VisualTests (Debug)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe",
|
||||
"args": [],
|
||||
"args": [
|
||||
"--tests"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "build",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"externalConsole": false
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "Attach",
|
||||
"name": "osu! VisualTests (Release)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "attach",
|
||||
"address": "localhost",
|
||||
"port": 55555
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe",
|
||||
"args": [
|
||||
"--tests"
|
||||
],
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Debug)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Debug)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
},
|
||||
{
|
||||
"name": "osu! (Release)",
|
||||
"windows": {
|
||||
"type": "clr"
|
||||
},
|
||||
"type": "mono",
|
||||
"request": "launch",
|
||||
"program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "Build (Release)",
|
||||
"runtimeExecutable": null,
|
||||
"env": {},
|
||||
"console": "internalConsole"
|
||||
}
|
||||
]
|
||||
}
|
||||
Vendored
+63
-18
@@ -1,25 +1,70 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "0.1.0",
|
||||
"windows": {
|
||||
"command": "msbuild"
|
||||
},
|
||||
"linux": {
|
||||
"command": "xbuild"
|
||||
},
|
||||
"args": [
|
||||
// Ask msbuild to generate full paths for file names.
|
||||
"/property:GenerateFullPaths=true"
|
||||
],
|
||||
"taskSelector": "/t:",
|
||||
"showOutput": "silent",
|
||||
"tasks": [
|
||||
"version": "2.0.0",
|
||||
"tasks": [{
|
||||
"label": "Build (Debug)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/p:DebugType=portable",
|
||||
"/m",
|
||||
"/v:m"
|
||||
],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"taskName": "build",
|
||||
// Show the output window only if unrecognized errors occur.
|
||||
"showOutput": "silent",
|
||||
// Use the standard MS compiler pattern to detect errors, warnings and infos
|
||||
"label": "Build (Release)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"/p:Configuration=Release",
|
||||
"/p:DebugType=portable",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/v:m"
|
||||
],
|
||||
"group": "build",
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Clean (Debug)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"/p:DebugType=portable",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/m",
|
||||
"/t:Clean",
|
||||
"/v:m"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Clean (Release)",
|
||||
"type": "shell",
|
||||
"command": "msbuild",
|
||||
"args": [
|
||||
"/p:Configuration=Release",
|
||||
"/p:GenerateFullPaths=true",
|
||||
"/p:DebugType=portable",
|
||||
"/m",
|
||||
"/t:Clean",
|
||||
"/v:m"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
},
|
||||
{
|
||||
"label": "Clean All",
|
||||
"dependsOn": [
|
||||
"Clean (Debug)",
|
||||
"Clean (Release)"
|
||||
],
|
||||
"problemMatcher": "$msCompile"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# Linux
|
||||
### 1. Requirements:
|
||||
Mono >= 5.4.0 (>= 5.8.0 recommended)
|
||||
Please check [here](http://www.mono-project.com/download/) for stable or [here](http://www.mono-project.com/download/alpha/) for an alpha release.
|
||||
NuGet >= 4.4.0
|
||||
msbuild
|
||||
git
|
||||
|
||||
### 2. Cloning project
|
||||
Clone the entire repository with submodules using
|
||||
```
|
||||
git clone https://github.com/ppy/osu --recursive
|
||||
```
|
||||
Then restore NuGet packages from the repository
|
||||
```
|
||||
nuget restore
|
||||
```
|
||||
### 3. Compiling
|
||||
Simply run `msbuild` where `osu.sln` is located, this will create all binaries in `osu/osu.Desktop/bin/Debug`.
|
||||
### 4. Optimizing
|
||||
If you want additional performance you can change build type to Release with
|
||||
```
|
||||
msbuild -p:Configuration=Release
|
||||
```
|
||||
Additionally, mono provides an AOT utility which attempts to precompile binaries. You can utilize that by running
|
||||
```
|
||||
mono --aot ./osu\!.exe
|
||||
```
|
||||
### 5. Troubleshooting
|
||||
You may run into trouble with NuGet versioning, as the one in packaging system is almost always out of date. Simply run
|
||||
```
|
||||
nuget
|
||||
sudo nuget update -self
|
||||
```
|
||||
**Warning** NuGet creates few config files when it's run for the first time.
|
||||
Do not run NuGet as root on the first run or you might run into very peculiar issues.
|
||||
+7
-5
@@ -1,9 +1,11 @@
|
||||
osu!lazer is currently in early stages of development and is not yet ready for end users. Please avoid creating issues or bugs if you do not personally intend to fix them. Some acceptable topics include:
|
||||
osu!lazer is currently still under heavy development!
|
||||
|
||||
Please ensure that you are making an issue for one of the following:
|
||||
|
||||
- A bug with currently implemented features (not features that don't exist)
|
||||
- A feature you are considering adding, so we can collaborate on feedback and design.
|
||||
- Discussions about technical design decisions
|
||||
- Bugs that you have found and are personally willing and able to fix
|
||||
- TODO lists of smaller tasks around larger features
|
||||
|
||||
Basically, issues are not a place for you to get help. They are a place for developers to collaborate on the game.
|
||||
|
||||
If your issue qualifies, replace this text with a detailed description of your issue with as much relevant information as you can provide.
|
||||
|
||||
Screenshots and log files are highly welcomed.
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
# osu! [](https://ci.appveyor.com/project/peppy/osu)
|
||||
# osu! [](https://ci.appveyor.com/project/peppy/osu) [](https://www.codefactor.io/repository/github/ppy/osu) [](https://discord.gg/ppy)
|
||||
|
||||
|
||||
|
||||
[osu! on the web](https://osu.ppy.sh) | [dev chat](https://discord.gg/ppy)
|
||||
|
||||
Rhythm is just a *click* away. The future of osu! and the beginning of an open era!
|
||||
Rhythm is just a *click* away. The future of [osu!](https://osu.ppy.sh) and the beginning of an open era!
|
||||
|
||||
# Status
|
||||
|
||||
@@ -12,14 +8,19 @@ This is still heavily under development and is not intended for end-user use. Th
|
||||
|
||||
# Requirements
|
||||
|
||||
- A desktop platform which can compile .NET 4.5.
|
||||
- Visual Studio or MonoDevelop is recommended.
|
||||
- A desktop platform that can compile .NET 4.6.1. We recommend using [Visual Studio Community Edition](https://www.visualstudio.com/) (Windows), [Visual Studio for Mac](https://www.visualstudio.com/vs/visual-studio-mac/) (macOS) or [MonoDevelop](http://www.monodevelop.com/download/) (Linux), all of which are free. [Visual Studio Code](https://code.visualstudio.com/) may also be used but requires further setup steps which are not covered here.
|
||||
|
||||
# Getting Started
|
||||
- Clone the repository including submodules (`git clone --recurse-submodules https://github.com/ppy/osu`)
|
||||
- Build in your IDE of choice (recommended IDEs automatically restore nuget packages; if you are using an alternative make sure to `nuget restore`)
|
||||
|
||||
# Contributing
|
||||
|
||||
We welcome all contributions, but keep in mind that we already have a lot of the UI designed. If you wish to work on something with the intention on having it included in the official distribution, please open an issue for discussion and we will give you what you need from a design perspective to proceed. If you want to make *changes* to the design, we recommend you open an issue with your intentions before spending too much time, to ensure no effort is wasted.
|
||||
|
||||
Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://goo.gl/nFdoyI). If you're unsure of what you can help with, check out the [list](https://github.com/ppy/osu/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3Abounty) of available issues with bounty.
|
||||
Please make sure you are familiar with the [development and testing](https://github.com/ppy/osu-framework/wiki/Development-and-Testing) procedure we have set up. New component development, and where possible, bug fixing and debugging existing components **should always be done under VisualTests**.
|
||||
|
||||
Contributions can be made via pull requests to this repository. We hope to credit and reward larger contributions via a [bounty system](https://www.bountysource.com/teams/ppy). If you're unsure of what you can help with, check out the [list of open issues](https://github.com/ppy/osu/issues).
|
||||
|
||||
Note that while we already have certain standards in place, nothing is set in stone. If you have an issue with the way code is structured; with any libraries we are using; with any processes involved with contributing, *please* bring it up. I welcome all feedback so we can make contributing to this project as pain-free as possible.
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using osu.Framework.Graphics;
|
||||
using OpenTK;
|
||||
using Symcol.Core.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.GameObjects
|
||||
{
|
||||
public class SymcolHitbox : SymcolContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// whether we want to do hit detection
|
||||
/// </summary>
|
||||
public int Team { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// whether we want to do hit detection
|
||||
/// </summary>
|
||||
public bool HitDetection { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// the shape of this object (used for hit detection)
|
||||
/// </summary>
|
||||
public Shape Shape { get; }
|
||||
|
||||
public SymcolHitbox(Vector2 size, Shape shape = Shape.Circle)
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
Shape = shape;
|
||||
Size = size;
|
||||
|
||||
if (Shape == Shape.Circle)
|
||||
Child = new SymcolContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
CornerRadius = Width / 2
|
||||
};
|
||||
else if (Shape == Shape.Rectangle)
|
||||
Child = new SymcolContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
};
|
||||
}
|
||||
|
||||
public bool HitDetect(SymcolHitbox hitbox1, SymcolHitbox hitbox2)
|
||||
{
|
||||
if (hitbox1.HitDetection && hitbox2.HitDetection && hitbox1.Team != hitbox2.Team)
|
||||
{
|
||||
if (hitbox1.Shape == Shape.Circle && hitbox2.Shape == Shape.Circle)
|
||||
{
|
||||
if (hitbox1.ScreenSpaceDrawQuad.AABB.IntersectsWith(hitbox2.ScreenSpaceDrawQuad.AABB))
|
||||
return true;
|
||||
}
|
||||
else if (hitbox1.Shape == Shape.Circle && hitbox2.Shape == Shape.Rectangle || hitbox1.Shape == Shape.Rectangle && hitbox2.Shape == Shape.Circle)
|
||||
{
|
||||
if (hitbox1.ScreenSpaceDrawQuad.AABB.IntersectsWith(hitbox2.ScreenSpaceDrawQuad.AABB))
|
||||
return true;
|
||||
}
|
||||
else if (hitbox1.Shape == Shape.Rectangle && hitbox2.Shape == Shape.Rectangle)
|
||||
{
|
||||
if (hitbox1.ScreenSpaceDrawQuad.AABB.IntersectsWith(hitbox2.ScreenSpaceDrawQuad.AABB))
|
||||
return true;
|
||||
}
|
||||
else if (hitbox1.Shape == Shape.Complex || hitbox2.Shape == Shape.Complex)
|
||||
foreach (SymcolContainer child1 in hitbox1.Children)
|
||||
foreach (SymcolContainer child2 in hitbox2.Children)
|
||||
if (child1.ScreenSpaceDrawQuad.AABB.IntersectsWith(child2.ScreenSpaceDrawQuad.AABB))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Shape
|
||||
{
|
||||
Circle,
|
||||
Rectangle,
|
||||
Complex
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.Graphics.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// Will support base eden game functions (if we come up with any)
|
||||
/// </summary>
|
||||
public class SymcolClickableContainer : ClickableContainer
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.Graphics.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// Will support base eden game functions (if we come up with any)
|
||||
/// </summary>
|
||||
public class SymcolContainer : Container
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Core.Graphics.Containers
|
||||
{
|
||||
public class SymcolDialContainer : CircularContainer
|
||||
{
|
||||
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => true;
|
||||
|
||||
private Vector2 mousePosition;
|
||||
|
||||
private float lastAngle;
|
||||
private float currentRotation;
|
||||
public float RotationAbsolute;
|
||||
|
||||
private int completeTick;
|
||||
|
||||
private bool updateCompleteTick() => completeTick != (completeTick = (int)(RotationAbsolute / 360));
|
||||
|
||||
private bool rotationTransferred;
|
||||
|
||||
protected override bool OnMouseMove(InputState state)
|
||||
{
|
||||
mousePosition = Parent.ToLocalSpace(state.Mouse.NativeState.Position);
|
||||
return base.OnMouseMove(state);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
var thisAngle = -(float)MathHelper.RadiansToDegrees(Math.Atan2(mousePosition.X - DrawSize.X / 2, mousePosition.Y - DrawSize.Y / 2));
|
||||
|
||||
|
||||
if (!rotationTransferred)
|
||||
{
|
||||
currentRotation = Rotation * 2;
|
||||
rotationTransferred = true;
|
||||
}
|
||||
|
||||
if (thisAngle - lastAngle > 180)
|
||||
lastAngle += 360;
|
||||
else if (lastAngle - thisAngle > 180)
|
||||
lastAngle -= 360;
|
||||
|
||||
currentRotation += thisAngle - lastAngle;
|
||||
RotationAbsolute += Math.Abs(thisAngle - lastAngle);
|
||||
|
||||
lastAngle = thisAngle;
|
||||
|
||||
foreach(Drawable drawable in Children)
|
||||
drawable.RotateTo(currentRotation / 2, 200, Easing.OutExpo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using osu.Framework.Input;
|
||||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace Symcol.Core.Graphics.Containers
|
||||
{
|
||||
public class SymcolDragContainer : SymcolContainer
|
||||
{
|
||||
protected override bool OnDragStart(InputState state) => true;
|
||||
|
||||
public bool AllowLeftClickDrag { get; set; } = true;
|
||||
|
||||
private bool drag;
|
||||
|
||||
private Vector2 startPosition;
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
{
|
||||
startPosition = Position;
|
||||
|
||||
if (args.Button == MouseButton.Left && AllowLeftClickDrag || args.Button == MouseButton.Right)
|
||||
drag = true;
|
||||
|
||||
return base.OnMouseDown(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
if (drag)
|
||||
Position = startPosition + state.Mouse.Position - state.Mouse.PositionMouseDown.GetValueOrDefault();
|
||||
|
||||
return base.OnDrag(state);
|
||||
}
|
||||
|
||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||
{
|
||||
if (args.Button == MouseButton.Left && AllowLeftClickDrag || args.Button == MouseButton.Right)
|
||||
drag = false;
|
||||
|
||||
return base.OnMouseUp(state, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Input;
|
||||
using Symcol.Core.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.Graphics.UserInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// just a Button with a sprite
|
||||
/// </summary>
|
||||
public class SpriteButton : SymcolClickableContainer
|
||||
{
|
||||
private readonly string textureName;
|
||||
|
||||
public string Text
|
||||
{
|
||||
get { return spriteText?.Text; }
|
||||
set
|
||||
{
|
||||
if (spriteText != null)
|
||||
spriteText.Text = value;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Sprite sprite;
|
||||
private readonly SpriteText spriteText;
|
||||
|
||||
public SpriteButton(string textureName)
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
this.textureName = textureName;
|
||||
Masking = true;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
sprite = new Sprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill
|
||||
},
|
||||
spriteText = new SpriteText
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(TextureStore textures)
|
||||
{
|
||||
sprite.Texture = textures.Get(textureName);
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
if (Enabled.Value)
|
||||
{
|
||||
var flash = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
};
|
||||
|
||||
Add(flash);
|
||||
|
||||
flash.Blending = BlendingMode.Additive;
|
||||
flash.FadeOut(200);
|
||||
flash.Expire();
|
||||
}
|
||||
|
||||
return base.OnClick(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Input;
|
||||
using Symcol.Core.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Core.Graphics.UserInterface
|
||||
{
|
||||
public class SymcolWindow : SymcolContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// Put all your stuff in this
|
||||
/// </summary>
|
||||
public SymcolContainer WindowContent { get; set; }
|
||||
public SpriteText WindowTitle;
|
||||
|
||||
private readonly SymcolContainer topBar;
|
||||
private readonly SymcolClickableContainer minimize;
|
||||
|
||||
public SymcolWindow(Vector2 size)
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
CornerRadius = 6;
|
||||
Masking = true;
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
topBar = new SymcolContainer
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Height = 20,
|
||||
Width = size.X,
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
},
|
||||
WindowTitle = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
TextSize = 18
|
||||
},
|
||||
new SymcolClickableContainer
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 30,
|
||||
Action = Close,
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.Red,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
}
|
||||
},
|
||||
minimize = new SymcolClickableContainer
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 30,
|
||||
Position = new Vector2(-30, 0),
|
||||
Action = Minimize,
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.White,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.5f
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
WindowContent = new SymcolContainer
|
||||
{
|
||||
Size = size,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre
|
||||
}
|
||||
};
|
||||
|
||||
WindowContent.Position = new Vector2(0, topBar.Height);
|
||||
}
|
||||
|
||||
protected void Close()
|
||||
{
|
||||
this.FadeOut(200);
|
||||
}
|
||||
|
||||
protected void Open()
|
||||
{
|
||||
this.FadeIn(200);
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
{
|
||||
if (Alpha > 0)
|
||||
this.FadeOut(200);
|
||||
else
|
||||
this.FadeIn(200);
|
||||
}
|
||||
|
||||
protected override bool OnDragStart(InputState state) => true;
|
||||
|
||||
private bool drag;
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
{
|
||||
if (args.Button == MouseButton.Left)
|
||||
drag = true;
|
||||
|
||||
return base.OnMouseDown(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
if (drag)
|
||||
Position += state.Mouse.Delta;
|
||||
|
||||
return base.OnDrag(state);
|
||||
}
|
||||
|
||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||
{
|
||||
if (args.Button == MouseButton.Left)
|
||||
drag = false;
|
||||
|
||||
return base.OnMouseUp(state, args);
|
||||
}
|
||||
|
||||
public void Maximize()
|
||||
{
|
||||
WindowContent.FadeIn(200);
|
||||
WindowContent.ScaleTo(Vector2.One, 200);
|
||||
minimize.Action = Minimize;
|
||||
}
|
||||
|
||||
public void Minimize()
|
||||
{
|
||||
WindowContent.FadeOut(200);
|
||||
WindowContent.ScaleTo(new Vector2(1, 0), 200);
|
||||
minimize.Action = Maximize;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class BasicPacket : Packet
|
||||
{
|
||||
/// <summary>
|
||||
/// Ask host if we can connect
|
||||
/// </summary>
|
||||
public bool Connect;
|
||||
|
||||
/// <summary>
|
||||
/// Tell the host we are breaking up
|
||||
/// </summary>
|
||||
public bool Disconnect;
|
||||
|
||||
/// <summary>
|
||||
/// Testing Connection
|
||||
/// </summary>
|
||||
public bool Test;
|
||||
|
||||
/// <summary>
|
||||
/// Send a force exit to others
|
||||
/// </summary>
|
||||
public bool Abort;
|
||||
|
||||
/// <summary>
|
||||
/// PreLoad the game
|
||||
/// </summary>
|
||||
public bool LoadGame;
|
||||
|
||||
/// <summary>
|
||||
/// Request a list of all players from Host
|
||||
/// </summary>
|
||||
public bool RequestPlayerList;
|
||||
|
||||
/// <summary>
|
||||
/// List of players in this match that we should account for
|
||||
/// </summary>
|
||||
public List<ClientInfo> PlayerList = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Tell Host we are PreLoaded
|
||||
/// </summary>
|
||||
public bool Loaded;
|
||||
|
||||
/// <summary>
|
||||
/// Start the game already!
|
||||
/// </summary>
|
||||
public bool StartGame;
|
||||
|
||||
/// <summary>
|
||||
/// Send to host when game started
|
||||
/// </summary>
|
||||
public bool GameStarted;
|
||||
|
||||
public BasicPacket(ClientInfo clientInfo) : base(clientInfo)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
/// <summary>
|
||||
/// Just a client signature basically
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ClientInfo
|
||||
{
|
||||
public string IP;
|
||||
|
||||
public int Port;
|
||||
|
||||
public int Ping;
|
||||
|
||||
public int ConncetionTryCount;
|
||||
|
||||
public double LastConnectionTime;
|
||||
|
||||
public double StartedTestConnectionTime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
public class NetworkingClient
|
||||
{
|
||||
public UdpClient UdpClient;
|
||||
|
||||
public IPEndPoint EndPoint;
|
||||
|
||||
/// <summary>
|
||||
/// if false we only receive
|
||||
/// </summary>
|
||||
public readonly bool Send;
|
||||
|
||||
public readonly int Port;
|
||||
|
||||
public readonly string IP;
|
||||
|
||||
public NetworkingClient(bool send, string ip, int port = 25570)
|
||||
{
|
||||
Port = port;
|
||||
IP = ip;
|
||||
|
||||
if (send)
|
||||
initializeSend();
|
||||
else
|
||||
initializeReceive();
|
||||
}
|
||||
|
||||
private void initializeSend()
|
||||
{
|
||||
UdpClient = new UdpClient(IP, Port);
|
||||
}
|
||||
|
||||
private void initializeReceive()
|
||||
{
|
||||
UdpClient = new UdpClient(Port);
|
||||
EndPoint = new IPEndPoint(IPAddress.Any, Port);
|
||||
}
|
||||
|
||||
private void sendByte(byte[] data)
|
||||
{
|
||||
UdpClient.Send(data, data.Length);
|
||||
}
|
||||
|
||||
private byte[] receiveByte()
|
||||
{
|
||||
return UdpClient.Receive(ref EndPoint);
|
||||
}
|
||||
|
||||
public static int SENTPACKETCOUNT;
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet somewhere
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendPacket(Packet packet)
|
||||
{
|
||||
SENTPACKETCOUNT++;
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
formatter.Serialize(stream, packet);
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
int i = packet.PacketSize;
|
||||
retry:
|
||||
byte[] data = new byte[i];
|
||||
|
||||
try
|
||||
{
|
||||
stream.Read(data, 0, (int)stream.Length);
|
||||
}
|
||||
catch
|
||||
{
|
||||
i *= 2;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
sendByte(data);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Receive a Packet from somewhere
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public Packet ReceivePacket(bool force = false)
|
||||
{
|
||||
if (UdpClient.Available > 0 || force)
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
byte[] data = receiveByte();
|
||||
stream.Write(data, 0, data.Length);
|
||||
|
||||
stream.Position = 0;
|
||||
|
||||
BinaryFormatter formatter = new BinaryFormatter();
|
||||
Packet packet = (Packet)formatter.Deserialize(stream);
|
||||
packet.ClientInfo.IP = EndPoint.Address.ToString();
|
||||
|
||||
return packet;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
if (UdpClient != null)
|
||||
UdpClient.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,646 @@
|
||||
#define SoloTesting
|
||||
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
//TODO: This NEEDS its own clock to avoid fuckery later on with DoubleTime and HalfTime
|
||||
public class NetworkingClientHandler : Container
|
||||
{
|
||||
//30 Seconds by default
|
||||
protected virtual double TimeOutTime => 30000;
|
||||
|
||||
protected readonly NetworkingClient ReceiveClient;
|
||||
|
||||
protected readonly NetworkingClient SendClient;
|
||||
|
||||
/// <summary>
|
||||
/// Just a client signature basically
|
||||
/// </summary>
|
||||
public ClientInfo ClientInfo;
|
||||
|
||||
/// <summary>
|
||||
/// All Connecting clients
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> ConnectingClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// All Connected clients
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> ConncetedClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Clients waiting in our match
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> InMatchClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Clients loaded and ready to start
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> LoadedClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Clients ingame playing
|
||||
/// </summary>
|
||||
public readonly List<ClientInfo> InGameClients = new List<ClientInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets hit when we get a Packet
|
||||
/// </summary>
|
||||
public Action<Packet> OnPacketReceive;
|
||||
|
||||
/// <summary>
|
||||
/// (Peer) Call this when we connect to a Host (Includes list of connected peers + Host)
|
||||
/// </summary>
|
||||
public Action<List<ClientInfo>> OnConnectedToHost;
|
||||
|
||||
/// <summary>
|
||||
/// (Host) Whenever a new client Connects
|
||||
/// </summary>
|
||||
public Action<ClientInfo> OnClientConnect;
|
||||
|
||||
/// <summary>
|
||||
/// (Host) Whenever a new client Disconnects
|
||||
/// </summary>
|
||||
public Action<ClientInfo> OnClientDisconnect;
|
||||
|
||||
/// <summary>
|
||||
/// (Host/Peer) When a new Client joins the game
|
||||
/// </summary>
|
||||
public Action<ClientInfo> OnClientJoin;
|
||||
|
||||
/// <summary>
|
||||
/// Receive a full player list
|
||||
/// </summary>
|
||||
public Action<List<ClientInfo>> OnReceivePlayerList;
|
||||
|
||||
/// <summary>
|
||||
/// if we are connected and in a match
|
||||
/// </summary>
|
||||
public bool InMatch;
|
||||
|
||||
/// <summary>
|
||||
/// Are we in a game
|
||||
/// </summary>
|
||||
public bool InGame;
|
||||
|
||||
/// <summary>
|
||||
/// Are we loaded and ready to start?
|
||||
/// </summary>
|
||||
public bool Loaded;
|
||||
|
||||
/// <summary>
|
||||
/// Called to leave an in-progress game
|
||||
/// </summary>
|
||||
public Action OnAbort;
|
||||
|
||||
/// <summary>
|
||||
/// Called to load the game (Includes Host)
|
||||
/// </summary>
|
||||
public Action<List<ClientInfo>> OnLoadGame;
|
||||
|
||||
/// <summary>
|
||||
/// Called to start the game once loaded
|
||||
/// </summary>
|
||||
public Action StartGame;
|
||||
|
||||
public readonly ClientType ClientType;
|
||||
|
||||
public NetworkingClientHandler(ClientType type, string ip, int port = 25570, string thisLocalIp = "0.0.0.0")
|
||||
{
|
||||
AlwaysPresent = true;
|
||||
|
||||
ClientType = type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ClientType.Host:
|
||||
ReceiveClient = new NetworkingClient(false, ip, port);
|
||||
break;
|
||||
case ClientType.Peer:
|
||||
ReceiveClient = new NetworkingClient(false, thisLocalIp, port);
|
||||
SendClient = new NetworkingClient(true, ip, port);
|
||||
break;
|
||||
case ClientType.Server:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
Logger.Log("Created a RulesetNetworkingClientHandler", LoggingTarget.Network, LogLevel.Verbose);
|
||||
|
||||
if (ClientInfo == null)
|
||||
ClientInfo = new ClientInfo
|
||||
{
|
||||
Port = port
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (ClientType == ClientType.Peer)
|
||||
ConnectToHost();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
PacketRestart:
|
||||
Packet p = null;
|
||||
|
||||
if (ReceiveClient.UdpClient.Available > 0)
|
||||
p = ReceiveClient.ReceivePacket();
|
||||
|
||||
if (p is BasicPacket packet)
|
||||
{
|
||||
//Hosts
|
||||
if (SendClient == null)
|
||||
{
|
||||
if (packet.Disconnect)
|
||||
{
|
||||
OnClientDisconnect?.Invoke(packet.ClientInfo);
|
||||
foreach (ClientInfo client in ConnectingClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
ConnectingClients.Remove(client);
|
||||
Logger.Log("A Connecting Client has Disconnected", LoggingTarget.Network, LogLevel.Verbose);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in ConncetedClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
ConncetedClients.Remove(client);
|
||||
Logger.Log("A Client has Disconnected", LoggingTarget.Network, LogLevel.Verbose);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in InMatchClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
InMatchClients.Remove(client);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in LoadedClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
LoadedClients.Remove(client);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in InGameClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
InGameClients.Remove(client);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (packet.Connect)
|
||||
{
|
||||
packet.ClientInfo.StartedTestConnectionTime = Time.Current;
|
||||
ConnectingClients.Add(packet.ClientInfo);
|
||||
|
||||
NetworkingClient client = new NetworkingClient(true, packet.ClientInfo.IP, packet.ClientInfo.Port);
|
||||
|
||||
List<ClientInfo> playerList = new List<ClientInfo>
|
||||
{
|
||||
ClientInfo
|
||||
};
|
||||
|
||||
foreach (ClientInfo clientInfo in ConncetedClients)
|
||||
playerList.Add(clientInfo);
|
||||
|
||||
client.SendPacket(new BasicPacket(ClientInfo)
|
||||
{
|
||||
PlayerList = playerList,
|
||||
Connect = true
|
||||
});
|
||||
|
||||
Logger.Log("A Client is Connecting. . .", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
if (packet.RequestPlayerList)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, packet.ClientInfo.IP, packet.ClientInfo.Port);
|
||||
|
||||
List<ClientInfo> playerList = new List<ClientInfo>
|
||||
{
|
||||
ClientInfo
|
||||
};
|
||||
|
||||
foreach (ClientInfo clientInfo in ConncetedClients)
|
||||
playerList.Add(clientInfo);
|
||||
|
||||
client.SendPacket(new BasicPacket(ClientInfo)
|
||||
{
|
||||
PlayerList = playerList,
|
||||
RequestPlayerList = true
|
||||
});
|
||||
|
||||
Logger.Log("A Client is Connecting. . .", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
if (packet.Loaded)
|
||||
foreach (ClientInfo client in InMatchClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
Logger.Log("A Client has Loaded and is ready to start", LoggingTarget.Network, LogLevel.Verbose);
|
||||
InMatchClients.Remove(client);
|
||||
LoadedClients.Add(client);
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet.GameStarted)
|
||||
foreach (ClientInfo client in LoadedClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
Logger.Log("A Client has started!", LoggingTarget.Network, LogLevel.Verbose);
|
||||
LoadedClients.Remove(client);
|
||||
InGameClients.Add(client);
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet.Test)
|
||||
{
|
||||
foreach (ClientInfo client in ConnectingClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
client.Ping = (int)Time.Current - (int)client.StartedTestConnectionTime;
|
||||
ConnectingClients.Remove(client);
|
||||
ConncetedClients.Add(client);
|
||||
InMatchClients.Add(client);
|
||||
OnClientJoin?.Invoke(client);
|
||||
client.LastConnectionTime = Time.Current;
|
||||
client.ConncetionTryCount = 0;
|
||||
Logger.Log("Successfully connected to a Client! Ping: " + client.Ping, LoggingTarget.Network, LogLevel.Verbose);
|
||||
break;
|
||||
}
|
||||
foreach (ClientInfo client in ConncetedClients)
|
||||
if (client.IP == packet.ClientInfo.IP)
|
||||
{
|
||||
client.Ping = (int)Time.Current - (int)client.StartedTestConnectionTime;
|
||||
client.LastConnectionTime = Time.Current;
|
||||
client.ConncetionTryCount = 0;
|
||||
Logger.Log("Successfully maintained connection to a Client! Ping: " + client.Ping, LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !SoloTesting
|
||||
if (InMatchClients.Count == 0 && LoadedClients.Count > 0 && Loaded && !InGame)
|
||||
SendStartGame();
|
||||
#endif
|
||||
|
||||
//Peers
|
||||
else if (SendClient != null)
|
||||
{
|
||||
if (packet.Connect)
|
||||
{
|
||||
if (!InGame && !InMatch)
|
||||
{
|
||||
InMatch = true;
|
||||
OnConnectedToHost?.Invoke(packet.PlayerList);
|
||||
}
|
||||
Logger.Log("Connected to Host!", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
if (packet.Test)
|
||||
{
|
||||
SendToHost(new BasicPacket(ClientInfo) { Test = true });
|
||||
Logger.Log("Received connection test info from host, returning. . .", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
if (packet.RequestPlayerList)
|
||||
OnReceivePlayerList?.Invoke(packet.PlayerList);
|
||||
|
||||
if (packet.StartGame)
|
||||
{
|
||||
StartGame?.Invoke();
|
||||
SendToHost(new BasicPacket(ClientInfo) { GameStarted = true });
|
||||
InGame = true;
|
||||
}
|
||||
|
||||
if (packet.Abort)
|
||||
{
|
||||
OnAbort?.Invoke();
|
||||
InGame = false;
|
||||
Loaded = false;
|
||||
}
|
||||
|
||||
if (packet.LoadGame)
|
||||
{
|
||||
Logger.Log("Received instructions to LoadGame for " + packet.PlayerList.Count + " players", LoggingTarget.Network, LogLevel.Verbose);
|
||||
OnLoadGame?.Invoke(packet.PlayerList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if SoloTesting
|
||||
if (Loaded && !InGame)
|
||||
SendStartGame();
|
||||
#endif
|
||||
|
||||
if (p != null)
|
||||
OnPacketReceive?.Invoke(p);
|
||||
|
||||
if (ReceiveClient.UdpClient.Available > 0)
|
||||
goto PacketRestart;
|
||||
|
||||
foreach (ClientInfo client in ConnectingClients)
|
||||
{
|
||||
if (client.LastConnectionTime + TimeOutTime / 10 <= Time.Current && client.ConncetionTryCount == 0)
|
||||
{
|
||||
client.StartedTestConnectionTime = Time.Current;
|
||||
TestConnection(client);
|
||||
}
|
||||
|
||||
if (client.LastConnectionTime + TimeOutTime / 6 <= Time.Current && client.ConncetionTryCount == 1)
|
||||
TestConnection(client);
|
||||
|
||||
if (client.LastConnectionTime + TimeOutTime / 3 <= Time.Current && client.ConncetionTryCount == 2)
|
||||
TestConnection(client);
|
||||
|
||||
if (client.StartedTestConnectionTime + TimeOutTime <= Time.Current)
|
||||
{
|
||||
ConnectingClients.Remove(client);
|
||||
Logger.Log("Connection to a connecting client lost! - " + client.IP + ":" + client.Port, LoggingTarget.Network, LogLevel.Error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ClientInfo client in ConncetedClients)
|
||||
{
|
||||
if (client.LastConnectionTime + TimeOutTime / 6 <= Time.Current && client.ConncetionTryCount == 0)
|
||||
{
|
||||
client.StartedTestConnectionTime = Time.Current;
|
||||
TestConnection(client);
|
||||
}
|
||||
|
||||
if (client.LastConnectionTime + TimeOutTime / 3 <= Time.Current && client.ConncetionTryCount == 1)
|
||||
TestConnection(client);
|
||||
|
||||
if (client.LastConnectionTime + TimeOutTime / 2 <= Time.Current && client.ConncetionTryCount == 2)
|
||||
TestConnection(client);
|
||||
|
||||
if (client.StartedTestConnectionTime + TimeOutTime <= Time.Current)
|
||||
{
|
||||
ConncetedClients.Remove(client);
|
||||
InGameClients.Remove(client);
|
||||
LoadedClients.Remove(client);
|
||||
InGameClients.Remove(client);
|
||||
Logger.Log("Connection to a connected client lost! - " + client.IP + ":" + client.Port, LoggingTarget.Network, LogLevel.Error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Poke!
|
||||
/// </summary>
|
||||
/// <param name="clientInfo"></param>
|
||||
protected void TestConnection(ClientInfo clientInfo)
|
||||
{
|
||||
clientInfo.ConncetionTryCount++;
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(new BasicPacket(ClientInfo) { Test = true });
|
||||
Logger.Log("Testing a client's connection - " + clientInfo.IP + ":" + clientInfo.Port, LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
public void RequestPlayerList()
|
||||
{
|
||||
BasicPacket packet = new BasicPacket(ClientInfo) { RequestPlayerList = true };
|
||||
SendToHost(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell peers to start loading game
|
||||
/// </summary>
|
||||
public virtual void StartLoadingGame()
|
||||
{
|
||||
if (SendClient == null)
|
||||
{
|
||||
BasicPacket packet = new BasicPacket(ClientInfo) { LoadGame = true };
|
||||
|
||||
foreach (ClientInfo client in InMatchClients)
|
||||
packet.PlayerList.Add(client);
|
||||
packet.PlayerList.Add(ClientInfo);
|
||||
|
||||
SendToInMatchClients(packet);
|
||||
|
||||
OnLoadGame?.Invoke(packet.PlayerList);
|
||||
}
|
||||
else
|
||||
Logger.Log("Called StartLoadingGame - We are not the Host!", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Call this when the game is Loaded and ready to be started
|
||||
/// </summary>
|
||||
public virtual void GameLoaded()
|
||||
{
|
||||
Loaded = true;
|
||||
SendToHost(new BasicPacket(ClientInfo) { Loaded = true });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to the Host
|
||||
/// </summary>
|
||||
public virtual void ConnectToHost()
|
||||
{
|
||||
SendToHost(new BasicPacket(ClientInfo) { Connect = true });
|
||||
Logger.Log("Attempting conection to Host. . .", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell peers to start and starts ours
|
||||
/// </summary>
|
||||
public virtual void SendStartGame()
|
||||
{
|
||||
if (SendClient == null)
|
||||
{
|
||||
SendToLoadedClients(new BasicPacket(ClientInfo) { StartGame = true });
|
||||
InGame = true;
|
||||
Logger.Log("Sending Start Game", LoggingTarget.Network, LogLevel.Verbose);
|
||||
}
|
||||
StartGame?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to the Host
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToHost(Packet packet)
|
||||
{
|
||||
if (SendClient != null)
|
||||
SendClient.SendPacket(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all Connecting clients
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToConnectingClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in ConnectingClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all clients Connected and waiting
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToConnectedClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in ConncetedClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all clients In this Match
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToInMatchClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in InMatchClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all clients Loaded
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToLoadedClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in LoadedClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to all clients InGame
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToInGameClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in InGameClients)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send a Packet to ALL clients we know
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
public void SendToAllClients(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
{
|
||||
SendToConnectingClients(packet);
|
||||
SendToConnectedClients(packet);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send to all but the one that sent it
|
||||
/// </summary>
|
||||
/// <param name="packet"></param>
|
||||
/// <param name="playerID"></param>
|
||||
public void ShareWithOtherPeers(Packet packet)
|
||||
{
|
||||
if (SendClient == null)
|
||||
foreach (ClientInfo clientInfo in ConncetedClients)
|
||||
if (packet.ClientInfo.IP != clientInfo.IP)
|
||||
{
|
||||
NetworkingClient client = new NetworkingClient(true, clientInfo.IP, clientInfo.Port);
|
||||
client.SendPacket(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void AbortGame()
|
||||
{
|
||||
SendToLoadedClients(new BasicPacket(ClientInfo) { Abort = true });
|
||||
SendToInGameClients(new BasicPacket(ClientInfo) { Abort = true });
|
||||
|
||||
restart:
|
||||
foreach (ClientInfo client in LoadedClients)
|
||||
{
|
||||
LoadedClients.Remove(client);
|
||||
InMatchClients.Add(client);
|
||||
goto restart;
|
||||
}
|
||||
foreach (ClientInfo client in InGameClients)
|
||||
{
|
||||
InGameClients.Remove(client);
|
||||
InMatchClients.Add(client);
|
||||
goto restart;
|
||||
}
|
||||
|
||||
InGame = false;
|
||||
Loaded = false;
|
||||
|
||||
OnAbort?.Invoke();
|
||||
}
|
||||
|
||||
public virtual void Disconnect()
|
||||
{
|
||||
Packet packet = new BasicPacket(ClientInfo) { Disconnect = true };
|
||||
|
||||
OnAbort?.Invoke();
|
||||
InMatch = false;
|
||||
InGame = false;
|
||||
Loaded = false;
|
||||
|
||||
if (SendClient == null)
|
||||
{
|
||||
SendToConnectingClients(packet);
|
||||
SendToConnectedClients(packet);
|
||||
}
|
||||
else
|
||||
SendToHost(packet);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Die
|
||||
/// </summary>
|
||||
/// <param name="isDisposing"></param>
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
ReceiveClient?.Clear();
|
||||
|
||||
if (SendClient != null)
|
||||
{
|
||||
SendToHost(new BasicPacket(ClientInfo) { Disconnect = true });
|
||||
SendClient.Clear();
|
||||
}
|
||||
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ClientType
|
||||
{
|
||||
Host,
|
||||
Peer,
|
||||
Server
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Symcol.Core.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class Packet
|
||||
{
|
||||
/// <summary>
|
||||
/// Just a Signature
|
||||
/// </summary>
|
||||
public readonly ClientInfo ClientInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Specify starting size of packet for efficiency
|
||||
/// </summary>
|
||||
public virtual int PacketSize => 1024;
|
||||
|
||||
public Packet(ClientInfo clientInfo)
|
||||
{
|
||||
ClientInfo = clientInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-14
@@ -1,38 +1,34 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("osu.Game.Modes.Mania")]
|
||||
[assembly: AssemblyTitle("symcol.Toys")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("osu.Game.Modes.Mania")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyProduct("symcol.Toys")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("48f4582b-7687-4621-9cbe-5c24197cb536")]
|
||||
[assembly: Guid("f34ac16c-e590-4d70-a069-a748326852bf")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{F34AC16C-E590-4D70-A069-A748326852BF}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Symcol.Core</RootNamespace>
|
||||
<AssemblyName>Symcol.Core</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Cyotek.Drawing.BitmapFont, Version=1.0.0.0, Culture=neutral, PublicKeyToken=58daa28b0b2de221, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Cyotek.Drawing.BitmapFont.1.3.4-beta1\lib\net46\Cyotek.Drawing.BitmapFont.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="ManagedBass, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ManagedBass.2.0.3\lib\net45\ManagedBass.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=3.8.1.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\NUnit.3.8.1\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\OpenTK.3.0.0-git00009\lib\net20\OpenTK.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net.Platform.Generic, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net40\SQLite.Net.Platform.Generic.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net.Platform.Win32, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLiteNetExtensions, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="GameObjects\SymcolHitbox.cs" />
|
||||
<Compile Include="Graphics\Containers\SymcolClickableContainer.cs" />
|
||||
<Compile Include="Graphics\Containers\SymcolDialContainer.cs" />
|
||||
<Compile Include="Graphics\Containers\SymcolDragContainer.cs" />
|
||||
<Compile Include="Graphics\Containers\SymcolContainer.cs" />
|
||||
<Compile Include="Graphics\UserInterface\SpriteButton.cs" />
|
||||
<Compile Include="Graphics\UserInterface\SymcolWindow.cs" />
|
||||
<Compile Include="Networking\BasicPacket.cs" />
|
||||
<Compile Include="Networking\ClientInfo.cs" />
|
||||
<Compile Include="Networking\NetworkingClient.cs" />
|
||||
<Compile Include="Networking\Packet.cs" />
|
||||
<Compile Include="Networking\NetworkingClientHandler.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\osu-Framework\osu.Framework\osu.Framework.csproj">
|
||||
<Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
|
||||
<Name>osu.Framework</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,43 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Containers
|
||||
{
|
||||
public class LinkText : OsuSpriteText, IHasTooltip
|
||||
{
|
||||
public string TooltipText => Tooltip;
|
||||
|
||||
public virtual string Tooltip => "";
|
||||
|
||||
private readonly OsuHoverContainer content;
|
||||
|
||||
public override bool HandleKeyboardInput => content.Action != null;
|
||||
public override bool HandleMouseInput => content.Action != null;
|
||||
|
||||
protected override Container<Drawable> Content => content ?? (Container<Drawable>)this;
|
||||
|
||||
public override IEnumerable<Drawable> FlowingChildren => Children;
|
||||
|
||||
public string Url
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
content.Action = () => Process.Start(value);
|
||||
}
|
||||
}
|
||||
|
||||
public LinkText()
|
||||
{
|
||||
AddInternal(content = new OsuHoverContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// TODO: make this more generic
|
||||
/// </summary>
|
||||
public class ProfileLink : LinkText
|
||||
{
|
||||
public override string Tooltip => "View profile in browser";
|
||||
|
||||
public ProfileLink(User user, bool maintainer = false)
|
||||
{
|
||||
if (!maintainer)
|
||||
Text = "Ruleset Creator: " + user.Username;
|
||||
else
|
||||
Text = "Ruleset Maintainer: " + user.Username;
|
||||
|
||||
Url = $@"https://osu.ppy.sh/users/{user.Id}";
|
||||
Font = @"Exo2.0-RegularItalic";
|
||||
TextSize = 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Rulesets.Core.HitObjects
|
||||
{
|
||||
/// <summary>
|
||||
/// Mostly stuff copied from Container
|
||||
/// </summary>
|
||||
/// <typeparam name="TObject"></typeparam>
|
||||
public abstract class DrawableSymcolHitObject<TObject> : DrawableHitObject<TObject>
|
||||
where TObject : HitObject
|
||||
{
|
||||
//Future prep?
|
||||
//public override void ClearTransformsAfter(double time, bool propagateChildren = false, string targetMember = null) { }
|
||||
//public override void ApplyTransformsAt(double time, bool propagateChildren = false) { }
|
||||
|
||||
protected virtual Container<Drawable> Content => new Container();
|
||||
|
||||
public IReadOnlyList<Drawable> Children
|
||||
{
|
||||
get
|
||||
{
|
||||
return InternalChildren;
|
||||
}
|
||||
set
|
||||
{
|
||||
ChildrenEnumerable = value;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<Drawable> ChildrenEnumerable
|
||||
{
|
||||
set
|
||||
{
|
||||
Clear();
|
||||
AddRange(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddRange(IEnumerable<Drawable> range)
|
||||
{
|
||||
foreach (Drawable d in range)
|
||||
Add(d);
|
||||
}
|
||||
|
||||
public Drawable Child
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Children.Count != 1)
|
||||
throw new InvalidOperationException($"{nameof(Child)} is only available when there's only 1 in {nameof(Children)}!");
|
||||
|
||||
return Children[0];
|
||||
}
|
||||
set
|
||||
{
|
||||
Clear();
|
||||
Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear() => Clear(true);
|
||||
|
||||
public virtual void Clear(bool disposeChildren)
|
||||
{
|
||||
if (Content != null)
|
||||
Content.Clear(disposeChildren);
|
||||
else
|
||||
ClearInternal(disposeChildren);
|
||||
}
|
||||
|
||||
protected DrawableSymcolHitObject(TObject hitObject)
|
||||
: base(hitObject)
|
||||
{
|
||||
}
|
||||
|
||||
public void Add(Drawable drawable)
|
||||
{
|
||||
AddInternal(drawable);
|
||||
}
|
||||
|
||||
public void Remove(Drawable drawable)
|
||||
{
|
||||
RemoveInternal(drawable);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class ChatPacket : Packet
|
||||
{
|
||||
public override int PacketSize => 4096;
|
||||
|
||||
public string Author;
|
||||
|
||||
public string AuthorColor;
|
||||
|
||||
public string Message;
|
||||
|
||||
public ChatPacket(ClientInfo clientInfo) : base(clientInfo)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
/// <summary>
|
||||
/// Just a client signature basically
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class RulesetClientInfo : ClientInfo
|
||||
{
|
||||
public string Username = "";
|
||||
|
||||
public int UserID = -1;
|
||||
|
||||
public string UserPic;
|
||||
|
||||
public string UserBackground;
|
||||
|
||||
public string UserCountry;
|
||||
|
||||
public string CountryFlagName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Online.API;
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
//TODO: This NEEDS its own clock to avoid fuckery later on with DoubleTime and HalfTime
|
||||
public class RulesetNetworkingClientHandler : NetworkingClientHandler, IOnlineComponent
|
||||
{
|
||||
public RulesetClientInfo RulesetClientInfo;
|
||||
|
||||
public Action<WorkingBeatmap> OnMapChange;
|
||||
|
||||
private OsuGame osu;
|
||||
|
||||
public RulesetNetworkingClientHandler(ClientType type, string ip, int port = 25570, string thisLocalIp = "0.0.0.0") : base(type, ip, port, thisLocalIp)
|
||||
{
|
||||
if (RulesetClientInfo == null)
|
||||
{
|
||||
RulesetClientInfo = new RulesetClientInfo
|
||||
{
|
||||
Port = port
|
||||
};
|
||||
|
||||
ClientInfo = RulesetClientInfo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send Map to Peers
|
||||
/// </summary>
|
||||
/// <param name="map"></param>
|
||||
public void SetMap(WorkingBeatmap map)
|
||||
{
|
||||
RulesetPacket packet;
|
||||
try
|
||||
{
|
||||
packet = new RulesetPacket(RulesetClientInfo)
|
||||
{
|
||||
OnlineBeatmapSetID = (int)map.BeatmapSetInfo.OnlineBeatmapSetID,
|
||||
OnlineBeatmapID = (int)map.BeatmapInfo.OnlineBeatmapID
|
||||
};
|
||||
SendToInMatchClients(packet);
|
||||
OnMapChange?.Invoke(osu.Beatmap.Value);
|
||||
}
|
||||
catch
|
||||
{
|
||||
packet = new RulesetPacket(RulesetClientInfo);
|
||||
SendToInMatchClients(packet);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api, OsuGame osu)
|
||||
{
|
||||
api.Register(this);
|
||||
this.osu = osu;
|
||||
}
|
||||
|
||||
public void APIStateChanged(APIAccess api, APIState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
default:
|
||||
RulesetClientInfo.Username = "";
|
||||
RulesetClientInfo.UserID = -1;
|
||||
break;
|
||||
case APIState.Online:
|
||||
RulesetClientInfo.Username = api.LocalUser.Value.Username;
|
||||
RulesetClientInfo.UserID = (int)api.LocalUser.Value.Id;
|
||||
RulesetClientInfo.UserCountry = api.LocalUser.Value.Country.FullName;
|
||||
RulesetClientInfo.CountryFlagName = api.LocalUser.Value.Country.FlagName;
|
||||
RulesetClientInfo.UserPic = api.LocalUser.Value.AvatarUrl;
|
||||
RulesetClientInfo.UserBackground = api.LocalUser.Value.CoverUrl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class RulesetPacket : Packet
|
||||
{
|
||||
public new readonly RulesetClientInfo ClientInfo;
|
||||
|
||||
public override int PacketSize => 4096;
|
||||
|
||||
public int OnlineBeatmapSetID = -1;
|
||||
|
||||
public int OnlineBeatmapID = -1;
|
||||
|
||||
public bool HaveMap;
|
||||
|
||||
public string ChatContent;
|
||||
|
||||
//public string RulesetName = "";
|
||||
|
||||
public RulesetPacket(RulesetClientInfo rulesetClientInfo) : base(rulesetClientInfo)
|
||||
{
|
||||
ClientInfo = rulesetClientInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Symcol.Core.Networking;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Networking
|
||||
{
|
||||
[Serializable]
|
||||
public class ScorePacket : Packet
|
||||
{
|
||||
public override int PacketSize => 2048;
|
||||
|
||||
public int Score;
|
||||
|
||||
public ScorePacket(ClientInfo clientInfo, int score) : base(clientInfo)
|
||||
{
|
||||
Score = score;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Options
|
||||
{
|
||||
public class MultiplayerDropdownEnumOption<T> : MultiplayerOption
|
||||
where T : struct
|
||||
{
|
||||
public readonly Bindable<T> BindableEnum;
|
||||
|
||||
public MultiplayerDropdownEnumOption(Bindable<T> bindable, string name, int quadrant, bool sync = true) : base(name, quadrant, sync)
|
||||
{
|
||||
BindableEnum = bindable;
|
||||
|
||||
OptionContainer.Child = new BetterSettingsEnumDropdown<T>
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Bindable = bindable,
|
||||
};
|
||||
}
|
||||
|
||||
private class BetterSettingsEnumDropdown<T> : SettingsEnumDropdown<T>
|
||||
{
|
||||
protected override Drawable CreateControl() => new BetterOsuEnumDropdown<T>
|
||||
{
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
};
|
||||
|
||||
private class BetterOsuEnumDropdown<T> : OsuEnumDropdown<T>
|
||||
{
|
||||
public BetterOsuEnumDropdown()
|
||||
{
|
||||
Menu.MaxHeight = 160;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using System;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Options
|
||||
{
|
||||
public abstract class MultiplayerOption : Container
|
||||
{
|
||||
protected readonly SpriteText Title;
|
||||
|
||||
protected readonly Container OptionContainer;
|
||||
|
||||
public MultiplayerOption(string name, int quadrant, bool sync = true)
|
||||
{
|
||||
if (quadrant == 1 | quadrant == 3 | quadrant == 5 | quadrant == 7)
|
||||
{
|
||||
switch (quadrant)
|
||||
{
|
||||
case 1:
|
||||
quadrant = 0;
|
||||
break;
|
||||
case 3:
|
||||
quadrant = 1;
|
||||
break;
|
||||
case 5:
|
||||
quadrant = 2;
|
||||
break;
|
||||
case 7:
|
||||
quadrant = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
Anchor = Anchor.TopLeft;
|
||||
Origin = Anchor.TopLeft;
|
||||
Position = new Vector2(16, 4 + (64 * quadrant));
|
||||
}
|
||||
else if (quadrant == 2 | quadrant == 4 | quadrant == 6 | quadrant == 8)
|
||||
{
|
||||
switch (quadrant)
|
||||
{
|
||||
case 2:
|
||||
quadrant = 0;
|
||||
break;
|
||||
case 4:
|
||||
quadrant = 1;
|
||||
break;
|
||||
case 6:
|
||||
quadrant = 2;
|
||||
break;
|
||||
case 8:
|
||||
quadrant = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopLeft;
|
||||
Position = new Vector2(22, 4 + (64 * quadrant));
|
||||
}
|
||||
else
|
||||
throw new Exception("Globglogabgalab");
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Width = 0.49f;
|
||||
Height = 80;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Title = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
TextSize = 20,
|
||||
Text = name
|
||||
},
|
||||
OptionContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(-16, 18),
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Framework.Graphics;
|
||||
using OpenTK;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Options
|
||||
{
|
||||
public class MultiplayerToggleOption : MultiplayerOption
|
||||
{
|
||||
public readonly Bindable<bool> BindableBool;
|
||||
|
||||
public MultiplayerToggleOption(Bindable<bool> bindable, string name, int quadrant, bool sync = true) : base(name, quadrant, sync)
|
||||
{
|
||||
BindableBool = bindable;
|
||||
|
||||
Child = new SettingsCheckbox
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Bindable = bindable,
|
||||
LabelText = " " + name,
|
||||
Position = new Vector2(-16, 18),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Users;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class Chat : Container, IOnlineComponent
|
||||
{
|
||||
private readonly RulesetNetworkingClientHandler rulesetNetworkingClientHandler;
|
||||
|
||||
private string playerColorHex = SymcolSettingsSubsection.SymcolConfigManager.GetBindable<string>(SymcolSetting.PlayerColor);
|
||||
|
||||
private User user;
|
||||
|
||||
private readonly FillFlowContainer<ChatMessage> messageContainer;
|
||||
private readonly OsuTextBox textBox;
|
||||
|
||||
public Chat(RulesetNetworkingClientHandler rulesetNetworkingClientHandler)
|
||||
{
|
||||
this.rulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
|
||||
rulesetNetworkingClientHandler.OnPacketReceive += (packet) =>
|
||||
{
|
||||
if (packet is ChatPacket chatPacket)
|
||||
Add(chatPacket);
|
||||
if (rulesetNetworkingClientHandler.ClientType == ClientType.Host)
|
||||
rulesetNetworkingClientHandler.ShareWithOtherPeers(packet);
|
||||
};
|
||||
|
||||
Anchor = Anchor.BottomCentre;
|
||||
Origin = Anchor.BottomCentre;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Height = 0.46f;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.8f
|
||||
},
|
||||
new OsuScrollContainer
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.9f,
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
messageContainer = new FillFlowContainer<ChatMessage>
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
}
|
||||
}
|
||||
},
|
||||
textBox = new OsuTextBox
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.98f,
|
||||
Height = 36,
|
||||
Position = new Vector2(0, -12),
|
||||
Colour = Color4.White,
|
||||
Text = "Type here!"
|
||||
}
|
||||
};
|
||||
|
||||
textBox.OnCommit += (s, r) =>
|
||||
{
|
||||
AddMessage(textBox.Text);
|
||||
textBox.Text = "";
|
||||
};
|
||||
}
|
||||
|
||||
public void Add(ChatPacket packet)
|
||||
{
|
||||
ChatMessage message = new ChatMessage(packet);
|
||||
messageContainer.Add(message);
|
||||
}
|
||||
|
||||
public void AddMessage(string message)
|
||||
{
|
||||
if (message == "" | message == " ")
|
||||
return;
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
OsuColour.FromHex(playerColorHex);
|
||||
}
|
||||
catch
|
||||
{
|
||||
playerColorHex = "#ffffff";
|
||||
}
|
||||
|
||||
ChatPacket packet = new ChatPacket(rulesetNetworkingClientHandler.ClientInfo)
|
||||
{
|
||||
Author = user.Username,
|
||||
AuthorColor = playerColorHex,
|
||||
Message = message,
|
||||
};
|
||||
|
||||
rulesetNetworkingClientHandler.SendToHost(packet);
|
||||
rulesetNetworkingClientHandler.SendToInMatchClients(packet);
|
||||
Add(packet);
|
||||
}
|
||||
else
|
||||
Logger.Log("You must be logged in to message!", LoggingTarget.Network, LogLevel.Error);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api)
|
||||
{
|
||||
api.Register(this);
|
||||
}
|
||||
|
||||
public void APIStateChanged(APIAccess api, APIState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
default:
|
||||
user = null;
|
||||
break;
|
||||
case APIState.Online:
|
||||
user = api.LocalUser.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class ChatMessage : Container
|
||||
{
|
||||
public ChatMessage(ChatPacket packet)
|
||||
{
|
||||
Anchor = Anchor.TopLeft;
|
||||
Origin = Anchor.TopLeft;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Colour = OsuColour.FromHex(packet.AuthorColor),
|
||||
TextSize = 24,
|
||||
Text = packet.Author + ":"
|
||||
},
|
||||
new OsuTextFlowContainer(t => { t.TextSize = 24; })
|
||||
{
|
||||
Position = new OpenTK.Vector2(140, 0),
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Text = packet.Message
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Users;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MatchPlayer : ClickableContainer, IHasContextMenu
|
||||
{
|
||||
public readonly RulesetClientInfo ClientInfo;
|
||||
|
||||
private readonly Box dim;
|
||||
|
||||
private readonly DrawableFlag countryFlag;
|
||||
private readonly UserCoverBackground profileBackground;
|
||||
private readonly UpdateableAvatar profilePicture;
|
||||
|
||||
public MatchPlayer(RulesetClientInfo clientInfo)
|
||||
{
|
||||
ClientInfo = clientInfo;
|
||||
|
||||
Alpha = 0;
|
||||
Masking = true;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 40f;
|
||||
CornerRadius = 10;
|
||||
|
||||
Country country = new Country
|
||||
{
|
||||
FullName = ClientInfo.UserCountry,
|
||||
FlagName = ClientInfo.CountryFlagName,
|
||||
};
|
||||
|
||||
User user = new User
|
||||
{
|
||||
Username = ClientInfo.Username,
|
||||
Id = ClientInfo.UserID,
|
||||
Country = country,
|
||||
AvatarUrl = ClientInfo.UserPic,
|
||||
CoverUrl = ClientInfo.UserBackground,
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
profileBackground = new UserCoverBackground(user)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
FillMode = FillMode.Fill,
|
||||
OnLoadComplete = d => d.FadeInFromZero(200),
|
||||
},
|
||||
dim = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.8f
|
||||
},
|
||||
profilePicture = new UpdateableAvatar
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Size = new Vector2(Height * 0.8f),
|
||||
Position = new Vector2(6, 0),
|
||||
User = user,
|
||||
Masking = true,
|
||||
CornerRadius = 6,
|
||||
},
|
||||
countryFlag = new DrawableFlag(country)
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Size = new Vector2(Height * 0.9f, (Height * 0.9f) * 0.66f),
|
||||
Position = new Vector2(-10, 0)
|
||||
},
|
||||
new SpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Position = new Vector2(Height * 1.1f, 0),
|
||||
TextSize = Height * 0.9f,
|
||||
Text = user.Username
|
||||
}
|
||||
};
|
||||
|
||||
Action = () =>
|
||||
{
|
||||
Process.Start("https://osu.ppy.sh/users/" + user.Id);
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
dim.FadeTo(0.6f, 200);
|
||||
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
base.OnHoverLost(state);
|
||||
|
||||
dim.FadeTo(0.8f, 200);
|
||||
}
|
||||
|
||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||
{
|
||||
new OsuMenuItem("View Profile", MenuItemType.Standard, () => { }),
|
||||
new OsuMenuItem("Promote to Host", MenuItemType.Highlighted, () => { }),
|
||||
new OsuMenuItem("Kick", MenuItemType.Destructive, () => { }),
|
||||
new OsuMenuItem("Ban", MenuItemType.Destructive, () => { }),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using OpenTK;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MatchPlayerList : Container
|
||||
{
|
||||
private readonly RulesetNetworkingClientHandler rulesetNetworkingClientHandler;
|
||||
|
||||
public readonly List<MatchPlayer> MatchPlayers = new List<MatchPlayer>();
|
||||
|
||||
public readonly FillFlowContainer MatchPlayersContianer;
|
||||
|
||||
public MatchPlayerList(RulesetNetworkingClientHandler rulesetNetworkingClientHandler)
|
||||
{
|
||||
this.rulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 16;
|
||||
Anchor = Anchor.TopLeft;
|
||||
Origin = Anchor.TopLeft;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Width = 0.49f;
|
||||
Height = 0.45f;
|
||||
Position = new Vector2(10);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.8f)
|
||||
},
|
||||
MatchPlayersContianer = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.98f,
|
||||
Height = 0.96f
|
||||
}
|
||||
};
|
||||
|
||||
rulesetNetworkingClientHandler.OnReceivePlayerList += (players) =>
|
||||
{
|
||||
restart:
|
||||
foreach (MatchPlayer matchPlayer in MatchPlayers)
|
||||
foreach (ClientInfo clientInfo in players)
|
||||
if (clientInfo is RulesetClientInfo rulesetClientInfo)
|
||||
if (rulesetClientInfo.IP + rulesetClientInfo.Port != matchPlayer.ClientInfo.IP + matchPlayer.ClientInfo.Port)
|
||||
{
|
||||
Add(rulesetClientInfo);
|
||||
players.Remove(clientInfo);
|
||||
goto restart;
|
||||
}
|
||||
};
|
||||
rulesetNetworkingClientHandler.RequestPlayerList();
|
||||
|
||||
rulesetNetworkingClientHandler.OnClientJoin += (clientInfo) =>
|
||||
{
|
||||
foreach (MatchPlayer matchPlayer in MatchPlayers)
|
||||
if (clientInfo is RulesetClientInfo rulesetClientInfo)
|
||||
if (rulesetClientInfo.IP + rulesetClientInfo.Port != matchPlayer.ClientInfo.IP + matchPlayer.ClientInfo.Port)
|
||||
{
|
||||
Add(rulesetClientInfo);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
rulesetNetworkingClientHandler.OnClientDisconnect += (clientInfo) =>
|
||||
{
|
||||
foreach (MatchPlayer matchPlayer in MatchPlayers)
|
||||
if (clientInfo is RulesetClientInfo rulesetClientInfo)
|
||||
if (rulesetClientInfo.IP + rulesetClientInfo.Port == matchPlayer.ClientInfo.IP + matchPlayer.ClientInfo.Port)
|
||||
{
|
||||
Remove(matchPlayer);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void Add(RulesetClientInfo clientInfo)
|
||||
{
|
||||
MatchPlayer matchPlayer = new MatchPlayer(clientInfo);
|
||||
|
||||
Add(matchPlayer);
|
||||
}
|
||||
|
||||
public void Add(MatchPlayer matchPlayer)
|
||||
{
|
||||
MatchPlayers.Add(matchPlayer);
|
||||
MatchPlayersContianer.Add(matchPlayer);
|
||||
matchPlayer.FadeInFromZero(200);
|
||||
}
|
||||
|
||||
public void Remove(MatchPlayer matchPlayer)
|
||||
{
|
||||
MatchPlayers.Remove(matchPlayer);
|
||||
matchPlayer.FadeOutFromOne(200)
|
||||
.Expire();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Screens.Symcol.Pieces;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Options;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MatchTools : Container
|
||||
{
|
||||
public readonly Bindable<MatchScreenMode> Mode = new Bindable<MatchScreenMode>() { Default = MatchScreenMode.MapDetails };
|
||||
|
||||
public readonly Bindable<MatchGamemode> GameMode = new Bindable<MatchGamemode>() { Default = MatchGamemode.HeadToHead };
|
||||
|
||||
public readonly OsuTabControl<MatchScreenMode> TabControl;
|
||||
|
||||
public readonly Container SelectedContent;
|
||||
|
||||
public readonly Container MapDetails;
|
||||
|
||||
public Container RulesetSettings;
|
||||
|
||||
public readonly Container SoundBoard;
|
||||
|
||||
private WorkingBeatmap selectedBeatmap;
|
||||
|
||||
private int selectedBeatmapSetID;
|
||||
|
||||
public MatchTools()
|
||||
{
|
||||
Masking = true;
|
||||
CornerRadius = 16;
|
||||
Anchor = Anchor.TopRight;
|
||||
Origin = Anchor.TopRight;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Width = 0.49f;
|
||||
Height = 0.45f;
|
||||
Position = new Vector2(-10, 10);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.8f)
|
||||
},
|
||||
TabControl = new OsuTabControl<MatchScreenMode>
|
||||
{
|
||||
Position = new Vector2(72, 0),
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.08f,
|
||||
Width = 0.8f
|
||||
},
|
||||
SelectedContent = new Container
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.92f
|
||||
}
|
||||
};
|
||||
TabControl.Current.Value = MatchScreenMode.MapDetails;
|
||||
|
||||
Mode.ValueChanged += (value) =>
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case MatchScreenMode.MapDetails:
|
||||
if (selectedBeatmap != null)
|
||||
SelectedContent.Child = new MapDetailsSection(selectedBeatmap);
|
||||
else if (selectedBeatmapSetID != 0)
|
||||
SelectedContent.Child = new MapDetailsSection(selectedBeatmapSetID);
|
||||
else
|
||||
SelectedContent.Child = new MapDetailsSection(true);
|
||||
break;
|
||||
case MatchScreenMode.MatchSettings:
|
||||
SelectedContent.Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new MultiplayerDropdownEnumOption<MatchGamemode>(GameMode, "Match Gamemode", 1)
|
||||
}
|
||||
};
|
||||
break;
|
||||
case MatchScreenMode.SoundBoard:
|
||||
SelectedContent.Child = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = new HitSoundBoard
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ButtonSize = 80
|
||||
}
|
||||
};
|
||||
break;
|
||||
}
|
||||
};
|
||||
Mode.BindTo(TabControl.Current);
|
||||
}
|
||||
|
||||
public void MapChange(WorkingBeatmap workingBeatmap)
|
||||
{
|
||||
if (workingBeatmap == null)
|
||||
{
|
||||
MapChange(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
selectedBeatmap = workingBeatmap;
|
||||
selectedBeatmapSetID = (int)workingBeatmap.BeatmapSetInfo.OnlineBeatmapSetID;
|
||||
|
||||
if (Mode.Value == MatchScreenMode.MapDetails)
|
||||
SelectedContent.Child = new MapDetailsSection(selectedBeatmap);
|
||||
}
|
||||
|
||||
public void MapChange(int onlineBeatmapSetID)
|
||||
{
|
||||
selectedBeatmap = null;
|
||||
selectedBeatmapSetID = onlineBeatmapSetID;
|
||||
|
||||
if (Mode.Value == MatchScreenMode.MapDetails)
|
||||
{
|
||||
if (selectedBeatmapSetID != 0 && selectedBeatmapSetID != -1)
|
||||
SelectedContent.Child = new MapDetailsSection(selectedBeatmapSetID);
|
||||
else
|
||||
SelectedContent.Child = new MapDetailsSection(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MapDetailsSection : ClickableContainer
|
||||
{
|
||||
private Sprite beatmapBG;
|
||||
private SpriteText name;
|
||||
private SpriteText artist;
|
||||
private SpriteText difficulty;
|
||||
private SpriteText time;
|
||||
|
||||
private Box dim;
|
||||
|
||||
public MapDetailsSection(WorkingBeatmap workingBeatmap)
|
||||
{
|
||||
draw();
|
||||
|
||||
HitObject lastObject = workingBeatmap.Beatmap.HitObjects.LastOrDefault();
|
||||
double endTime = (lastObject as IHasEndTime)?.EndTime ?? lastObject?.StartTime ?? 0;
|
||||
|
||||
beatmapBG.Texture = workingBeatmap.Background;
|
||||
name.Text = workingBeatmap.BeatmapSetInfo.Metadata.Title;
|
||||
artist.Text = "By: " + workingBeatmap.BeatmapSetInfo.Metadata.Artist;
|
||||
difficulty.Text = workingBeatmap.BeatmapInfo.Version + " (" + Math.Round(workingBeatmap.BeatmapInfo.StarDifficulty, 2) + " stars) mapped by " + workingBeatmap.BeatmapInfo.Metadata.AuthorString;
|
||||
time.Text = getBPMRange(workingBeatmap.Beatmap) + " bpm for " + TimeSpan.FromMilliseconds(endTime - workingBeatmap.Beatmap.HitObjects.First().StartTime).ToString(@"m\:ss");
|
||||
|
||||
BorderColour = getColour(workingBeatmap.BeatmapInfo);
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Radius = 16,
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = getColour(workingBeatmap.BeatmapInfo).Opacity(0.2f)
|
||||
};
|
||||
Action = () => Process.Start("https://osu.ppy.sh/beatmapsets/" + workingBeatmap.BeatmapSetInfo.OnlineBeatmapSetID);
|
||||
}
|
||||
|
||||
public MapDetailsSection(int onlineBeatmapSetID)
|
||||
{
|
||||
draw();
|
||||
name.Text = "Missing Map!";
|
||||
artist.Text = "Click to open in Browser";
|
||||
Action = () => Process.Start("https://osu.ppy.sh/beatmapsets/" + onlineBeatmapSetID);
|
||||
}
|
||||
|
||||
public MapDetailsSection(bool invalid)
|
||||
{
|
||||
draw();
|
||||
name.Text = "Invalid / No Map Selected!";
|
||||
artist.Text = "Don't hit start, weird things might happen";
|
||||
Action = () => Process.Start("https://osu.ppy.sh/home");
|
||||
}
|
||||
|
||||
private void draw()
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Width = 0.95f;
|
||||
Height = 0.9f;
|
||||
|
||||
Masking = true;
|
||||
BorderColour = Color4.LightBlue;
|
||||
BorderThickness = 4;
|
||||
CornerRadius = 10;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Radius = 16,
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.LightBlue.Opacity(0.2f)
|
||||
};
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
beatmapBG = new Sprite
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
},
|
||||
dim = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.6f
|
||||
},
|
||||
name = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, 0),
|
||||
Font = @"Exo2.0-SemiBoldItalic",
|
||||
TextSize = 40
|
||||
},
|
||||
artist = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, 38),
|
||||
Font = @"Exo2.0-MediumItalic",
|
||||
TextSize = 24
|
||||
},
|
||||
difficulty = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, 64),
|
||||
Font = "Exo2.0-Bold",
|
||||
TextSize = 16
|
||||
},
|
||||
time = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, 84),
|
||||
TextSize = 16
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
dim.FadeTo(0.4f, 200);
|
||||
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
base.OnHoverLost(state);
|
||||
|
||||
dim.FadeTo(0.6f, 200);
|
||||
}
|
||||
|
||||
//"Borrowed" stuff
|
||||
private string getBPMRange(Beatmap beatmap)
|
||||
{
|
||||
double bpmMax = beatmap.ControlPointInfo.BPMMaximum;
|
||||
double bpmMin = beatmap.ControlPointInfo.BPMMinimum;
|
||||
|
||||
if (Precision.AlmostEquals(bpmMin, bpmMax))
|
||||
return $"{bpmMin:0}";
|
||||
|
||||
return $"{bpmMin:0}-{bpmMax:0} (mostly {beatmap.ControlPointInfo.BPMMode:0})";
|
||||
}
|
||||
|
||||
private enum DifficultyRating
|
||||
{
|
||||
Easy,
|
||||
Normal,
|
||||
Hard,
|
||||
Insane,
|
||||
Expert,
|
||||
ExpertPlus
|
||||
}
|
||||
|
||||
private DifficultyRating getDifficultyRating(BeatmapInfo beatmap)
|
||||
{
|
||||
if (beatmap == null)
|
||||
throw new ArgumentNullException(nameof(beatmap));
|
||||
|
||||
var rating = beatmap.StarDifficulty;
|
||||
|
||||
if (rating < 1.5) return DifficultyRating.Easy;
|
||||
if (rating < 2.25) return DifficultyRating.Normal;
|
||||
if (rating < 3.75) return DifficultyRating.Hard;
|
||||
if (rating < 5.25) return DifficultyRating.Insane;
|
||||
if (rating < 6.75) return DifficultyRating.Expert;
|
||||
return DifficultyRating.ExpertPlus;
|
||||
}
|
||||
|
||||
private Color4 getColour(BeatmapInfo beatmap)
|
||||
{
|
||||
OsuColour palette = new OsuColour();
|
||||
switch (getDifficultyRating(beatmap))
|
||||
{
|
||||
case DifficultyRating.Easy:
|
||||
return palette.Green;
|
||||
default:
|
||||
case DifficultyRating.Normal:
|
||||
return palette.Blue;
|
||||
case DifficultyRating.Hard:
|
||||
return palette.Yellow;
|
||||
case DifficultyRating.Insane:
|
||||
return palette.Pink;
|
||||
case DifficultyRating.Expert:
|
||||
return palette.Purple;
|
||||
case DifficultyRating.ExpertPlus:
|
||||
return palette.Gray0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum MatchGamemode
|
||||
{
|
||||
[System.ComponentModel.Description("Head to Head")]
|
||||
HeadToHead,
|
||||
[System.ComponentModel.Description("Head to Head with Live Spectator")]
|
||||
HeadToHeadSpectator,
|
||||
[System.ComponentModel.Description("Team Versus")]
|
||||
TeamVS,
|
||||
[System.ComponentModel.Description("TAG4")]
|
||||
TAG4,
|
||||
[System.ComponentModel.Description("Team TAG4")]
|
||||
TeamTAG4,
|
||||
[System.ComponentModel.Description("Tourny Mode")]
|
||||
Tournement,
|
||||
}
|
||||
|
||||
public enum MatchScreenMode
|
||||
{
|
||||
[System.ComponentModel.Description("Map Details")]
|
||||
MapDetails,
|
||||
[System.ComponentModel.Description("Match Settings")]
|
||||
MatchSettings,
|
||||
[System.ComponentModel.Description("Ruleset Settings")]
|
||||
RulesetSettings,
|
||||
[System.ComponentModel.Description("Sound Board")]
|
||||
SoundBoard
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MultiplayerScoreboard : Container
|
||||
{
|
||||
public readonly Container<MultiplayerScoreboardItem> ScoreboardItems;
|
||||
|
||||
private readonly RulesetNetworkingClientHandler rulesetNetworkingClientHandler;
|
||||
|
||||
private readonly ScoreProcessor scoreProcessor;
|
||||
|
||||
private double updateScoreTime = 0;
|
||||
|
||||
public MultiplayerScoreboard(RulesetNetworkingClientHandler rulesetNetworkingClientHandler, List<ClientInfo> playerList, ScoreProcessor scoreProcessor)
|
||||
{
|
||||
this.rulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
this.scoreProcessor = scoreProcessor;
|
||||
|
||||
AlwaysPresent = true;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Width = 120;
|
||||
|
||||
Position = new Vector2(0, -200);
|
||||
Anchor = Anchor.CentreLeft;
|
||||
Origin = Anchor.TopLeft;
|
||||
|
||||
Child = ScoreboardItems = new Container<MultiplayerScoreboardItem>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
};
|
||||
|
||||
int i = 1;
|
||||
foreach (ClientInfo clientInfo in playerList)
|
||||
{
|
||||
if (clientInfo is RulesetClientInfo rulesetClientInfo)
|
||||
{
|
||||
ScoreboardItems.Add(new MultiplayerScoreboardItem(rulesetClientInfo, i) { });
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
rulesetNetworkingClientHandler.OnPacketReceive += (Packet packet) =>
|
||||
{
|
||||
if (packet is ScorePacket scorePacket)
|
||||
{
|
||||
rulesetNetworkingClientHandler.ShareWithOtherPeers(scorePacket);
|
||||
foreach (MultiplayerScoreboardItem item in ScoreboardItems)
|
||||
if (scorePacket.ClientInfo == item.ClientInfo)
|
||||
item.Score = scorePacket.Score;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (Time.Current >= updateScoreTime)
|
||||
{
|
||||
updateScoreTime = Time.Current + 500;
|
||||
foreach (MultiplayerScoreboardItem item in ScoreboardItems)
|
||||
if (rulesetNetworkingClientHandler.ClientInfo == item.ClientInfo)
|
||||
item.Score = (int)scoreProcessor.TotalScore.Value;
|
||||
|
||||
rulesetNetworkingClientHandler.SendToHost(new ScorePacket(rulesetNetworkingClientHandler.ClientInfo, (int)scoreProcessor.TotalScore.Value));
|
||||
rulesetNetworkingClientHandler.SendToInGameClients(new ScorePacket(rulesetNetworkingClientHandler.ClientInfo, (int)scoreProcessor.TotalScore.Value));
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
{
|
||||
if (args.Key == Key.Tab)
|
||||
{
|
||||
if (Alpha > 0)
|
||||
this.FadeOut(100);
|
||||
else
|
||||
this.FadeIn(100);
|
||||
}
|
||||
|
||||
return base.OnKeyDown(state, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Pieces
|
||||
{
|
||||
public class MultiplayerScoreboardItem : Container
|
||||
{
|
||||
public int Score
|
||||
{
|
||||
get { return score; }
|
||||
set
|
||||
{
|
||||
if (value != score)
|
||||
{
|
||||
score = value;
|
||||
scoreText.Text = value.ToString();
|
||||
|
||||
foreach(MultiplayerScoreboardItem item in itemList)
|
||||
if (value > item.Score && Place > item.Place)
|
||||
{
|
||||
Place = item.Place;
|
||||
foreach (MultiplayerScoreboardItem i in itemList)
|
||||
if (i.Place < Place)
|
||||
i.Place -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Place
|
||||
{
|
||||
get { return place; }
|
||||
set
|
||||
{
|
||||
if (Place != place)
|
||||
{
|
||||
place = value;
|
||||
this.MoveTo(new Vector2(0, (-height - 8) * (value - 1)), 200, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int place = 0;
|
||||
|
||||
private int score = 0;
|
||||
|
||||
private const int height = 60;
|
||||
|
||||
public readonly RulesetClientInfo ClientInfo;
|
||||
|
||||
private readonly SpriteText scoreText;
|
||||
|
||||
private static List<MultiplayerScoreboardItem> itemList = new List<MultiplayerScoreboardItem>();
|
||||
|
||||
public MultiplayerScoreboardItem(RulesetClientInfo clientInfo, int place)
|
||||
{
|
||||
ClientInfo = clientInfo;
|
||||
this.place = place;
|
||||
|
||||
itemList.Add(this);
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = height;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 8;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.8f,
|
||||
},
|
||||
new SpriteText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(4),
|
||||
Text = clientInfo.Username
|
||||
},
|
||||
scoreText = new SpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Position = new Vector2(-4),
|
||||
Text = Score.ToString()
|
||||
}
|
||||
};
|
||||
|
||||
this.MoveTo(new Vector2(0, (-height - 8) * (Place - 1)), 200, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
itemList.Remove(this);
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Screens.Select;
|
||||
using System;
|
||||
using osu.Game.Screens;
|
||||
using osu.Framework.Screens;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public class MatchSongSelect : SongSelect
|
||||
{
|
||||
public WorkingBeatmap SelectedMap;
|
||||
|
||||
private bool exiting;
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => null;
|
||||
|
||||
public Action Action;
|
||||
|
||||
public readonly RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
public MatchSongSelect(RulesetNetworkingClientHandler rulesetNetworkingClientHandler)
|
||||
{
|
||||
RulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
Add(RulesetNetworkingClientHandler);
|
||||
base.OnEntering(last);
|
||||
}
|
||||
|
||||
protected override bool OnSelectionFinalised()
|
||||
{
|
||||
if (!exiting)
|
||||
{
|
||||
RulesetNetworkingClientHandler.OnMapChange?.Invoke(null);
|
||||
SelectedMap = Beatmap.Value;
|
||||
Action();
|
||||
exiting = true;
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
Exit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osu.Game.Storyboards.Drawables;
|
||||
using OpenTK;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Play;
|
||||
using OpenTK.Input;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Pieces;
|
||||
using System.Collections.Generic;
|
||||
using Symcol.Core.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public class MultiPlayer : ScreenWithBeatmapBackground, IProvideCursor
|
||||
{
|
||||
public readonly RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
protected override BackgroundScreen CreateBackground() => new BackgroundScreenBeatmap(Beatmap);
|
||||
|
||||
protected override float BackgroundParallaxAmount => 0.1f;
|
||||
|
||||
public override bool ShowOverlaysOnEnter => false;
|
||||
|
||||
public Action RestartRequested;
|
||||
|
||||
public override bool AllowBeatmapRulesetChange => false;
|
||||
|
||||
public bool HasFailed { get; private set; }
|
||||
|
||||
public bool AllowPause { get; set; } = false;
|
||||
public bool AllowLeadIn { get; set; } = true;
|
||||
public bool AllowResults { get; set; } = true;
|
||||
|
||||
public int RestartCount;
|
||||
|
||||
public CursorContainer Cursor => RulesetContainer.Cursor;
|
||||
public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded.Value;
|
||||
|
||||
private IAdjustableClock sourceClock;
|
||||
private DecoupleableInterpolatingFramedClock adjustableClock;
|
||||
|
||||
private RulesetInfo ruleset;
|
||||
|
||||
private APIAccess api;
|
||||
|
||||
private ScoreProcessor scoreProcessor;
|
||||
protected RulesetContainer RulesetContainer;
|
||||
|
||||
#region User Settings
|
||||
|
||||
private Bindable<double> dimLevel;
|
||||
private Bindable<double> blurLevel;
|
||||
private Bindable<bool> showStoryboard;
|
||||
private Bindable<bool> mouseWheelDisabled;
|
||||
private Bindable<double> userAudioOffset;
|
||||
|
||||
private SampleChannel sampleRestart;
|
||||
|
||||
#endregion
|
||||
|
||||
private Container storyboardContainer;
|
||||
private DrawableStoryboard storyboard;
|
||||
|
||||
private HUDOverlay hudOverlay;
|
||||
|
||||
private MultiplayerScoreboard scoreboard;
|
||||
|
||||
private bool loadedSuccessfully => RulesetContainer?.Objects.Any() == true;
|
||||
|
||||
private readonly List<ClientInfo> playerList;
|
||||
|
||||
public MultiPlayer(RulesetNetworkingClientHandler rulesetNetworkingClientHandler, List<ClientInfo> playerList)//, WorkingBeatmap beatmap = null)
|
||||
{
|
||||
RulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
RulesetNetworkingClientHandler.OnAbort = () => Exit();
|
||||
RulesetNetworkingClientHandler.StartGame = () => start();
|
||||
this.playerList = playerList;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, APIAccess api, OsuConfigManager config)
|
||||
{
|
||||
this.api = api;
|
||||
|
||||
dimLevel = config.GetBindable<double>(OsuSetting.DimLevel);
|
||||
blurLevel = config.GetBindable<double>(OsuSetting.BlurLevel);
|
||||
showStoryboard = config.GetBindable<bool>(OsuSetting.ShowStoryboard);
|
||||
|
||||
mouseWheelDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableWheel);
|
||||
|
||||
sampleRestart = audio.Sample.Get(@"Gameplay/restart");
|
||||
userAudioOffset = config.GetBindable<double>(OsuSetting.AudioOffset);
|
||||
|
||||
WorkingBeatmap working = Beatmap.Value;
|
||||
Beatmap beatmap;
|
||||
|
||||
try
|
||||
{
|
||||
beatmap = working.Beatmap;
|
||||
|
||||
if (beatmap == null)
|
||||
throw new InvalidOperationException("Beatmap was not loaded");
|
||||
|
||||
ruleset = Ruleset.Value ?? beatmap.BeatmapInfo.Ruleset;
|
||||
var rulesetInstance = ruleset.CreateInstance();
|
||||
|
||||
try
|
||||
{
|
||||
RulesetContainer = rulesetInstance.CreateRulesetContainerWith(working, ruleset.ID == beatmap.BeatmapInfo.Ruleset.ID);
|
||||
}
|
||||
catch (BeatmapInvalidForRulesetException)
|
||||
{
|
||||
// we may fail to create a RulesetContainer if the beatmap cannot be loaded with the user's preferred ruleset
|
||||
// let's try again forcing the beatmap's ruleset.
|
||||
ruleset = beatmap.BeatmapInfo.Ruleset;
|
||||
rulesetInstance = ruleset.CreateInstance();
|
||||
RulesetContainer = rulesetInstance.CreateRulesetContainerWith(Beatmap, true);
|
||||
}
|
||||
|
||||
if (!RulesetContainer.Objects.Any())
|
||||
throw new InvalidOperationException("Beatmap contains no hit objects!");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, "Could not load beatmap sucessfully!");
|
||||
|
||||
//couldn't load, hard abort!
|
||||
Exit();
|
||||
return;
|
||||
}
|
||||
|
||||
sourceClock = (IAdjustableClock)working.Track ?? new StopwatchClock();
|
||||
adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
||||
|
||||
var firstObjectTime = RulesetContainer.Objects.First().StartTime;
|
||||
adjustableClock.Seek(AllowLeadIn
|
||||
? Math.Min(0, firstObjectTime - Math.Max(beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, beatmap.BeatmapInfo.AudioLeadIn))
|
||||
: firstObjectTime);
|
||||
|
||||
adjustableClock.ProcessFrame();
|
||||
|
||||
// the final usable gameplay clock with user-set offsets applied.
|
||||
var offsetClock = new FramedOffsetClock(adjustableClock);
|
||||
|
||||
userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
|
||||
userAudioOffset.TriggerChange();
|
||||
|
||||
scoreProcessor = RulesetContainer.CreateScoreProcessor();
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = offsetClock,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
storyboardContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
},
|
||||
RulesetContainer,
|
||||
hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, working, offsetClock, adjustableClock)
|
||||
{
|
||||
Clock = Clock, // hud overlay doesn't want to use the audio clock directly
|
||||
ProcessCustomClock = false,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
},
|
||||
new BreakOverlay(beatmap.BeatmapInfo.LetterboxInBreaks, scoreProcessor)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ProcessCustomClock = false,
|
||||
Breaks = beatmap.Breaks
|
||||
},
|
||||
scoreboard = new MultiplayerScoreboard(RulesetNetworkingClientHandler, playerList, scoreProcessor)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (showStoryboard)
|
||||
initializeStoryboard(false);
|
||||
|
||||
// Bind ScoreProcessor to ourselves
|
||||
scoreProcessor.AllJudged += onCompletion;
|
||||
scoreProcessor.Failed += onFail;
|
||||
|
||||
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToScoreProcessor>())
|
||||
mod.ApplyToScoreProcessor(scoreProcessor);
|
||||
}
|
||||
|
||||
private void applyRateFromMods()
|
||||
{
|
||||
if (sourceClock == null) return;
|
||||
|
||||
sourceClock.Rate = 1;
|
||||
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToClock>())
|
||||
mod.ApplyToClock(sourceClock);
|
||||
}
|
||||
|
||||
private void initializeStoryboard(bool asyncLoad)
|
||||
{
|
||||
if (storyboardContainer == null)
|
||||
return;
|
||||
|
||||
var beatmap = Beatmap.Value;
|
||||
|
||||
storyboard = beatmap.Storyboard.CreateDrawable();
|
||||
storyboard.Masking = true;
|
||||
|
||||
if (asyncLoad)
|
||||
LoadComponentAsync(storyboard, storyboardContainer.Add);
|
||||
else
|
||||
storyboardContainer.Add(storyboard);
|
||||
}
|
||||
|
||||
private ScheduledDelegate onCompletionEvent;
|
||||
|
||||
private void onCompletion()
|
||||
{
|
||||
// Only show the completion screen if the player hasn't failed
|
||||
if (scoreProcessor.HasFailed || onCompletionEvent != null)
|
||||
return;
|
||||
|
||||
ValidForResume = false;
|
||||
|
||||
if (!AllowResults) return;
|
||||
|
||||
using (BeginDelayedSequence(1000))
|
||||
{
|
||||
onCompletionEvent = Schedule(delegate
|
||||
{
|
||||
if (!IsCurrentScreen) return;
|
||||
|
||||
var score = new Score
|
||||
{
|
||||
Beatmap = Beatmap.Value.BeatmapInfo,
|
||||
Ruleset = ruleset
|
||||
};
|
||||
scoreProcessor.PopulateScore(score);
|
||||
score.User = RulesetContainer.Replay?.User ?? api.LocalUser.Value;
|
||||
Push(new Results(score));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private bool onFail()
|
||||
{
|
||||
if (Beatmap.Value.Mods.Value.OfType<IApplicableFailOverride>().Any(m => !m.AllowFail))
|
||||
return false;
|
||||
|
||||
HasFailed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
|
||||
Add(RulesetNetworkingClientHandler);
|
||||
|
||||
if (!loadedSuccessfully)
|
||||
return;
|
||||
|
||||
Content.Alpha = 0;
|
||||
Content
|
||||
.ScaleTo(0.7f)
|
||||
.ScaleTo(1, 750, Easing.OutQuint)
|
||||
.Delay(250)
|
||||
.FadeIn(250);
|
||||
|
||||
Task.Run(() =>
|
||||
{
|
||||
sourceClock.Reset();
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
adjustableClock.ChangeSource(sourceClock);
|
||||
applyRateFromMods();
|
||||
|
||||
this.Delay(750).Schedule(() =>
|
||||
{
|
||||
Logger.Log("Client finnished loading", LoggingTarget.Network, LogLevel.Verbose);
|
||||
RulesetNetworkingClientHandler.GameLoaded();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private void start()
|
||||
{
|
||||
adjustableClock.Start();
|
||||
}
|
||||
|
||||
protected override void OnSuspending(Screen next)
|
||||
{
|
||||
fadeOut();
|
||||
base.OnSuspending(next);
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
fadeOut();
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
|
||||
protected override void UpdateBackgroundElements()
|
||||
{
|
||||
if (!IsCurrentScreen) return;
|
||||
|
||||
base.UpdateBackgroundElements();
|
||||
|
||||
if (ShowStoryboard && storyboard == null)
|
||||
initializeStoryboard(true);
|
||||
|
||||
var beatmap = Beatmap.Value;
|
||||
var storyboardVisible = ShowStoryboard && beatmap.Storyboard.HasDrawable;
|
||||
|
||||
storyboardContainer?
|
||||
.FadeColour(OsuColour.Gray(BackgroundOpacity), BACKGROUND_FADE_DURATION, Easing.OutQuint)
|
||||
.FadeTo(storyboardVisible && BackgroundOpacity > 0 ? 1 : 0, BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
||||
|
||||
if (storyboardVisible && beatmap.Storyboard.ReplacesBackground)
|
||||
Background?.FadeTo(0, BACKGROUND_FADE_DURATION, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void fadeOut()
|
||||
{
|
||||
const float fade_out_duration = 250;
|
||||
|
||||
RulesetContainer?.FadeOut(fade_out_duration);
|
||||
Content.FadeOut(fade_out_duration);
|
||||
|
||||
hudOverlay?.ScaleTo(0.7f, fade_out_duration * 3, Easing.In);
|
||||
|
||||
Background?.FadeTo(1f, fade_out_duration);
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
{
|
||||
if (args.Key == Key.Escape)
|
||||
BackOut();
|
||||
|
||||
return base.OnKeyDown(state, args);
|
||||
}
|
||||
|
||||
public void BackOut()
|
||||
{
|
||||
RulesetNetworkingClientHandler.AbortGame();
|
||||
RulesetNetworkingClientHandler.OnAbort();
|
||||
}
|
||||
|
||||
protected override bool OnWheel(InputState state) => mouseWheelDisabled.Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Screens;
|
||||
using System;
|
||||
using osu.Framework.Screens;
|
||||
using System.Collections.Generic;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public abstract class RulesetLobbyScreen : OsuScreen
|
||||
{
|
||||
public abstract string RulesetName { get; }
|
||||
|
||||
public abstract RulesetMatchScreen MatchScreen { get; }
|
||||
|
||||
public RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
public readonly SettingsButton HostGameButton;
|
||||
public readonly SettingsButton DirectConnectButton;
|
||||
public readonly SettingsButton JoinGameButton;
|
||||
|
||||
public readonly Container NewGame;
|
||||
protected readonly TextBox HostIP;
|
||||
protected readonly TextBox HostPort;
|
||||
//protected readonly TextBox PublicIp;
|
||||
protected readonly TextBox LocalIp;
|
||||
|
||||
public readonly Container JoinIP;
|
||||
|
||||
public RulesetLobbyScreen()
|
||||
{
|
||||
AlwaysPresent = true;
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
HostGameButton = new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.3f,
|
||||
Text = "Host Game",
|
||||
Action = HostGame
|
||||
},
|
||||
DirectConnectButton = new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.3f,
|
||||
Text = "Direct Connect",
|
||||
Action = DirectConnect
|
||||
},
|
||||
JoinGameButton = new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.3f,
|
||||
Text = "Join Game"
|
||||
},
|
||||
NewGame = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Masking = true,
|
||||
Size = new Vector2(400, 300),
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Blue,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
},
|
||||
HostIP = new TextBox
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
Text = "Host IP Address"
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
},
|
||||
HostPort = new TextBox
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
Text = "25570"
|
||||
},
|
||||
/*
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Position = new Vector2(0, 22),
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
},
|
||||
PublicIp = new TextBox
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Position = new Vector2(0, 22),
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
Text = "You're Public IP Address"
|
||||
},
|
||||
*/
|
||||
new Box
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Position = new Vector2(0, 44),
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
},
|
||||
LocalIp = new TextBox
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Position = new Vector2(0, 44),
|
||||
Width = 0.48f,
|
||||
Height = 20,
|
||||
Text = "You're Local IP Address"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
MakeCurrent();
|
||||
}
|
||||
|
||||
protected override void OnResuming(Screen last)
|
||||
{
|
||||
base.OnResuming(last);
|
||||
MakeCurrent();
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
{
|
||||
if (RulesetNetworkingClientHandler != null)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.Dispose();
|
||||
}
|
||||
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
|
||||
protected virtual void HostGame()
|
||||
{
|
||||
if (RulesetNetworkingClientHandler != null)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.Dispose();
|
||||
}
|
||||
Add(RulesetNetworkingClientHandler = new RulesetNetworkingClientHandler(ClientType.Host, LocalIp.Text, Int32.Parse(HostPort.Text)));
|
||||
|
||||
List<ClientInfo> list = new List<ClientInfo>();
|
||||
list.Add(RulesetNetworkingClientHandler.RulesetClientInfo);
|
||||
|
||||
JoinMatch(list);
|
||||
}
|
||||
|
||||
protected virtual void DirectConnect()
|
||||
{
|
||||
if (RulesetNetworkingClientHandler != null)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.Dispose();
|
||||
}
|
||||
Add(RulesetNetworkingClientHandler = new RulesetNetworkingClientHandler(ClientType.Peer, HostIP.Text, Int32.Parse(HostPort.Text), LocalIp.Text));
|
||||
|
||||
RulesetNetworkingClientHandler.OnConnectedToHost += (p) => JoinMatch(p);
|
||||
}
|
||||
|
||||
protected virtual void JoinMatch(List<ClientInfo> clientInfos)
|
||||
{
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
MakeCurrent();
|
||||
Push(MatchScreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Screens;
|
||||
using Symcol.Core.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Pieces;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public abstract class RulesetMatchScreen : OsuScreen
|
||||
{
|
||||
public readonly RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
private readonly MatchPlayerList playerList;
|
||||
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
protected MatchTools MatchTools;
|
||||
|
||||
private readonly Chat chat;
|
||||
|
||||
public RulesetMatchScreen(RulesetNetworkingClientHandler rulesetNetworkingClientHandler)
|
||||
{
|
||||
RulesetNetworkingClientHandler = rulesetNetworkingClientHandler;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.35f,
|
||||
Text = "Leave",
|
||||
Action = () => Exit()
|
||||
},
|
||||
new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.3f,
|
||||
Text = "Open Song Select",
|
||||
Action = () => openSongSelect()
|
||||
},
|
||||
new SettingsButton
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.35f,
|
||||
Text = "Start Match",
|
||||
Action = () => RulesetNetworkingClientHandler.StartLoadingGame()
|
||||
},
|
||||
playerList = new MatchPlayerList(RulesetNetworkingClientHandler),
|
||||
MatchTools = new MatchTools(),
|
||||
chat = new Chat(RulesetNetworkingClientHandler)
|
||||
};
|
||||
|
||||
RulesetNetworkingClientHandler.OnPacketReceive += (Packet packet) =>
|
||||
{
|
||||
if (packet is RulesetPacket rulesetPacket && rulesetPacket.OnlineBeatmapID != -1)
|
||||
foreach (BeatmapSetInfo beatmapSet in beatmaps.GetAllUsableBeatmapSets())
|
||||
if (beatmapSet.OnlineBeatmapSetID == rulesetPacket.OnlineBeatmapSetID)
|
||||
{
|
||||
foreach (BeatmapInfo beatmap in beatmapSet.Beatmaps)
|
||||
if (beatmap.OnlineBeatmapID == rulesetPacket.OnlineBeatmapID)
|
||||
{
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
|
||||
Beatmap.Value.Track.Start();
|
||||
MatchTools.MapChange(Beatmap);
|
||||
RulesetNetworkingClientHandler.OnMapChange?.Invoke(Beatmap);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
MatchTools.MapChange(rulesetPacket.OnlineBeatmapSetID);
|
||||
};
|
||||
|
||||
RulesetNetworkingClientHandler.OnMapChange += (beatmap) => MatchTools.MapChange(beatmap);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
playerList.Add(RulesetNetworkingClientHandler.RulesetClientInfo);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapManager beatmaps)
|
||||
{
|
||||
this.beatmaps = beatmaps;
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
MakeCurrent();
|
||||
Add(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.OnLoadGame = (i) => Load(i);
|
||||
}
|
||||
|
||||
protected override void OnResuming(Screen last)
|
||||
{
|
||||
base.OnResuming(last);
|
||||
MakeCurrent();
|
||||
if (RulesetNetworkingClientHandler != null)
|
||||
Add(RulesetNetworkingClientHandler);
|
||||
}
|
||||
|
||||
protected override void OnSuspending(Screen next)
|
||||
{
|
||||
base.OnSuspending(next);
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
{
|
||||
RulesetNetworkingClientHandler.Disconnect();
|
||||
Remove(RulesetNetworkingClientHandler);
|
||||
RulesetNetworkingClientHandler.Dispose();
|
||||
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
|
||||
protected virtual void Load(List<ClientInfo> playerList)
|
||||
{
|
||||
MakeCurrent();
|
||||
Push(new MultiPlayer(RulesetNetworkingClientHandler, playerList));
|
||||
}
|
||||
|
||||
private void openSongSelect()
|
||||
{
|
||||
MatchSongSelect songSelect = new MatchSongSelect(RulesetNetworkingClientHandler);
|
||||
MakeCurrent();
|
||||
Push(songSelect);
|
||||
songSelect.Action = () => RulesetNetworkingClientHandler.SetMap(songSelect.SelectedMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
//osu.Game.Screens.Symcol.SymcolMenu
|
||||
//Symcol.Rulesets.Core.SymcolSettingsSubsection
|
||||
#define SymcolMods
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Symcol;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Multiplayer.Screens
|
||||
{
|
||||
public class RulesetMultiplayerSelection : OsuScreen
|
||||
{
|
||||
public static readonly FillFlowContainer<RulesetLobbyItem> LobbyItems = new FillFlowContainer<RulesetLobbyItem>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.85f,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
};
|
||||
|
||||
public RulesetMultiplayerSelection()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Add(LobbyItems);
|
||||
}
|
||||
|
||||
protected override void OnEntering(Screen last)
|
||||
{
|
||||
base.OnEntering(last);
|
||||
foreach (RulesetLobbyItem item in LobbyItems)
|
||||
item.Action = () => Push(item.RulesetLobbyScreen);
|
||||
}
|
||||
|
||||
protected override bool OnExiting(Screen next)
|
||||
{
|
||||
Remove(LobbyItems);
|
||||
|
||||
#if SymcolMods
|
||||
SymcolSettingsSubsection.RulesetMultiplayerSelection = new RulesetMultiplayerSelection();
|
||||
|
||||
SymcolMenu.RulesetMultiplayerScreen = SymcolSettingsSubsection.RulesetMultiplayerSelection;
|
||||
#endif
|
||||
|
||||
return base.OnExiting(next);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class RulesetLobbyItem : ClickableContainer
|
||||
{
|
||||
public abstract Texture Icon { get; }
|
||||
|
||||
public abstract string RulesetName { get; }
|
||||
|
||||
public virtual Texture Background { get; }
|
||||
|
||||
public abstract RulesetLobbyScreen RulesetLobbyScreen { get; }
|
||||
|
||||
public RulesetLobbyItem()
|
||||
{
|
||||
CornerRadius = 20;
|
||||
Masking = true;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 100;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Sprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Texture = Background
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
new Sprite
|
||||
{
|
||||
Size = new Vector2(Height),
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Texture = Icon
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Text = RulesetName,
|
||||
TextSize = 60,
|
||||
Position = new Vector2(-20, 0)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-14
@@ -1,38 +1,34 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("osu.Game.Modes.Taiko")]
|
||||
[assembly: AssemblyTitle("Symcol.Rulesets.Core")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("osu.Game.Modes.Taiko")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyProduct("Symcol.Rulesets.Core")]
|
||||
[assembly: AssemblyCopyright("Copyright © Shawdooow 2018")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("f167e17a-7de6-4af5-b920-a5112296c695")]
|
||||
[assembly: Guid("552b5940-c647-4060-aa4d-61baac415c72")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
@@ -0,0 +1,97 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.IO.Stores;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Skinning
|
||||
{
|
||||
public abstract class SkinElement : Container
|
||||
{
|
||||
private static string loadedSkin;
|
||||
|
||||
private static ResourceStore<byte[]> skinResources;
|
||||
private static TextureStore skinTextures;
|
||||
|
||||
/// <summary>
|
||||
/// Will attempt to get a skin element fron the skin, if no element is found return the default element
|
||||
/// </summary>
|
||||
/// <param name="stockTextures"></param>
|
||||
/// <param name="skin"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="storage"></param>
|
||||
/// <returns></returns>
|
||||
public static Texture GetSkinElement(TextureStore stockTextures, Bindable<string> skin, string fileName, Storage storage)
|
||||
{
|
||||
Texture texture = null;
|
||||
|
||||
string fileNameHd = fileName + "@2x";
|
||||
|
||||
Storage skinStorage = storage.GetStorageForDirectory("Skins\\" + skin);
|
||||
|
||||
if (skin.Value == "default")
|
||||
{
|
||||
texture = stockTextures.Get(fileName + ".png");
|
||||
|
||||
if (texture == null)
|
||||
texture = stockTextures.Get(fileNameHd + ".png");
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
if (loadedSkin != skin.ToString())
|
||||
{
|
||||
loadedSkin = skin.ToString();
|
||||
skinResources = new ResourceStore<byte[]>(new StorageBackedResourceStore(skinStorage));
|
||||
skinTextures = new TextureStore(new RawTextureLoaderStore(skinResources));
|
||||
}
|
||||
|
||||
if (skinStorage.Exists(fileNameHd + ".png"))
|
||||
texture = skinTextures.Get(fileNameHd + ".png");
|
||||
else if (skinStorage.Exists(fileName + ".png"))
|
||||
{
|
||||
texture = skinTextures.Get(fileName + ".png");
|
||||
texture.ScaleAdjust = 1f;
|
||||
}
|
||||
else
|
||||
texture = stockTextures.Get(fileNameHd + ".png");
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Will attempt to get a skin element from the skin, if no element is found return null
|
||||
/// </summary>
|
||||
/// <param name="skin"></param>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="storage"></param>
|
||||
/// <returns></returns>
|
||||
public static Texture GetElement(Bindable<string> skin, string fileName, Storage storage)
|
||||
{
|
||||
Texture texture = null;
|
||||
|
||||
string fileNameHd = fileName + "@2x";
|
||||
|
||||
Storage skinStorage = storage.GetStorageForDirectory("Skins\\" + skin);
|
||||
|
||||
if (loadedSkin != skin.ToString())
|
||||
{
|
||||
loadedSkin = skin.ToString();
|
||||
skinResources = new ResourceStore<byte[]>(new StorageBackedResourceStore(skinStorage));
|
||||
skinTextures = new TextureStore(new RawTextureLoaderStore(skinResources));
|
||||
}
|
||||
|
||||
if (skinStorage.Exists(fileNameHd + ".png"))
|
||||
texture = skinTextures.Get(fileNameHd + ".png");
|
||||
else if (skinStorage.Exists(fileName + ".png"))
|
||||
{
|
||||
texture = skinTextures.Get(fileName + ".png");
|
||||
texture.ScaleAdjust = 1f;
|
||||
}
|
||||
else
|
||||
texture = null;
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Skinning
|
||||
{
|
||||
public class SkinConfigReader<T> : IniConfigManager<T>
|
||||
where T : struct
|
||||
{
|
||||
protected override string Filename => @"skin.ini";
|
||||
|
||||
public SkinConfigReader(Storage storage) : base(storage) { }
|
||||
|
||||
protected override bool PerformSave() { return false; }
|
||||
}
|
||||
|
||||
//wildly incomplete
|
||||
public enum ClassicIniParameters
|
||||
{
|
||||
Name,
|
||||
Author,
|
||||
CursorRotate,
|
||||
CursorExpand,
|
||||
CursorCentre
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{552B5940-C647-4060-AA4D-61BAAC415C72}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Symcol.Rulesets.Core</RootNamespace>
|
||||
<AssemblyName>Symcol.Rulesets.Core</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Containers\LinkText.cs" />
|
||||
<Compile Include="Containers\ProfileLink.cs" />
|
||||
<Compile Include="HitObjects\DrawableSymcolHitObject.cs" />
|
||||
<Compile Include="Multiplayer\Networking\ScorePacket.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\Chat.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\ChatMessage.cs" />
|
||||
<Compile Include="Multiplayer\Networking\ChatPacket.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MatchTools.cs" />
|
||||
<Compile Include="Multiplayer\Networking\RulesetClientInfo.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MatchPlayer.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MatchPlayerList.cs" />
|
||||
<Compile Include="Multiplayer\Options\MultiplayerDropdownEnumOption.cs" />
|
||||
<Compile Include="Multiplayer\Options\MultiplayerOption.cs" />
|
||||
<Compile Include="Multiplayer\Options\MultiplayerToggleOption.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MultiplayerScoreboard.cs" />
|
||||
<Compile Include="Multiplayer\Pieces\MultiplayerScoreboardItem.cs" />
|
||||
<Compile Include="Multiplayer\Screens\MatchSongSelect.cs" />
|
||||
<Compile Include="Multiplayer\Screens\MultiPlayer.cs" />
|
||||
<Compile Include="Multiplayer\Screens\RulesetLobbyScreen.cs" />
|
||||
<Compile Include="Multiplayer\Screens\RulesetMatchScreen.cs" />
|
||||
<Compile Include="Multiplayer\Screens\RulesetMultiplayerSelection.cs" />
|
||||
<Compile Include="Multiplayer\Networking\RulesetNetworkingClientHandler.cs" />
|
||||
<Compile Include="Multiplayer\Networking\RulesetPacket.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Skinning\SkinElement.cs" />
|
||||
<Compile Include="Skinning\SkinIniReader.cs" />
|
||||
<Compile Include="SymcolConfigManager.cs" />
|
||||
<Compile Include="SymcolPlayfield.cs" />
|
||||
<Compile Include="SymcolSettingsSubsection.cs" />
|
||||
<Compile Include="SymcolInputManager.cs" />
|
||||
<Compile Include="VectorVideos\VectorVideo.cs" />
|
||||
<Compile Include="Wiki\WikiOptionEnumExplanation.cs" />
|
||||
<Compile Include="Wiki\WikiParagraph.cs" />
|
||||
<Compile Include="Wiki\WikiSubSectionHeader.cs" />
|
||||
<Compile Include="Wiki\WikiOverlay.cs" />
|
||||
<Compile Include="Wiki\WikiHeader.cs" />
|
||||
<Compile Include="Wiki\WikiSection.cs" />
|
||||
<Compile Include="Wiki\WikiSubSectionLinkHeader.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\osu-Framework\osu.Framework\osu.Framework.csproj">
|
||||
<Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
|
||||
<Name>osu.Framework</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
|
||||
<Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
|
||||
<Name>osu.Game.Resources</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
|
||||
<Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
|
||||
<Name>osu.Game</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Symcol.Core\Symcol.Core.csproj">
|
||||
<Project>{F34AC16C-E590-4D70-A069-A748326852BF}</Project>
|
||||
<Name>Symcol.Core</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
@@ -0,0 +1,22 @@
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace Symcol.Rulesets.Core
|
||||
{
|
||||
public class SymcolConfigManager : IniConfigManager<SymcolSetting>
|
||||
{
|
||||
protected override string Filename => "symcol.ini";
|
||||
|
||||
public SymcolConfigManager(Storage storage) : base(storage) { }
|
||||
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
Set(SymcolSetting.PlayerColor, "#ffffff");
|
||||
}
|
||||
}
|
||||
|
||||
public enum SymcolSetting
|
||||
{
|
||||
PlayerColor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using Symcol.Rulesets.Core.VectorVideos;
|
||||
|
||||
namespace Symcol.Rulesets.Core
|
||||
{
|
||||
public class SymcolInputManager<T> : RulesetInputManager<T>
|
||||
where T : struct
|
||||
{
|
||||
protected virtual bool VectorVideo => false;
|
||||
|
||||
public SymcolInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique)
|
||||
{
|
||||
Child = new VectorVideo();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using OpenTK;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Networking;
|
||||
|
||||
namespace Symcol.Rulesets.Core
|
||||
{
|
||||
public class SymcolPlayfield : Playfield
|
||||
{
|
||||
public static RulesetNetworkingClientHandler RulesetNetworkingClientHandler;
|
||||
|
||||
public SymcolPlayfield(Vector2 size) : base(size.X)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//osu.Game.Screens.Symcol.SymcolMenu
|
||||
//Symcol.Rulesets.Core.Multiplayer.Screens.RulesetMultiplayerSelection
|
||||
#define SymcolMods
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using Symcol.Rulesets.Core.Wiki;
|
||||
using osu.Game.Screens.Symcol;
|
||||
using Symcol.Rulesets.Core.Multiplayer.Screens;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Logging;
|
||||
|
||||
namespace Symcol.Rulesets.Core
|
||||
{
|
||||
public abstract class SymcolSettingsSubsection : SettingsSubsection
|
||||
{
|
||||
public virtual WikiOverlay Wiki => null;
|
||||
|
||||
public virtual RulesetLobbyItem RulesetLobbyItem => null;
|
||||
|
||||
#if SymcolMods
|
||||
public static RulesetMultiplayerSelection RulesetMultiplayerSelection;
|
||||
#endif
|
||||
|
||||
public static SymcolConfigManager SymcolConfigManager;
|
||||
|
||||
private OsuGame osu;
|
||||
|
||||
public SymcolSettingsSubsection()
|
||||
{
|
||||
|
||||
#if SymcolMods
|
||||
if (RulesetLobbyItem != null)
|
||||
RulesetMultiplayerSelection.LobbyItems.Add(RulesetLobbyItem);
|
||||
|
||||
if (RulesetMultiplayerSelection == null)
|
||||
RulesetMultiplayerSelection = new RulesetMultiplayerSelection();
|
||||
|
||||
SymcolMenu.RulesetMultiplayerScreen = RulesetMultiplayerSelection;
|
||||
#endif
|
||||
#if !SymcolMods
|
||||
Logger.Log("osu.Game mods not installed! Online Multiplayer will not be avalible without them. . .", LoggingTarget.Information, LogLevel.Important);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGame osu, Storage storage)
|
||||
{
|
||||
this.osu = osu;
|
||||
|
||||
if (SymcolConfigManager == null)
|
||||
SymcolConfigManager = new SymcolConfigManager(storage);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
if (Wiki != null)
|
||||
osu.Add(Wiki);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Rulesets.Core.VectorVideos
|
||||
{
|
||||
public class VectorVideo : BeatSyncedContainer
|
||||
{
|
||||
public const string FILE_NAME = "VectorVideo.symcol";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(Storage storage)
|
||||
{
|
||||
}
|
||||
|
||||
protected void LoadContent(string args)
|
||||
{
|
||||
string[] parameters = args.Split(',');
|
||||
|
||||
ObjectType objectType = ObjectType.LogoVisualizer;
|
||||
Anchor anchor = Anchor.Centre;
|
||||
Anchor origin = Anchor.Centre;
|
||||
|
||||
bool checkingType = false;
|
||||
|
||||
foreach (string parameter in parameters)
|
||||
{
|
||||
string[] subParameters = parameter.Split('=');
|
||||
|
||||
foreach (string subParameter in subParameters)
|
||||
{
|
||||
if (subParameter == "Type")
|
||||
checkingType = true;
|
||||
|
||||
if (checkingType)
|
||||
switch (subParameter)
|
||||
{
|
||||
case "LogoVisualizer":
|
||||
objectType = ObjectType.LogoVisualizer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadLogoVisualizer()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public enum ObjectType
|
||||
{
|
||||
LogoVisualizer
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using OpenTK.Graphics;
|
||||
using Symcol.Rulesets.Core.Containers;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public abstract class WikiHeader : Container
|
||||
{
|
||||
protected abstract Texture RulesetIcon { get; }
|
||||
|
||||
protected abstract string RulesetName { get; }
|
||||
|
||||
protected abstract string RulesetDescription { get; }
|
||||
|
||||
protected virtual string RulesetUrl => $@"https://osu.ppy.sh/home";
|
||||
|
||||
protected virtual User Creator => null;
|
||||
|
||||
protected virtual User Maintainer => null;
|
||||
|
||||
protected virtual string DiscordInvite => $@"https://discord.gg/ppy";
|
||||
|
||||
protected virtual Texture HeaderBackground => null;
|
||||
|
||||
private const float description_height = 150;
|
||||
private const float description_width = 220;
|
||||
private const float icon_size = 200;
|
||||
private const float header_margin = 50;
|
||||
private const float rulesetname_height = 60;
|
||||
|
||||
public WikiHeader()
|
||||
{
|
||||
Masking = true;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = header_margin + icon_size + rulesetname_height;
|
||||
|
||||
|
||||
var user = Creator;
|
||||
bool maintainer = false;
|
||||
string userTitle = "Creator";
|
||||
if (Creator == null)
|
||||
{
|
||||
user = Maintainer;
|
||||
maintainer = true;
|
||||
userTitle = "Maintainer";
|
||||
}
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Sprite
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Texture = HeaderBackground
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
new Sprite
|
||||
{
|
||||
Size = new Vector2(icon_size),
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Texture = RulesetIcon
|
||||
},
|
||||
new LinkText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, icon_size),
|
||||
Text = RulesetName,
|
||||
Url = RulesetUrl,
|
||||
Font = @"Exo2.0-RegularItalic",
|
||||
TextSize = rulesetname_height
|
||||
},
|
||||
new ProfileLink(user, maintainer)
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, icon_size + rulesetname_height),
|
||||
},
|
||||
new LinkText
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Position = new Vector2(10, icon_size + rulesetname_height + 20),
|
||||
Text = userTitle + "'s Discord server",
|
||||
Url = DiscordInvite,
|
||||
Font = @"Exo2.0-RegularItalic",
|
||||
TextSize = 16
|
||||
},
|
||||
new OsuTextFlowContainer(t => { t.TextSize = 20; })
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Size = new Vector2(description_width, description_height),
|
||||
Text = RulesetDescription
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Overlays.Settings;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public class WikiOptionEnumExplanation<T> : Container
|
||||
where T : struct
|
||||
{
|
||||
public OsuTextFlowContainer Description;
|
||||
|
||||
public WikiOptionEnumExplanation(Bindable<T> bindable)
|
||||
{
|
||||
OsuColour osu = new OsuColour();
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Masking = true;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = osu.Yellow,
|
||||
Masking = true,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Size = new Vector2(10, 0.98f),
|
||||
CornerRadius = 5,
|
||||
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Position = new Vector2(-10, 0),
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.45f,
|
||||
|
||||
Child = new SettingsEnumDropdown<T>
|
||||
{
|
||||
Bindable = bindable
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.45f,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
AutoSizeDuration = 100,
|
||||
AutoSizeEasing = Easing.OutQuint,
|
||||
|
||||
Child = Description = new OsuTextFlowContainer(t => { t.TextSize = 20; })
|
||||
{
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using System.Linq;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public abstract class WikiOverlay : WaveOverlayContainer
|
||||
{
|
||||
protected abstract WikiHeader Header { get; }
|
||||
protected abstract WikiSection[] Sections { get; }
|
||||
|
||||
private WikiSection lastSection;
|
||||
private SectionsContainer<WikiSection> sectionsContainer;
|
||||
private WikiTabControl tabs;
|
||||
|
||||
public const float CONTENT_X_MARGIN = 100;
|
||||
|
||||
public WikiOverlay()
|
||||
{
|
||||
FirstWaveColour = OsuColour.Gray(0.4f);
|
||||
SecondWaveColour = OsuColour.Gray(0.3f);
|
||||
ThirdWaveColour = OsuColour.Gray(0.2f);
|
||||
FourthWaveColour = OsuColour.Gray(0.1f);
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
RelativePositionAxes = Axes.Both;
|
||||
Width = 0.85f;
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
|
||||
Masking = true;
|
||||
AlwaysPresent = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 10
|
||||
};
|
||||
|
||||
tabs = new WikiTabControl
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Height = 30
|
||||
};
|
||||
|
||||
Add(new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.Gray(0.2f)
|
||||
});
|
||||
|
||||
Add(sectionsContainer = new SectionsContainer<WikiSection>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ExpandableHeader = Header,
|
||||
FixedHeader = tabs,
|
||||
HeaderBackground = new Box
|
||||
{
|
||||
Colour = OsuColour.Gray(34),
|
||||
RelativeSizeAxes = Axes.Both
|
||||
}
|
||||
});
|
||||
|
||||
sectionsContainer.SelectedSection.ValueChanged += s =>
|
||||
{
|
||||
if (lastSection != s)
|
||||
{
|
||||
lastSection = s;
|
||||
tabs.Current.Value = lastSection;
|
||||
}
|
||||
};
|
||||
|
||||
tabs.Current.ValueChanged += s =>
|
||||
{
|
||||
if (lastSection == null)
|
||||
{
|
||||
lastSection = sectionsContainer.Children.FirstOrDefault();
|
||||
if (lastSection != null)
|
||||
tabs.Current.Value = lastSection;
|
||||
return;
|
||||
}
|
||||
if (lastSection != s)
|
||||
{
|
||||
lastSection = s;
|
||||
sectionsContainer.ScrollTo(lastSection);
|
||||
}
|
||||
};
|
||||
|
||||
foreach (WikiSection sec in Sections)
|
||||
{
|
||||
if (sec != null)
|
||||
{
|
||||
sectionsContainer.Add(sec);
|
||||
tabs.AddItem(sec);
|
||||
}
|
||||
}
|
||||
|
||||
sectionsContainer.ScrollToTop();
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
base.PopIn();
|
||||
FadeEdgeEffectTo(0.5f, APPEAR_DURATION, Easing.In);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
FadeEdgeEffectTo(0, DISAPPEAR_DURATION, Easing.Out);
|
||||
}
|
||||
|
||||
private class WikiTabControl : PageTabControl<WikiSection>
|
||||
{
|
||||
public WikiTabControl()
|
||||
{
|
||||
TabContainer.RelativeSizeAxes &= ~Axes.X;
|
||||
TabContainer.AutoSizeAxes |= Axes.X;
|
||||
TabContainer.Anchor |= Anchor.x1;
|
||||
TabContainer.Origin |= Anchor.x1;
|
||||
}
|
||||
|
||||
protected override TabItem<WikiSection> CreateTabItem(WikiSection value) => new WikiTabItem(value);
|
||||
|
||||
protected override Dropdown<WikiSection> CreateDropdown() => null;
|
||||
|
||||
private class WikiTabItem : PageTabItem
|
||||
{
|
||||
public WikiTabItem(WikiSection value) : base(value)
|
||||
{
|
||||
Text.Text = value.Title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public class WikiParagraph : Container
|
||||
{
|
||||
public WikiParagraph(string text, float textsize = 20)
|
||||
{
|
||||
paragraphNoMarkdown(text, textsize);
|
||||
}
|
||||
|
||||
public WikiParagraph(string text, bool markdown)
|
||||
{
|
||||
if (!markdown)
|
||||
paragraphNoMarkdown(text, 20);
|
||||
else
|
||||
paragraphMarkdown(text, 20);
|
||||
}
|
||||
public WikiParagraph(string text, float textsize, bool markdown)
|
||||
{
|
||||
if (!markdown)
|
||||
paragraphNoMarkdown(text, textsize);
|
||||
else
|
||||
paragraphMarkdown(text, textsize);
|
||||
}
|
||||
|
||||
private void paragraphNoMarkdown(string text, float textsize)
|
||||
{
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Child = new OsuTextFlowContainer(t => { t.TextSize = textsize; })
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Text = text
|
||||
};
|
||||
}
|
||||
|
||||
private void paragraphMarkdown(string text, float textsize)
|
||||
{
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Child = new OsuTextFlowContainer(t => { t.TextSize = textsize; })
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Text = text
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public abstract class WikiSection : FillFlowContainer
|
||||
{
|
||||
public abstract string Title { get; }
|
||||
|
||||
private readonly FillFlowContainer content;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
protected WikiSection()
|
||||
{
|
||||
OsuColour osu = new OsuColour();
|
||||
Direction = FillDirection.Vertical;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Colour = osu.Yellow,
|
||||
Text = Title,
|
||||
TextSize = 32,
|
||||
Font = @"Exo2.0-Bold",
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
Horizontal = WikiOverlay.CONTENT_X_MARGIN,
|
||||
Vertical = 12
|
||||
}
|
||||
},
|
||||
content = new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Horizontal = WikiOverlay.CONTENT_X_MARGIN,
|
||||
Bottom = 20
|
||||
}
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 1,
|
||||
Colour = OsuColour.Gray(34),
|
||||
EdgeSmoothness = new Vector2(1)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public class WikiSubSectionHeader : OsuSpriteText
|
||||
{
|
||||
public WikiSubSectionHeader(string text)
|
||||
{
|
||||
OsuColour osu = new OsuColour();
|
||||
Colour = osu.Pink;
|
||||
Text = text;
|
||||
TextSize = 24;
|
||||
Font = @"Exo2.0-BoldItalic";
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
Vertical = 10
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using Symcol.Rulesets.Core.Containers;
|
||||
|
||||
namespace Symcol.Rulesets.Core.Wiki
|
||||
{
|
||||
public class WikiSubSectionLinkHeader : LinkText
|
||||
{
|
||||
public override string Tooltip => tooltip;
|
||||
|
||||
private string tooltip = "";
|
||||
|
||||
public WikiSubSectionLinkHeader(string text, string url, string tooltip = "")
|
||||
{
|
||||
this.tooltip = tooltip;
|
||||
Url = url;
|
||||
OsuColour osu = new OsuColour();
|
||||
Colour = osu.Pink;
|
||||
Text = text;
|
||||
TextSize = 24;
|
||||
Font = @"Exo2.0-BoldItalic";
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
Vertical = 10
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
# 2017-09-14
|
||||
clone_depth: 1
|
||||
version: '{branch}-{build}'
|
||||
image: Visual Studio 2017
|
||||
configuration: Debug
|
||||
cache:
|
||||
- C:\ProgramData\chocolatey\bin -> appveyor.yml
|
||||
- C:\ProgramData\chocolatey\lib -> appveyor.yml
|
||||
- inspectcode -> appveyor.yml
|
||||
- packages -> **\packages.config
|
||||
install:
|
||||
- cmd: git submodule update --init --recursive --depth=5
|
||||
- cmd: choco install resharper-clt -y
|
||||
- cmd: choco install nvika -y
|
||||
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.4/CodeFileSanity.exe
|
||||
before_build:
|
||||
- cmd: CodeFileSanity.exe
|
||||
- cmd: nuget restore -verbosity quiet
|
||||
build:
|
||||
project: osu.sln
|
||||
parallel: true
|
||||
verbosity: minimal
|
||||
test:
|
||||
assemblies:
|
||||
only:
|
||||
- 'osu.Desktop\**\*.dll'
|
||||
after_build:
|
||||
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
|
||||
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
|
||||
+1
-1
Submodule osu-framework updated: 659cb25892...d8d4f55e10
+1
-1
Submodule osu-resources updated: 51f2b9b37f...6e145ed502
@@ -1,4 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<configuration>
|
||||
<appSettings>
|
||||
<add key="StagingFolder" value="Staging" />
|
||||
@@ -9,7 +13,7 @@
|
||||
<add key="ProjectName" value="osu.Desktop" />
|
||||
<add key="NuSpecName" value="osu.Desktop\osu.nuspec" />
|
||||
<add key="SolutionName" value="osu" />
|
||||
<add key="TargetName" value="Client\osu.Desktop" />
|
||||
<add key="TargetName" value="osu.Desktop" />
|
||||
<add key="PackageName" value="osulazer" />
|
||||
<add key="IconName" value="lazer.ico" />
|
||||
<add key="CodeSigningCertificate" value="" />
|
||||
@@ -19,9 +23,17 @@
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="DeltaCompressionDotNet.MsDelta" publicKeyToken="46b2138a390abf55" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="SharpCompress" publicKeyToken="afb0a02973931d96" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-0.18.1.0" newVersion="0.18.1.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using Newtonsoft.Json;
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace osu.Desktop.Deploy
|
||||
{
|
||||
internal class GitHubObject
|
||||
public class GitHubObject
|
||||
{
|
||||
[JsonProperty(@"id")]
|
||||
public int Id;
|
||||
@@ -10,4 +13,4 @@ namespace osu.Desktop.Deploy
|
||||
[JsonProperty(@"name")]
|
||||
public string Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
using Newtonsoft.Json;
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace osu.Desktop.Deploy
|
||||
{
|
||||
internal class GitHubRelease
|
||||
public class GitHubRelease
|
||||
{
|
||||
[JsonProperty(@"id")]
|
||||
public int Id;
|
||||
@@ -22,4 +25,4 @@ namespace osu.Desktop.Deploy
|
||||
[JsonProperty(@"upload_url")]
|
||||
public string UploadUrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.GitHubusercontent.com/ppy/osu-framework/master/LICENCE
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -7,7 +7,6 @@ using System.Configuration;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.IO.Network;
|
||||
using FileWebRequest = osu.Framework.IO.Network.FileWebRequest;
|
||||
@@ -17,9 +16,9 @@ namespace osu.Desktop.Deploy
|
||||
{
|
||||
internal static class Program
|
||||
{
|
||||
private const string nuget_path = @"packages\NuGet.CommandLine.3.5.0\tools\NuGet.exe";
|
||||
private const string squirrel_path = @"packages\squirrel.windows.1.5.2\tools\Squirrel.exe";
|
||||
private const string msbuild_path = @"C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe";
|
||||
private const string nuget_path = @"packages\NuGet.CommandLine.4.3.0\tools\NuGet.exe";
|
||||
private const string squirrel_path = @"packages\squirrel.windows.1.7.8\tools\Squirrel.exe";
|
||||
private const string msbuild_path = @"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe";
|
||||
|
||||
public static string StagingFolder = ConfigurationManager.AppSettings["StagingFolder"];
|
||||
public static string ReleasesFolder = ConfigurationManager.AppSettings["ReleasesFolder"];
|
||||
@@ -29,7 +28,7 @@ namespace osu.Desktop.Deploy
|
||||
public static string SolutionName = ConfigurationManager.AppSettings["SolutionName"];
|
||||
public static string ProjectName = ConfigurationManager.AppSettings["ProjectName"];
|
||||
public static string NuSpecName = ConfigurationManager.AppSettings["NuSpecName"];
|
||||
public static string TargetName = ConfigurationManager.AppSettings["TargetName"];
|
||||
public static string TargetNames = ConfigurationManager.AppSettings["TargetName"];
|
||||
public static string PackageName = ConfigurationManager.AppSettings["PackageName"];
|
||||
public static string IconName = ConfigurationManager.AppSettings["IconName"];
|
||||
public static string CodeSigningCertificate = ConfigurationManager.AppSettings["CodeSigningCertificate"];
|
||||
@@ -40,7 +39,7 @@ namespace osu.Desktop.Deploy
|
||||
/// <summary>
|
||||
/// How many previous build deltas we want to keep when publishing.
|
||||
/// </summary>
|
||||
const int keep_delta_count = 3;
|
||||
private const int keep_delta_count = 3;
|
||||
|
||||
private static string codeSigningCmd => string.IsNullOrEmpty(codeSigningPassword) ? "" : $"-n \"/a /f {codeSigningCertPath} /p {codeSigningPassword} /t http://timestamp.comodoca.com/authenticode\"";
|
||||
|
||||
@@ -53,7 +52,7 @@ namespace osu.Desktop.Deploy
|
||||
private static string nupkgFilename(string ver) => $"{PackageName}.{ver}.nupkg";
|
||||
private static string nupkgDistroFilename(string ver) => $"{PackageName}-{ver}-full.nupkg";
|
||||
|
||||
private static Stopwatch sw = new Stopwatch();
|
||||
private static readonly Stopwatch sw = new Stopwatch();
|
||||
|
||||
private static string codeSigningPassword;
|
||||
|
||||
@@ -74,7 +73,7 @@ namespace osu.Desktop.Deploy
|
||||
refreshDirectory(StagingFolder);
|
||||
|
||||
//increment build number until we have a unique one.
|
||||
string verBase = DateTime.Now.ToString("yyyy.Md.");
|
||||
string verBase = DateTime.Now.ToString("yyyy.Mdd.");
|
||||
int increment = 0;
|
||||
while (Directory.GetFiles(ReleasesFolder, $"*{verBase}{increment}*").Any())
|
||||
increment++;
|
||||
@@ -100,7 +99,8 @@ namespace osu.Desktop.Deploy
|
||||
updateAssemblyInfo(version);
|
||||
|
||||
write("Running build process...");
|
||||
runCommand(msbuild_path, $"/v:quiet /m /t:{TargetName.Replace('.', '_')} /p:OutputPath={stagingPath};Configuration=Release {SolutionName}.sln");
|
||||
foreach (string targetName in TargetNames.Split(','))
|
||||
runCommand(msbuild_path, $"/v:quiet /m /t:{targetName.Replace('.', '_')} /p:OutputPath={stagingPath};Targets=\"Clean;Build\";Configuration=Release {SolutionName}.sln");
|
||||
|
||||
write("Creating NuGet deployment package...");
|
||||
runCommand(nuget_path, $"pack {NuSpecName} -Version {version} -Properties Configuration=Deploy -OutputDirectory {stagingPath} -BasePath {stagingPath}");
|
||||
@@ -145,6 +145,8 @@ namespace osu.Desktop.Deploy
|
||||
/// </summary>
|
||||
private static void checkReleaseFiles()
|
||||
{
|
||||
if (!canGitHub) return;
|
||||
|
||||
var releaseLines = getReleaseLines();
|
||||
|
||||
//ensure we have all files necessary
|
||||
@@ -157,6 +159,8 @@ namespace osu.Desktop.Deploy
|
||||
|
||||
private static void pruneReleases()
|
||||
{
|
||||
if (!canGitHub) return;
|
||||
|
||||
write("Pruning RELEASES...");
|
||||
|
||||
var releaseLines = getReleaseLines().ToList();
|
||||
@@ -172,10 +176,10 @@ namespace osu.Desktop.Deploy
|
||||
}
|
||||
|
||||
//remove excess deltas
|
||||
var deltas = releaseLines.Where(l => l.Filename.Contains("-delta"));
|
||||
if (deltas.Count() > keep_delta_count)
|
||||
var deltas = releaseLines.Where(l => l.Filename.Contains("-delta")).ToArray();
|
||||
if (deltas.Length > keep_delta_count)
|
||||
{
|
||||
foreach (var l in deltas.Take(deltas.Count() - keep_delta_count))
|
||||
foreach (var l in deltas.Take(deltas.Length - keep_delta_count))
|
||||
{
|
||||
write($"- Removing old delta {l.Filename}", ConsoleColor.Yellow);
|
||||
File.Delete(Path.Combine(ReleasesFolder, l.Filename));
|
||||
@@ -190,7 +194,7 @@ namespace osu.Desktop.Deploy
|
||||
|
||||
private static void uploadBuild(string version)
|
||||
{
|
||||
if (string.IsNullOrEmpty(GitHubAccessToken) || string.IsNullOrEmpty(codeSigningCertPath))
|
||||
if (!canGitHub || string.IsNullOrEmpty(CodeSigningCertificate))
|
||||
return;
|
||||
|
||||
write("Publishing to GitHub...");
|
||||
@@ -198,7 +202,7 @@ namespace osu.Desktop.Deploy
|
||||
write($"- Creating release {version}...", ConsoleColor.Yellow);
|
||||
var req = new JsonWebRequest<GitHubRelease>($"{GitHubApiEndpoint}")
|
||||
{
|
||||
Method = HttpMethod.POST
|
||||
Method = HttpMethod.POST,
|
||||
};
|
||||
req.AddRaw(JsonConvert.SerializeObject(new GitHubRelease
|
||||
{
|
||||
@@ -215,6 +219,7 @@ namespace osu.Desktop.Deploy
|
||||
var upload = new WebRequest(assetUploadUrl, Path.GetFileName(a))
|
||||
{
|
||||
Method = HttpMethod.POST,
|
||||
Timeout = 240000,
|
||||
ContentType = "application/octet-stream",
|
||||
};
|
||||
|
||||
@@ -227,8 +232,12 @@ namespace osu.Desktop.Deploy
|
||||
|
||||
private static void openGitHubReleasePage() => Process.Start(GitHubReleasePage);
|
||||
|
||||
private static bool canGitHub => !string.IsNullOrEmpty(GitHubAccessToken);
|
||||
|
||||
private static void checkGitHubReleases()
|
||||
{
|
||||
if (!canGitHub) return;
|
||||
|
||||
write("Checking GitHub releases...");
|
||||
var req = new JsonWebRequest<List<GitHubRelease>>($"{GitHubApiEndpoint}");
|
||||
req.AuthenticatedBlockingPerform();
|
||||
@@ -261,7 +270,7 @@ namespace osu.Desktop.Deploy
|
||||
|
||||
if (!File.Exists(Path.Combine(ReleasesFolder, nupkgDistroFilename(lastRelease.Name))))
|
||||
{
|
||||
write("Last verion's package not found locally.", ConsoleColor.Red);
|
||||
write("Last version's package not found locally.", ConsoleColor.Red);
|
||||
requireDownload = true;
|
||||
}
|
||||
else
|
||||
@@ -282,6 +291,8 @@ namespace osu.Desktop.Deploy
|
||||
|
||||
foreach (var a in assets)
|
||||
{
|
||||
if (a.Name.EndsWith(".exe")) continue;
|
||||
|
||||
write($"- Downloading {a.Name}...", ConsoleColor.Yellow);
|
||||
new FileWebRequest(Path.Combine(ReleasesFolder, a.Name), $"{GitHubApiEndpoint}/assets/{a.Id}").AuthenticatedBlockingPerform();
|
||||
}
|
||||
@@ -337,12 +348,17 @@ namespace osu.Desktop.Deploy
|
||||
WorkingDirectory = solutionPath,
|
||||
CreateNoWindow = true,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
WindowStyle = ProcessWindowStyle.Hidden
|
||||
};
|
||||
|
||||
Process p = Process.Start(psi);
|
||||
if (p == null) return false;
|
||||
|
||||
string output = p.StandardOutput.ReadToEnd();
|
||||
output += p.StandardError.ReadToEnd();
|
||||
|
||||
if (p.ExitCode == 0) return true;
|
||||
|
||||
write(output);
|
||||
@@ -383,7 +399,7 @@ namespace osu.Desktop.Deploy
|
||||
public static void AuthenticatedBlockingPerform(this WebRequest r)
|
||||
{
|
||||
r.AddHeader("Authorization", $"token {GitHubAccessToken}");
|
||||
r.BlockingPerform();
|
||||
r.Perform();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,12 +409,7 @@ namespace osu.Desktop.Deploy
|
||||
{
|
||||
}
|
||||
|
||||
protected override HttpWebRequest CreateWebRequest(string requestString = null)
|
||||
{
|
||||
var req = base.CreateWebRequest(requestString);
|
||||
req.Accept = "application/octet-stream";
|
||||
return req;
|
||||
}
|
||||
protected override string Accept => "application/octet-stream";
|
||||
}
|
||||
|
||||
internal class ReleaseLine
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("osu.Desktop.Deploy")]
|
||||
@@ -14,8 +16,8 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
@@ -25,11 +27,11 @@ using System.Runtime.InteropServices;
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Import Project="..\osu.Game.props" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
@@ -9,7 +9,7 @@
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>osu.Desktop.Deploy</RootNamespace>
|
||||
<AssemblyName>osu.Desktop.Deploy</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
@@ -36,52 +36,52 @@
|
||||
<StartupObject>osu.Desktop.Deploy.Program</StartupObject>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="DeltaCompressionDotNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.dll</HintPath>
|
||||
<Reference Include="DeltaCompressionDotNet, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="DeltaCompressionDotNet.MsDelta, Version=1.0.0.0, Culture=neutral, PublicKeyToken=46b2138a390abf55, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.MsDelta.dll</HintPath>
|
||||
<Reference Include="DeltaCompressionDotNet.MsDelta, Version=1.1.0.0, Culture=neutral, PublicKeyToken=46b2138a390abf55, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.MsDelta.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="DeltaCompressionDotNet.PatchApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3e8888ee913ed789, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.PatchApi.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\squirrel.windows.1.5.2\lib\Net45\ICSharpCode.SharpZipLib.dll</HintPath>
|
||||
<Reference Include="DeltaCompressionDotNet.PatchApi, Version=1.1.0.0, Culture=neutral, PublicKeyToken=3e8888ee913ed789, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Cecil, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.dll</HintPath>
|
||||
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Cecil.Mdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
|
||||
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Cecil.Pdb, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
|
||||
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Mono.Cecil.Rocks, Version=0.9.6.0, Culture=neutral, PublicKeyToken=0738eb9f132ed756, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
|
||||
<HintPath>$(SolutionDir)\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="NuGet.Squirrel, Version=3.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\squirrel.windows.1.5.2\lib\Net45\NuGet.Squirrel.dll</HintPath>
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Splat, Version=1.6.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Splat.1.6.2\lib\Net45\Splat.dll</HintPath>
|
||||
<Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\SharpCompress.0.18.1\lib\net45\SharpCompress.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Squirrel, Version=1.5.2.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\squirrel.windows.1.5.2\lib\Net45\Squirrel.dll</HintPath>
|
||||
<Reference Include="Splat, Version=2.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Squirrel, Version=1.7.8.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\Squirrel.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
@@ -101,21 +101,19 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="App.config">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework.Desktop\osu.Framework.Desktop.csproj">
|
||||
<Project>{65dc628f-a640-4111-ab35-3a5652bc1e17}</Project>
|
||||
<Name>osu.Framework.Desktop</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
|
||||
<Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
|
||||
<Name>osu.Framework</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<packages>
|
||||
<package id="DeltaCompressionDotNet" version="1.0.0" targetFramework="net452" />
|
||||
<package id="Mono.Cecil" version="0.9.6.1" targetFramework="net452" />
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
|
||||
<package id="NuGet.CommandLine" version="3.5.0" targetFramework="net452" developmentDependency="true" />
|
||||
<package id="Splat" version="1.6.2" targetFramework="net452" />
|
||||
<package id="squirrel.windows" version="1.5.2" targetFramework="net452" />
|
||||
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net452" />
|
||||
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net452" />
|
||||
<package id="Newtonsoft.Json" version="10.0.3" targetFramework="net461" />
|
||||
<package id="NuGet.CommandLine" version="4.3.0" targetFramework="net461" developmentDependency="true" />
|
||||
<package id="SharpCompress" version="0.18.1" targetFramework="net461" />
|
||||
<package id="Splat" version="2.0.0" targetFramework="net452" />
|
||||
<package id="squirrel.windows" version="1.7.8" targetFramework="net461" />
|
||||
</packages>
|
||||
@@ -1,33 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Desktop.VisualTests;
|
||||
using osu.Framework.Desktop.Platform;
|
||||
using osu.Game.Modes;
|
||||
using osu.Game.Modes.Catch;
|
||||
using osu.Game.Modes.Mania;
|
||||
using osu.Game.Modes.Osu;
|
||||
using osu.Game.Modes.Taiko;
|
||||
|
||||
namespace osu.Desktop.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class BenchmarkTest
|
||||
{
|
||||
[Test]
|
||||
public void TestBenchmark()
|
||||
{
|
||||
using (var host = new HeadlessGameHost())
|
||||
{
|
||||
Ruleset.Register(new OsuRuleset());
|
||||
Ruleset.Register(new TaikoRuleset());
|
||||
Ruleset.Register(new ManiaRuleset());
|
||||
Ruleset.Register(new CatchRuleset());
|
||||
|
||||
host.Add(new Benchmark());
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<configuration>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -1,120 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{230AC4F3-7783-49FB-9AEC-B83CDA3B9F3D}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>osu.Desktop.Tests</RootNamespace>
|
||||
<AssemblyName>osu.Desktop.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="nunit.framework, Version=3.5.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.3.5.0\lib\net45\nunit.framework.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLiteNetExtensions">
|
||||
<HintPath>$(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net.Platform.Win32">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net.Platform.Generic">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net40\SQLite.Net.Platform.Generic.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1339\lib\net45\OpenTK.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BenchmarkTest.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework.Desktop\osu.Framework.Desktop.csproj">
|
||||
<Project>{65DC628F-A640-4111-AB35-3A5652BC1E17}</Project>
|
||||
<Name>osu.Framework.Desktop</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
|
||||
<Project>{C76BF5B3-985E-4D39-95FE-97C9C879B83A}</Project>
|
||||
<Name>osu.Framework</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
|
||||
<Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
|
||||
<Name>osu.Game.Resources</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Desktop.VisualTests\osu.Desktop.VisualTests.csproj">
|
||||
<Project>{69051C69-12AE-4E7D-A3E6-460D2E282312}</Project>
|
||||
<Name>osu.Desktop.VisualTests</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game.Modes.Catch\osu.Game.Modes.Catch.csproj">
|
||||
<Project>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</Project>
|
||||
<Name>osu.Game.Modes.Catch</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game.Modes.Mania\osu.Game.Modes.Mania.csproj">
|
||||
<Project>{48F4582B-7687-4621-9CBE-5C24197CB536}</Project>
|
||||
<Name>osu.Game.Modes.Mania</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game.Modes.Osu\osu.Game.Modes.Osu.csproj">
|
||||
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
|
||||
<Name>osu.Game.Modes.Osu</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game.Modes.Taiko\osu.Game.Modes.Taiko.csproj">
|
||||
<Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project>
|
||||
<Name>osu.Game.Modes.Taiko</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
|
||||
<Project>{0D3FBF8A-7464-4CF7-8C90-3E7886DF2D4D}</Project>
|
||||
<Name>osu.Game</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\osu.licenseheader">
|
||||
<Link>osu.licenseheader</Link>
|
||||
</None>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
|
||||
<package id="NUnit" version="3.5.0" targetFramework="net45" />
|
||||
<package id="SQLite.Net.Core-PCL" version="3.1.1" targetFramework="net45" />
|
||||
<package id="SQLite.Net-PCL" version="3.1.1" targetFramework="net45" />
|
||||
<package id="SQLiteNetExtensions" version="1.3.0" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Desktop.Platform;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Game;
|
||||
using osu.Game.Modes;
|
||||
using osu.Game.Modes.Catch;
|
||||
using osu.Game.Modes.Mania;
|
||||
using osu.Game.Modes.Osu;
|
||||
using osu.Game.Modes.Taiko;
|
||||
|
||||
namespace osu.Desktop.VisualTests
|
||||
{
|
||||
public class Benchmark : OsuGameBase
|
||||
{
|
||||
private double timePerTest = 200;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BaseGame game)
|
||||
{
|
||||
Host.MaximumDrawHz = int.MaxValue;
|
||||
Host.MaximumUpdateHz = int.MaxValue;
|
||||
Host.MaximumInactiveHz = int.MaxValue;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
TestBrowser f = new TestBrowser();
|
||||
Add(f);
|
||||
|
||||
Console.WriteLine($@"{Time}: Running {f.TestCount} tests for {timePerTest}ms each...");
|
||||
|
||||
for (int i = 1; i < f.TestCount; i++)
|
||||
{
|
||||
int loadableCase = i;
|
||||
Scheduler.AddDelayed(delegate
|
||||
{
|
||||
f.LoadTest(loadableCase);
|
||||
Console.WriteLine($@"{Time}: Switching to test #{loadableCase}");
|
||||
}, loadableCase * timePerTest);
|
||||
}
|
||||
|
||||
Scheduler.AddDelayed(Host.Exit, f.TestCount * timePerTest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework;
|
||||
using osu.Framework.Desktop.Platform;
|
||||
using SQLite.Net;
|
||||
using SQLite.Net.Interop;
|
||||
using SQLite.Net.Platform.Generic;
|
||||
using SQLite.Net.Platform.Win32;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Platform
|
||||
{
|
||||
public class TestStorage : DesktopStorage
|
||||
{
|
||||
public TestStorage(string baseName) : base(baseName)
|
||||
{
|
||||
}
|
||||
|
||||
public override SQLiteConnection GetDatabase(string name)
|
||||
{
|
||||
ISQLitePlatform platform;
|
||||
if (RuntimeInfo.IsWindows)
|
||||
platform = new SQLitePlatformWin32();
|
||||
else
|
||||
platform = new SQLitePlatformGeneric();
|
||||
return new SQLiteConnection(platform, $@":memory:");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Desktop;
|
||||
using osu.Framework.Desktop.Platform;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Modes;
|
||||
using osu.Game.Modes.Catch;
|
||||
using osu.Game.Modes.Mania;
|
||||
using osu.Game.Modes.Osu;
|
||||
using osu.Game.Modes.Taiko;
|
||||
|
||||
namespace osu.Desktop.VisualTests
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
bool benchmark = args.Length > 0 && args[0] == @"-benchmark";
|
||||
|
||||
using (BasicGameHost host = Host.GetSuitableHost(@"osu"))
|
||||
{
|
||||
Ruleset.Register(new OsuRuleset());
|
||||
Ruleset.Register(new TaikoRuleset());
|
||||
Ruleset.Register(new ManiaRuleset());
|
||||
Ruleset.Register(new CatchRuleset());
|
||||
|
||||
if (benchmark)
|
||||
host.Add(new Benchmark());
|
||||
else
|
||||
host.Add(new VisualTestGame());
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using osu.Framework;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.Chat;
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Online.Chat.Drawables;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseChatDisplay : TestCase
|
||||
{
|
||||
private ScheduledDelegate messageRequest;
|
||||
|
||||
public override string Name => @"Chat";
|
||||
public override string Description => @"Testing API polling";
|
||||
|
||||
FlowContainer flow;
|
||||
|
||||
private Scheduler scheduler = new Scheduler();
|
||||
|
||||
private APIAccess api;
|
||||
|
||||
private ChannelDisplay channelDisplay;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api)
|
||||
{
|
||||
this.api = api;
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
if (api.State != APIState.Online)
|
||||
api.OnStateChange += delegate { initializeChannels(); };
|
||||
else
|
||||
initializeChannels();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
scheduler.Update();
|
||||
base.Update();
|
||||
}
|
||||
|
||||
private long? lastMessageId;
|
||||
|
||||
List<Channel> careChannels;
|
||||
|
||||
private void initializeChannels()
|
||||
{
|
||||
careChannels = new List<Channel>();
|
||||
|
||||
if (api.State != APIState.Online)
|
||||
return;
|
||||
|
||||
Add(flow = new FlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Direction = FlowDirections.Vertical
|
||||
});
|
||||
|
||||
SpriteText loading;
|
||||
Add(loading = new SpriteText
|
||||
{
|
||||
Text = @"Loading available channels...",
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
TextSize = 40,
|
||||
});
|
||||
|
||||
messageRequest?.Cancel();
|
||||
|
||||
ListChannelsRequest req = new ListChannelsRequest();
|
||||
req.Success += delegate (List<Channel> channels)
|
||||
{
|
||||
Scheduler.Add(delegate
|
||||
{
|
||||
loading.FadeOut(100);
|
||||
});
|
||||
|
||||
addChannel(channels.Find(c => c.Name == @"#osu"));
|
||||
addChannel(channels.Find(c => c.Name == @"#lobby"));
|
||||
addChannel(channels.Find(c => c.Name == @"#english"));
|
||||
|
||||
messageRequest = scheduler.AddDelayed(() => FetchNewMessages(api), 1000, true);
|
||||
};
|
||||
api.Queue(req);
|
||||
}
|
||||
|
||||
private void addChannel(Channel channel)
|
||||
{
|
||||
flow.Add(channelDisplay = new ChannelDisplay(channel)
|
||||
{
|
||||
Size = new Vector2(1, 0.3f)
|
||||
});
|
||||
|
||||
careChannels.Add(channel);
|
||||
}
|
||||
|
||||
GetMessagesRequest fetchReq;
|
||||
|
||||
public void FetchNewMessages(APIAccess api)
|
||||
{
|
||||
if (fetchReq != null) return;
|
||||
|
||||
fetchReq = new GetMessagesRequest(careChannels, lastMessageId);
|
||||
fetchReq.Success += delegate (List<Message> messages)
|
||||
{
|
||||
foreach (Message m in messages)
|
||||
{
|
||||
careChannels.Find(c => c.Id == m.ChannelId).AddNewMessages(m);
|
||||
}
|
||||
|
||||
lastMessageId = messages.LastOrDefault()?.Id ?? lastMessageId;
|
||||
|
||||
Debug.Write("success!");
|
||||
fetchReq = null;
|
||||
};
|
||||
fetchReq.Failure += delegate
|
||||
{
|
||||
Debug.Write("failure!");
|
||||
fetchReq = null;
|
||||
};
|
||||
|
||||
api.Queue(fetchReq);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Modes.Catch;
|
||||
using osu.Game.Modes.Catch.UI;
|
||||
using osu.Game.Modes.Mania;
|
||||
using osu.Game.Modes.Mania.UI;
|
||||
using osu.Game.Modes.Objects;
|
||||
using osu.Game.Modes.Osu;
|
||||
using osu.Game.Modes.Osu.Objects;
|
||||
using osu.Game.Modes.Osu.UI;
|
||||
using osu.Game.Modes.Taiko;
|
||||
using osu.Game.Modes.Taiko.UI;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseGamefield : TestCase
|
||||
{
|
||||
public override string Name => @"Gamefield";
|
||||
|
||||
public override string Description => @"Showing hitobjects and what not.";
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
//ensure we are at offset 0
|
||||
Clock = new FramedClock();
|
||||
|
||||
List<HitObject> objects = new List<HitObject>();
|
||||
|
||||
int time = 500;
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
objects.Add(new HitCircle()
|
||||
{
|
||||
StartTime = time,
|
||||
Position = new Vector2(RNG.Next(0, 512), RNG.Next(0, 384)),
|
||||
Scale = RNG.NextSingle(0.5f, 1.0f),
|
||||
});
|
||||
|
||||
time += RNG.Next(50, 500);
|
||||
}
|
||||
|
||||
Beatmap beatmap = new Beatmap
|
||||
{
|
||||
HitObjects = objects
|
||||
};
|
||||
|
||||
Add(new Drawable[]
|
||||
{
|
||||
new OsuHitRenderer
|
||||
{
|
||||
Beatmap = beatmap,
|
||||
Scale = new Vector2(0.5f),
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft
|
||||
},
|
||||
new TaikoHitRenderer
|
||||
{
|
||||
Beatmap = beatmap,
|
||||
Scale = new Vector2(0.5f),
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight
|
||||
},
|
||||
new CatchHitRenderer
|
||||
{
|
||||
Beatmap = beatmap,
|
||||
Scale = new Vector2(0.5f),
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft
|
||||
},
|
||||
new ManiaHitRenderer
|
||||
{
|
||||
Beatmap = beatmap,
|
||||
Scale = new Vector2(0.5f),
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Timing;
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Game.Modes.Objects;
|
||||
using osu.Game.Modes.Objects.Drawables;
|
||||
using osu.Game.Modes.Osu.Objects;
|
||||
using osu.Game.Modes.Osu.Objects.Drawables;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Modes;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseHitObjects : TestCase
|
||||
{
|
||||
public override string Name => @"Hit Objects";
|
||||
|
||||
private StopwatchClock rateAdjustClock;
|
||||
private FramedClock framedClock;
|
||||
|
||||
bool auto = false;
|
||||
|
||||
public TestCaseHitObjects()
|
||||
{
|
||||
rateAdjustClock = new StopwatchClock(true);
|
||||
framedClock = new FramedClock(rateAdjustClock);
|
||||
playbackSpeed.ValueChanged += delegate { rateAdjustClock.Rate = playbackSpeed.Value; };
|
||||
}
|
||||
|
||||
HitObjectType mode = HitObjectType.Slider;
|
||||
|
||||
BindableNumber<double> playbackSpeed = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1 };
|
||||
private Container playfieldContainer;
|
||||
private Container approachContainer;
|
||||
|
||||
private void load(HitObjectType mode)
|
||||
{
|
||||
this.mode = mode;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case HitObjectType.Circle:
|
||||
const int count = 10;
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var h = new HitCircle
|
||||
{
|
||||
StartTime = framedClock.CurrentTime + 600 + i * 80,
|
||||
Position = new Vector2((i - count / 2) * 14),
|
||||
};
|
||||
|
||||
add(new DrawableHitCircle(h));
|
||||
}
|
||||
break;
|
||||
case HitObjectType.Slider:
|
||||
add(new DrawableSlider(new Slider
|
||||
{
|
||||
StartTime = framedClock.CurrentTime + 600,
|
||||
ControlPoints = new List<Vector2>()
|
||||
{
|
||||
new Vector2(-200, 0),
|
||||
new Vector2(400, 0),
|
||||
},
|
||||
Length = 400,
|
||||
Position = new Vector2(-200, 0),
|
||||
Velocity = 1,
|
||||
TickDistance = 100,
|
||||
}));
|
||||
break;
|
||||
case HitObjectType.Spinner:
|
||||
add(new DrawableSpinner(new Spinner
|
||||
{
|
||||
StartTime = framedClock.CurrentTime + 600,
|
||||
Length = 1000,
|
||||
Position = new Vector2(0, 0),
|
||||
}));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
playbackSpeed.TriggerChange();
|
||||
|
||||
AddButton(@"circles", () => load(HitObjectType.Circle));
|
||||
AddButton(@"slider", () => load(HitObjectType.Slider));
|
||||
AddButton(@"spinner", () => load(HitObjectType.Spinner));
|
||||
|
||||
AddToggle(@"auto", () => { auto = !auto; load(mode); });
|
||||
|
||||
ButtonsContainer.Add(new SpriteText { Text = "Playback Speed" });
|
||||
ButtonsContainer.Add(new BasicSliderBar<double>
|
||||
{
|
||||
Width = 150,
|
||||
Height = 10,
|
||||
SelectionColor = Color4.Orange,
|
||||
Bindable = playbackSpeed
|
||||
});
|
||||
|
||||
framedClock.ProcessFrame();
|
||||
|
||||
var clockAdjustContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Clock = framedClock,
|
||||
Children = new[]
|
||||
{
|
||||
playfieldContainer = new Container { RelativeSizeAxes = Axes.Both },
|
||||
approachContainer = new Container { RelativeSizeAxes = Axes.Both }
|
||||
}
|
||||
};
|
||||
|
||||
Add(clockAdjustContainer);
|
||||
|
||||
load(mode);
|
||||
}
|
||||
|
||||
int depth;
|
||||
void add(DrawableHitObject h)
|
||||
{
|
||||
h.Anchor = Anchor.Centre;
|
||||
h.Depth = depth++;
|
||||
|
||||
if (auto)
|
||||
{
|
||||
h.State = ArmedState.Hit;
|
||||
h.Judgement = new OsuJudgementInfo { Result = HitResult.Hit };
|
||||
}
|
||||
|
||||
playfieldContainer.Add(h);
|
||||
var proxyable = h as IDrawableHitObjectWithProxiedApproach;
|
||||
if (proxyable != null)
|
||||
approachContainer.Add(proxyable.ProxiedLayer.CreateProxy());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Configuration;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Transformations;
|
||||
using osu.Game.Screens.Play;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseKeyCounter : TestCase
|
||||
{
|
||||
public override string Name => @"KeyCounter";
|
||||
|
||||
public override string Description => @"Tests key counter";
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
KeyCounterCollection kc = new KeyCounterCollection
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
IsCounting = true,
|
||||
Children = new KeyCounter[]
|
||||
{
|
||||
new KeyCounterKeyboard(@"Z", Key.Z),
|
||||
new KeyCounterKeyboard(@"X", Key.X),
|
||||
new KeyCounterMouse(@"M1", MouseButton.Left),
|
||||
new KeyCounterMouse(@"M2", MouseButton.Right),
|
||||
},
|
||||
};
|
||||
BindableInt bindable = new BindableInt { MinValue = 0, MaxValue = 200, Default = 50 };
|
||||
bindable.ValueChanged += delegate { kc.FadeTime = bindable.Value; };
|
||||
AddButton("Add Random", () =>
|
||||
{
|
||||
Key key = (Key)((int)Key.A + RNG.Next(26));
|
||||
kc.Add(new KeyCounterKeyboard(key.ToString(), key));
|
||||
});
|
||||
ButtonsContainer.Add(new SpriteText { Text = "FadeTime" });
|
||||
ButtonsContainer.Add(new TestSliderBar<int>
|
||||
{
|
||||
Width = 150,
|
||||
Height = 10,
|
||||
SelectionColor = Color4.Orange,
|
||||
Bindable = bindable
|
||||
});
|
||||
Add(kc);
|
||||
}
|
||||
private class TestSliderBar<T> : SliderBar<T> where T : struct
|
||||
{
|
||||
public Color4 Color
|
||||
{
|
||||
get { return Box.Colour; }
|
||||
set { Box.Colour = value; }
|
||||
}
|
||||
|
||||
public Color4 SelectionColor
|
||||
{
|
||||
get { return SelectionBox.Colour; }
|
||||
set { SelectionBox.Colour = value; }
|
||||
}
|
||||
|
||||
protected readonly Box SelectionBox;
|
||||
protected readonly Box Box;
|
||||
|
||||
public TestSliderBar()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Box = new Box { RelativeSizeAxes = Axes.Both },
|
||||
SelectionBox = new Box { RelativeSizeAxes = Axes.Both }
|
||||
};
|
||||
}
|
||||
|
||||
protected override void UpdateValue(float value)
|
||||
{
|
||||
SelectionBox.ScaleTo(
|
||||
new Vector2(value, 1),
|
||||
300, EasingTypes.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Screens.Menu;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseMenuButtonSystem : TestCase
|
||||
{
|
||||
public override string Name => @"ButtonSystem";
|
||||
public override string Description => @"Main menu button system";
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(new Box
|
||||
{
|
||||
ColourInfo = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke),
|
||||
RelativeSizeAxes = Framework.Graphics.Axes.Both,
|
||||
});
|
||||
Add(new ButtonSystem());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Overlays;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseMusicController : TestCase
|
||||
{
|
||||
public override string Name => @"Music Controller";
|
||||
public override string Description => @"Tests music controller ui.";
|
||||
|
||||
private MusicController mc;
|
||||
|
||||
public TestCaseMusicController()
|
||||
{
|
||||
Clock = new FramedClock();
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
Clock.ProcessFrame();
|
||||
mc = new MusicController
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre
|
||||
};
|
||||
Add(mc);
|
||||
AddToggle(@"Show", mc.ToggleVisibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Overlays;
|
||||
using System.Linq;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseNotificationManager : TestCase
|
||||
{
|
||||
public override string Name => @"Notification Manager";
|
||||
public override string Description => @"I handle notifications";
|
||||
|
||||
NotificationManager manager;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
progressingNotifications.Clear();
|
||||
|
||||
Content.Add(manager = new NotificationManager
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
});
|
||||
|
||||
AddToggle(@"show", manager.ToggleVisibility);
|
||||
|
||||
AddButton(@"simple #1", sendNotification1);
|
||||
AddButton(@"simple #2", sendNotification2);
|
||||
AddButton(@"progress #1", sendProgress1);
|
||||
AddButton(@"progress #2", sendProgress2);
|
||||
AddButton(@"barrage", () => sendBarrage());
|
||||
}
|
||||
|
||||
private void sendBarrage(int remaining = 100)
|
||||
{
|
||||
switch (RNG.Next(0, 4))
|
||||
{
|
||||
case 0:
|
||||
sendNotification1();
|
||||
break;
|
||||
case 1:
|
||||
sendNotification2();
|
||||
break;
|
||||
case 2:
|
||||
sendProgress1();
|
||||
break;
|
||||
case 3:
|
||||
sendProgress2();
|
||||
break;
|
||||
}
|
||||
|
||||
if (remaining > 0)
|
||||
{
|
||||
Delay(80);
|
||||
Schedule(() => sendBarrage(remaining - 1));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed);
|
||||
|
||||
while (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3)
|
||||
{
|
||||
var p = progressingNotifications.FirstOrDefault(n => n.IsLoaded && n.State == ProgressNotificationState.Queued);
|
||||
if (p == null)
|
||||
break;
|
||||
|
||||
p.State = ProgressNotificationState.Active;
|
||||
}
|
||||
|
||||
foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active))
|
||||
{
|
||||
if (n.Progress < 1)
|
||||
n.Progress += (float)(Time.Elapsed / 2000) * RNG.NextSingle();
|
||||
else
|
||||
n.State = ProgressNotificationState.Completed;
|
||||
}
|
||||
}
|
||||
|
||||
private void sendProgress2()
|
||||
{
|
||||
var n = new ProgressNotification { Text = @"Downloading Haitai..." };
|
||||
manager.Post(n);
|
||||
progressingNotifications.Add(n);
|
||||
}
|
||||
|
||||
List<ProgressNotification> progressingNotifications = new List<ProgressNotification>();
|
||||
|
||||
private void sendProgress1()
|
||||
{
|
||||
var n = new ProgressNotification { Text = @"Uploading to BSS..." };
|
||||
manager.Post(n);
|
||||
progressingNotifications.Add(n);
|
||||
}
|
||||
|
||||
private void sendNotification2()
|
||||
{
|
||||
manager.Post(new SimpleNotification { Text = @"You are amazing" });
|
||||
}
|
||||
|
||||
private void sendNotification1()
|
||||
{
|
||||
manager.Post(new SimpleNotification { Text = @"Welcome to osu!. Enjoy your stay!" });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using OpenTK.Input;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseOptions : TestCase
|
||||
{
|
||||
public override string Name => @"Options";
|
||||
|
||||
public override string Description => @"Tests the options overlay";
|
||||
|
||||
private OptionsOverlay options;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Children = new[] { options = new OptionsOverlay() };
|
||||
options.ToggleVisibility();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Overlays.Pause;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCasePauseOverlay : TestCase
|
||||
{
|
||||
public override string Name => @"PauseOverlay";
|
||||
|
||||
public override string Description => @"Tests the pause overlay";
|
||||
|
||||
private PauseOverlay pauseOverlay;
|
||||
private int retryCount;
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(pauseOverlay = new PauseOverlay
|
||||
{
|
||||
Depth = -1,
|
||||
OnResume = () => Logger.Log(@"Resume"),
|
||||
OnRetry = () => Logger.Log(@"Retry"),
|
||||
OnQuit = () => Logger.Log(@"Quit")
|
||||
});
|
||||
AddButton("Pause", pauseOverlay.Show);
|
||||
AddButton("Add Retry", delegate
|
||||
{
|
||||
retryCount++;
|
||||
pauseOverlay.Retries = retryCount;
|
||||
});
|
||||
|
||||
retryCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Desktop.VisualTests.Platform;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Modes;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCasePlaySongSelect : TestCase
|
||||
{
|
||||
private BeatmapDatabase db, oldDb;
|
||||
private TestStorage storage;
|
||||
|
||||
public override string Name => @"Song Select";
|
||||
public override string Description => @"with fake data";
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
oldDb = Dependencies.Get<BeatmapDatabase>();
|
||||
if (db == null)
|
||||
{
|
||||
storage = new TestStorage(@"TestCasePlaySongSelect");
|
||||
db = new BeatmapDatabase(storage);
|
||||
Dependencies.Cache(db, true);
|
||||
|
||||
var sets = new List<BeatmapSetInfo>();
|
||||
|
||||
for (int i = 0; i < 100; i += 10)
|
||||
sets.Add(createTestBeatmapSet(i));
|
||||
|
||||
db.Import(sets);
|
||||
}
|
||||
Add(new PlaySongSelect());
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
if (oldDb != null)
|
||||
{
|
||||
Dependencies.Cache(oldDb, true);
|
||||
db = null;
|
||||
}
|
||||
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
|
||||
private BeatmapSetInfo createTestBeatmapSet(int i)
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 1234 + i,
|
||||
Hash = "d8e8fca2dc0f896fd7cb4cb0031ba249",
|
||||
Path = string.Empty,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
OnlineBeatmapSetID = 1234 + i,
|
||||
Artist = "MONACA",
|
||||
Title = "Black Song",
|
||||
Author = "Some Guy",
|
||||
},
|
||||
Beatmaps = new List<BeatmapInfo>(new[]
|
||||
{
|
||||
new BeatmapInfo
|
||||
{
|
||||
OnlineBeatmapID = 1234 + i,
|
||||
Mode = PlayMode.Osu,
|
||||
Path = "normal.osu",
|
||||
Version = "Normal",
|
||||
BaseDifficulty = new BaseDifficulty
|
||||
{
|
||||
OverallDifficulty = 3.5f,
|
||||
}
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
OnlineBeatmapID = 1235 + i,
|
||||
Mode = PlayMode.Osu,
|
||||
Path = "hard.osu",
|
||||
Version = "Hard",
|
||||
BaseDifficulty = new BaseDifficulty
|
||||
{
|
||||
OverallDifficulty = 5,
|
||||
}
|
||||
},
|
||||
new BeatmapInfo
|
||||
{
|
||||
OnlineBeatmapID = 1236 + i,
|
||||
Mode = PlayMode.Osu,
|
||||
Path = "insane.osu",
|
||||
Version = "Insane",
|
||||
BaseDifficulty = new BaseDifficulty
|
||||
{
|
||||
OverallDifficulty = 7,
|
||||
}
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Modes;
|
||||
using osu.Game.Modes.Objects;
|
||||
using osu.Game.Modes.Osu.Objects;
|
||||
using osu.Game.Screens.Play;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCasePlayer : TestCase
|
||||
{
|
||||
private WorkingBeatmap beatmap;
|
||||
public override string Name => @"Player";
|
||||
|
||||
public override string Description => @"Showing everything to play the game.";
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(BeatmapDatabase db)
|
||||
{
|
||||
var beatmapInfo = db.Query<BeatmapInfo>().Where(b => b.Mode == PlayMode.Osu).FirstOrDefault();
|
||||
if (beatmapInfo != null)
|
||||
beatmap = db.GetWorkingBeatmap(beatmapInfo);
|
||||
}
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
if (beatmap?.Track == null)
|
||||
{
|
||||
var objects = new List<HitObject>();
|
||||
|
||||
int time = 1500;
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
objects.Add(new HitCircle()
|
||||
{
|
||||
StartTime = time,
|
||||
Position = new Vector2(i % 4 == 0 || i % 4 == 2 ? 0 : 512,
|
||||
i % 4 < 2 ? 0 : 384),
|
||||
NewCombo = i % 4 == 0
|
||||
});
|
||||
|
||||
time += 500;
|
||||
}
|
||||
|
||||
var decoder = new ConstructableBeatmapDecoder();
|
||||
|
||||
Beatmap b = new Beatmap
|
||||
{
|
||||
HitObjects = objects
|
||||
};
|
||||
|
||||
decoder.Process(b);
|
||||
|
||||
beatmap = new WorkingBeatmap(b);
|
||||
}
|
||||
|
||||
Add(new Box
|
||||
{
|
||||
RelativeSizeAxes = Framework.Graphics.Axes.Both,
|
||||
Colour = Color4.Gray,
|
||||
});
|
||||
|
||||
Add(new Player
|
||||
{
|
||||
PreferredPlayMode = PlayMode.Osu,
|
||||
Beatmap = beatmap
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Modes;
|
||||
using osu.Game.Modes.Catch;
|
||||
using osu.Game.Modes.Catch.UI;
|
||||
using osu.Game.Modes.Mania;
|
||||
using osu.Game.Modes.Mania.UI;
|
||||
using osu.Game.Modes.Osu;
|
||||
using osu.Game.Modes.Osu.UI;
|
||||
using osu.Game.Modes.Taiko;
|
||||
using osu.Game.Modes.Taiko.UI;
|
||||
using osu.Game.Modes.UI;
|
||||
using osu.Game.Screens.Play;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics.Primitives;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseScoreCounter : TestCase
|
||||
{
|
||||
public override string Name => @"ScoreCounter";
|
||||
|
||||
public override string Description => @"Tests multiple counters";
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
int numerator = 0, denominator = 0;
|
||||
|
||||
bool maniaHold = false;
|
||||
|
||||
ScoreCounter score = new ScoreCounter(7)
|
||||
{
|
||||
Origin = Anchor.TopRight,
|
||||
Anchor = Anchor.TopRight,
|
||||
TextSize = 40,
|
||||
Count = 0,
|
||||
Margin = new MarginPadding(20),
|
||||
};
|
||||
Add(score);
|
||||
|
||||
ComboCounter standardCombo = new OsuComboCounter
|
||||
{
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Margin = new MarginPadding(10),
|
||||
Count = 0,
|
||||
TextSize = 40,
|
||||
};
|
||||
Add(standardCombo);
|
||||
|
||||
CatchComboCounter catchCombo = new CatchComboCounter
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Count = 0,
|
||||
TextSize = 40,
|
||||
};
|
||||
Add(catchCombo);
|
||||
|
||||
ComboCounter taikoCombo = new TaikoComboCounter
|
||||
{
|
||||
Origin = Anchor.BottomCentre,
|
||||
Anchor = Anchor.Centre,
|
||||
Position = new Vector2(0, -160),
|
||||
Count = 0,
|
||||
TextSize = 40,
|
||||
};
|
||||
Add(taikoCombo);
|
||||
|
||||
ManiaComboCounter maniaCombo = new ManiaComboCounter
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Position = new Vector2(0, -80),
|
||||
Count = 0,
|
||||
TextSize = 40,
|
||||
};
|
||||
Add(maniaCombo);
|
||||
|
||||
|
||||
PercentageCounter accuracyCombo = new PercentageCounter
|
||||
{
|
||||
Origin = Anchor.TopRight,
|
||||
Anchor = Anchor.TopRight,
|
||||
Position = new Vector2(-20, 60),
|
||||
};
|
||||
Add(accuracyCombo);
|
||||
|
||||
StarCounter stars = new StarCounter
|
||||
{
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Position = new Vector2(20, -160),
|
||||
Count = 5,
|
||||
};
|
||||
Add(stars);
|
||||
|
||||
SpriteText starsLabel = new SpriteText
|
||||
{
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Position = new Vector2(20, -190),
|
||||
Text = stars.Count.ToString("0.00"),
|
||||
};
|
||||
Add(starsLabel);
|
||||
|
||||
AddButton(@"Reset all", delegate
|
||||
{
|
||||
score.Count = 0;
|
||||
standardCombo.Count = 0;
|
||||
taikoCombo.Count = 0;
|
||||
maniaCombo.Count = 0;
|
||||
catchCombo.Count = 0;
|
||||
numerator = denominator = 0;
|
||||
accuracyCombo.SetFraction(0, 0);
|
||||
stars.Count = 0;
|
||||
starsLabel.Text = stars.Count.ToString("0.00");
|
||||
});
|
||||
|
||||
AddButton(@"Hit! :D", delegate
|
||||
{
|
||||
score.Count += 300 + (ulong)(300.0 * (standardCombo.Count > 0 ? standardCombo.Count - 1 : 0) / 25.0);
|
||||
standardCombo.Count++;
|
||||
taikoCombo.Count++;
|
||||
maniaCombo.Count++;
|
||||
catchCombo.CatchFruit(new Color4(
|
||||
Math.Max(0.5f, RNG.NextSingle()),
|
||||
Math.Max(0.5f, RNG.NextSingle()),
|
||||
Math.Max(0.5f, RNG.NextSingle()),
|
||||
1)
|
||||
);
|
||||
numerator++; denominator++;
|
||||
accuracyCombo.SetFraction(numerator, denominator);
|
||||
});
|
||||
|
||||
AddButton(@"miss...", delegate
|
||||
{
|
||||
standardCombo.Roll();
|
||||
taikoCombo.Roll();
|
||||
maniaCombo.Roll();
|
||||
catchCombo.Roll();
|
||||
denominator++;
|
||||
accuracyCombo.SetFraction(numerator, denominator);
|
||||
});
|
||||
|
||||
AddButton(@"mania hold", delegate
|
||||
{
|
||||
if (!maniaHold)
|
||||
maniaCombo.HoldStart();
|
||||
else
|
||||
maniaCombo.HoldEnd();
|
||||
maniaHold = !maniaHold;
|
||||
});
|
||||
|
||||
AddButton(@"Alter stars", delegate
|
||||
{
|
||||
stars.Count = RNG.NextSingle() * (stars.MaxStars + 1);
|
||||
starsLabel.Text = stars.Count.ToString("0.00");
|
||||
});
|
||||
|
||||
AddButton(@"Stop counters", delegate
|
||||
{
|
||||
score.StopRolling();
|
||||
standardCombo.StopRolling();
|
||||
catchCombo.StopRolling();
|
||||
taikoCombo.StopRolling();
|
||||
maniaCombo.StopRolling();
|
||||
accuracyCombo.StopRolling();
|
||||
stars.StopAnimation();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseTextAwesome : TestCase
|
||||
{
|
||||
public override string Name => @"TextAwesome";
|
||||
|
||||
public override string Description => @"Tests display of icons";
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
FlowContainer flow;
|
||||
|
||||
Add(flow = new FlowContainer()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(0.5f),
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre
|
||||
});
|
||||
|
||||
int i = 50;
|
||||
foreach (FontAwesome fa in Enum.GetValues(typeof(FontAwesome)))
|
||||
{
|
||||
flow.Add(new TextAwesome
|
||||
{
|
||||
Icon = fa,
|
||||
TextSize = 60,
|
||||
Colour = new Color4(
|
||||
Math.Max(0.5f, RNG.NextSingle()),
|
||||
Math.Max(0.5f, RNG.NextSingle()),
|
||||
Math.Max(0.5f, RNG.NextSingle()),
|
||||
1)
|
||||
});
|
||||
|
||||
if (i-- == 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Screens.Play;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Desktop.VisualTests.Tests
|
||||
{
|
||||
class TestCaseTwoLayerButton : TestCase
|
||||
{
|
||||
public override string Name => @"TwoLayerButton";
|
||||
public override string Description => @"Back and skip and what not";
|
||||
|
||||
public override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
|
||||
Add(new BackButton());
|
||||
Add(new SkipButton());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework;
|
||||
using osu.Framework.GameModes.Testing;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Database;
|
||||
using osu.Game;
|
||||
using osu.Framework.Desktop.Platform;
|
||||
using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
|
||||
namespace osu.Desktop.VisualTests
|
||||
{
|
||||
class VisualTestGame : OsuGameBase
|
||||
{
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
(new BackgroundModeDefault() { Depth = 10 }).Preload(this, AddInternal);
|
||||
|
||||
// Have to construct this here, rather than in the constructor, because
|
||||
// we depend on some dependencies to be loaded within OsuGameBase.load().
|
||||
Add(new TestBrowser());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{69051C69-12AE-4E7D-A3E6-460D2E282312}</ProjectGuid>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>osu.Desktop.VisualTests</RootNamespace>
|
||||
<AssemblyName>osu!</AssemblyName>
|
||||
<ManifestCertificateThumbprint>3CF060CD28877D0E3112948951A64B2A7CEEC909</ManifestCertificateThumbprint>
|
||||
<ManifestKeyFile>codesigning.pfx</ManifestKeyFile>
|
||||
<GenerateManifests>false</GenerateManifests>
|
||||
<SignManifests>false</SignManifests>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>3.5</OldToolsVersion>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<StartupObject>osu.Desktop.VisualTests.Program</StartupObject>
|
||||
<RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
|
||||
<SignAssembly>false</SignAssembly>
|
||||
<TargetZone>LocalIntranet</TargetZone>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>2</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<ProductVersion>12.0.0</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<TargetFrameworkProfile>
|
||||
</TargetFrameworkProfile>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>0</WarningLevel>
|
||||
<NoStdLib>true</NoStdLib>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<RunCodeAnalysis>false</RunCodeAnalysis>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>none</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>CuttingEdge NoUpdate</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<NoStdLib>true</NoStdLib>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<Win32Resource>
|
||||
</Win32Resource>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="SQLite.Net, Version=3.1.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net.Core-PCL.3.1.1\lib\portable-win8+net45+wp8+wpa81+MonoAndroid1+MonoTouch1\SQLite.Net.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLiteNetExtensions">
|
||||
<HintPath>$(SolutionDir)\packages\SQLiteNetExtensions.1.3.0\lib\portable-net45+netcore45+wpa81+wp8+MonoAndroid1+MonoTouch1\SQLiteNetExtensions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net.Platform.Win32">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net4\SQLite.Net.Platform.Win32.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SQLite.Net.Platform.Generic">
|
||||
<HintPath>$(SolutionDir)\packages\SQLite.Net-PCL.3.1.1\lib\net40\SQLite.Net.Platform.Generic.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="OpenTK">
|
||||
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.2.0.50727.1339\lib\net45\OpenTK.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\osu.licenseheader">
|
||||
<Link>osu.licenseheader</Link>
|
||||
</None>
|
||||
<None Include="app.config" />
|
||||
<None Include="packages.config" />
|
||||
<None Include="OpenTK.dll.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework.Desktop\osu.Framework.Desktop.csproj">
|
||||
<Project>{65dc628f-a640-4111-ab35-3a5652bc1e17}</Project>
|
||||
<Name>osu.Framework.Desktop</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
|
||||
<Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
|
||||
<Name>osu.Framework</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu-resources\osu.Game.Resources\osu.Game.Resources.csproj">
|
||||
<Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
|
||||
<Name>osu.Game.Resources</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game.Modes.Osu\osu.Game.Modes.Osu.csproj">
|
||||
<Project>{c92a607b-1fdd-4954-9f92-03ff547d9080}</Project>
|
||||
<Name>osu.Game.Modes.Osu</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game.Modes.Catch\osu.Game.Modes.Catch.csproj">
|
||||
<Project>{58f6c80c-1253-4a0e-a465-b8c85ebeadf3}</Project>
|
||||
<Name>osu.Game.Modes.Catch</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game.Modes.Mania\osu.Game.Modes.Mania.csproj">
|
||||
<Project>{48f4582b-7687-4621-9cbe-5c24197cb536}</Project>
|
||||
<Name>osu.Game.Modes.Mania</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game.Modes.Taiko\osu.Game.Modes.Taiko.csproj">
|
||||
<Project>{f167e17a-7de6-4af5-b920-a5112296c695}</Project>
|
||||
<Name>osu.Game.Modes.Taiko</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
|
||||
<Project>{0d3fbf8a-7464-4cf7-8c90-3e7886df2d4d}</Project>
|
||||
<Name>osu.Game</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Benchmark.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Tests\TestCaseChatDisplay.cs" />
|
||||
<Compile Include="Tests\TestCaseGamefield.cs" />
|
||||
<Compile Include="Tests\TestCaseMusicController.cs" />
|
||||
<Compile Include="Tests\TestCaseNotificationManager.cs" />
|
||||
<Compile Include="Tests\TestCasePlayer.cs" />
|
||||
<Compile Include="Tests\TestCaseHitObjects.cs" />
|
||||
<Compile Include="Tests\TestCaseKeyCounter.cs" />
|
||||
<Compile Include="Tests\TestCaseMenuButtonSystem.cs" />
|
||||
<Compile Include="Tests\TestCaseScoreCounter.cs" />
|
||||
<Compile Include="Tests\TestCaseTextAwesome.cs" />
|
||||
<Compile Include="Tests\TestCasePlaySongSelect.cs" />
|
||||
<Compile Include="Tests\TestCaseTwoLayerButton.cs" />
|
||||
<Compile Include="VisualTestGame.cs" />
|
||||
<Compile Include="Platform\TestStorage.cs" />
|
||||
<Compile Include="Tests\TestCaseOptions.cs" />
|
||||
<Compile Include="Tests\TestCasePauseOverlay.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup />
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
<PreBuildEvent>
|
||||
</PreBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
|
||||
<package id="ppy.OpenTK" version="2.0.50727.1339" targetFramework="net45" />
|
||||
<package id="SQLite.Net.Core-PCL" version="3.1.1" targetFramework="net45" />
|
||||
<package id="SQLite.Net-PCL" version="3.1.1" targetFramework="net45" />
|
||||
<package id="SQLiteNetExtensions" version="1.3.0" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Beatmaps.Formats;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Database;
|
||||
|
||||
namespace osu.Desktop.Beatmaps.IO
|
||||
{
|
||||
/// <summary>
|
||||
/// Reads an extracted legacy beatmap from disk.
|
||||
/// </summary>
|
||||
public class LegacyFilesystemReader : ArchiveReader
|
||||
{
|
||||
public static void Register() => AddReader<LegacyFilesystemReader>((storage, path) => Directory.Exists(path));
|
||||
|
||||
private string basePath { get; set; }
|
||||
private Beatmap firstMap { get; set; }
|
||||
|
||||
public LegacyFilesystemReader(string path)
|
||||
{
|
||||
basePath = path;
|
||||
BeatmapFilenames = Directory.GetFiles(basePath, @"*.osu").Select(f => Path.GetFileName(f)).ToArray();
|
||||
if (BeatmapFilenames.Length == 0)
|
||||
throw new FileNotFoundException(@"This directory contains no beatmaps");
|
||||
StoryboardFilename = Directory.GetFiles(basePath, @"*.osb").Select(f => Path.GetFileName(f)).FirstOrDefault();
|
||||
using (var stream = new StreamReader(GetStream(BeatmapFilenames[0])))
|
||||
{
|
||||
var decoder = BeatmapDecoder.GetDecoder(stream);
|
||||
firstMap = decoder.Decode(stream);
|
||||
}
|
||||
}
|
||||
|
||||
public override Stream GetStream(string name)
|
||||
{
|
||||
return File.OpenRead(Path.Combine(basePath, name));
|
||||
}
|
||||
|
||||
public override BeatmapMetadata ReadMetadata()
|
||||
{
|
||||
return firstMap.BeatmapInfo.Metadata;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,3 @@
|
||||
<!--
|
||||
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
-->
|
||||
<configuration>
|
||||
<dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
|
||||
<dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
|
||||
@@ -1,71 +1,121 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Desktop.Platform;
|
||||
using osu.Game.Database;
|
||||
using osu.Desktop.Overlays;
|
||||
using System.Reflection;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32;
|
||||
using osu.Desktop.Overlays;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace osu.Desktop
|
||||
{
|
||||
class OsuGameDesktop : OsuGame
|
||||
internal class OsuGameDesktop : OsuGame
|
||||
{
|
||||
private readonly bool noVersionOverlay;
|
||||
|
||||
public OsuGameDesktop(string[] args = null)
|
||||
: base(args)
|
||||
{
|
||||
noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false;
|
||||
}
|
||||
|
||||
public override Storage GetStorageForStableInstall()
|
||||
{
|
||||
try
|
||||
{
|
||||
return new StableStorage();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A method of accessing an osu-stable install in a controlled fashion.
|
||||
/// </summary>
|
||||
private class StableStorage : DesktopStorage
|
||||
{
|
||||
protected override string LocateBasePath()
|
||||
{
|
||||
bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs"));
|
||||
|
||||
string stableInstallPath;
|
||||
|
||||
try
|
||||
{
|
||||
using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu"))
|
||||
stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(String.Empty).ToString().Split('"')[1].Replace("osu!.exe", "");
|
||||
|
||||
if (checkExists(stableInstallPath))
|
||||
return stableInstallPath;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!");
|
||||
if (checkExists(stableInstallPath))
|
||||
return stableInstallPath;
|
||||
|
||||
stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu");
|
||||
if (checkExists(stableInstallPath))
|
||||
return stableInstallPath;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public StableStorage()
|
||||
: base(string.Empty)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
(new VersionManager()).Preload(this, Add);
|
||||
if (!noVersionOverlay)
|
||||
{
|
||||
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
|
||||
{
|
||||
Add(v);
|
||||
v.State = Visibility.Visible;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetHost(BasicGameHost host)
|
||||
public override void SetHost(GameHost host)
|
||||
{
|
||||
base.SetHost(host);
|
||||
var desktopWindow = host.Window as DesktopGameWindow;
|
||||
if (desktopWindow != null)
|
||||
{
|
||||
desktopWindow.Icon = Icon.ExtractAssociatedIcon(Assembly.GetExecutingAssembly().Location);
|
||||
desktopWindow.Title = @"osu!lazer";
|
||||
desktopWindow.CursorState |= CursorState.Hidden;
|
||||
|
||||
desktopWindow.DragEnter += dragEnter;
|
||||
desktopWindow.DragDrop += dragDrop;
|
||||
desktopWindow.Icon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
|
||||
desktopWindow.Title = Name;
|
||||
|
||||
desktopWindow.FileDrop += fileDrop;
|
||||
}
|
||||
}
|
||||
|
||||
private void dragDrop(DragEventArgs e)
|
||||
private void fileDrop(object sender, FileDropEventArgs e)
|
||||
{
|
||||
// this method will only be executed if e.Effect in dragEnter gets set to something other that None.
|
||||
var dropData = e.Data.GetData(DataFormats.FileDrop) as object[];
|
||||
var filePaths = dropData.Select(f => f.ToString()).ToArray();
|
||||
ImportBeatmaps(filePaths);
|
||||
}
|
||||
var filePaths = new [] { e.FileName };
|
||||
|
||||
private void dragEnter(DragEventArgs e)
|
||||
{
|
||||
// dragDrop will only be executed if e.Effect gets set to something other that None in this method.
|
||||
bool isFile = e.Data.GetDataPresent(DataFormats.FileDrop);
|
||||
if (isFile)
|
||||
{
|
||||
var paths = (e.Data.GetData(DataFormats.FileDrop) as object[]).Select(f => f.ToString()).ToArray();
|
||||
if (paths.Any(p => !p.EndsWith(".osz")))
|
||||
e.Effect = DragDropEffects.None;
|
||||
else
|
||||
e.Effect = DragDropEffects.Copy;
|
||||
}
|
||||
var firstExtension = Path.GetExtension(filePaths.First());
|
||||
|
||||
if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
|
||||
|
||||
Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game;
|
||||
using osu.Game.Screens.Backgrounds;
|
||||
|
||||
namespace osu.Desktop
|
||||
{
|
||||
internal class OsuTestBrowser : OsuGameBase
|
||||
{
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
LoadComponentAsync(new BackgroundScreenDefault { Depth = 10 }, AddInternal);
|
||||
|
||||
// Have to construct this here, rather than in the constructor, because
|
||||
// we depend on some dependencies to be loaded within OsuGameBase.load().
|
||||
Add(new TestBrowser());
|
||||
}
|
||||
|
||||
public override void SetHost(GameHost host)
|
||||
{
|
||||
base.SetHost(host);
|
||||
host.Window.CursorState |= CursorState.Hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,80 +1,78 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Development;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using Squirrel;
|
||||
using System.Reflection;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using Squirrel;
|
||||
|
||||
namespace osu.Desktop.Overlays
|
||||
{
|
||||
public class VersionManager : OverlayContainer
|
||||
{
|
||||
private UpdateManager updateManager;
|
||||
private NotificationManager notification;
|
||||
private NotificationOverlay notificationOverlay;
|
||||
private OsuConfigManager config;
|
||||
private OsuGameBase game;
|
||||
|
||||
protected override bool HideOnEscape => false;
|
||||
|
||||
public override bool HandleInput => false;
|
||||
public override bool HandleKeyboardInput => false;
|
||||
public override bool HandleMouseInput => false;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(NotificationManager notification, OsuColour colours, TextureStore textures)
|
||||
private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config)
|
||||
{
|
||||
this.notification = notification;
|
||||
notificationOverlay = notification;
|
||||
this.config = config;
|
||||
this.game = game;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Anchor = Anchor.BottomCentre;
|
||||
Origin = Anchor.BottomCentre;
|
||||
|
||||
Alpha = 0;
|
||||
|
||||
bool isDebug = false;
|
||||
Debug.Assert(isDebug = true);
|
||||
|
||||
var asm = Assembly.GetEntryAssembly().GetName();
|
||||
string version;
|
||||
if (asm.Version.Major == 0)
|
||||
{
|
||||
version = @"local " + (isDebug ? @"debug" : @"release");
|
||||
}
|
||||
else
|
||||
version = $@"{asm.Version.Major}.{asm.Version.Minor}.{asm.Version.Build}";
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FlowContainer
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FlowDirections.Vertical,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FlowContainer
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FlowDirections.Horizontal,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5),
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Spacing = new Vector2(5),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = @"Exo2.0-Bold",
|
||||
Text = $@"osu!lazer"
|
||||
Text = game.Name
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Colour = isDebug ? colours.Red : Color4.White,
|
||||
Text = version
|
||||
Colour = DebugUtils.IsDebug ? colours.Red : Color4.White,
|
||||
Text = game.Version
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -85,23 +83,56 @@ namespace osu.Desktop.Overlays
|
||||
TextSize = 12,
|
||||
Colour = colours.Yellow,
|
||||
Font = @"Venera",
|
||||
Text = $@"Development Build"
|
||||
Text = @"Development Build"
|
||||
},
|
||||
new Sprite
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Texture = textures.Get(@"Menu/dev-build-footer"),
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateChecker();
|
||||
if (game.IsDeployedBuild)
|
||||
checkForUpdateAsync();
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
State = Visibility.Visible;
|
||||
|
||||
var version = game.Version;
|
||||
var lastVersion = config.Get<string>(OsuSetting.Version);
|
||||
if (game.IsDeployedBuild && version != lastVersion)
|
||||
{
|
||||
config.Set(OsuSetting.Version, version);
|
||||
|
||||
// only show a notification if we've previously saved a version to the config file (ie. not the first run).
|
||||
if (!string.IsNullOrEmpty(lastVersion))
|
||||
notificationOverlay.Post(new UpdateCompleteNotification(version));
|
||||
}
|
||||
}
|
||||
|
||||
private class UpdateCompleteNotification : SimpleNotification
|
||||
{
|
||||
public UpdateCompleteNotification(string version)
|
||||
{
|
||||
Text = $"You are now running osu!lazer {version}.\nClick to see what's new!";
|
||||
Icon = FontAwesome.fa_check_square;
|
||||
Activated = delegate
|
||||
{
|
||||
Process.Start($"https://github.com/ppy/osu/releases/tag/v{version}");
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
IconBackgound.Colour = colours.BlueDark;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
@@ -110,55 +141,126 @@ namespace osu.Desktop.Overlays
|
||||
updateManager?.Dispose();
|
||||
}
|
||||
|
||||
private async void updateChecker()
|
||||
private async void checkForUpdateAsync(bool useDeltaPatching = true, UpdateProgressNotification notification = null)
|
||||
{
|
||||
updateManager = await UpdateManager.GitHubUpdateManager(@"https://github.com/ppy/osu", @"osulazer", null, null, true);
|
||||
//should we schedule a retry on completion of this check?
|
||||
bool scheduleRetry = true;
|
||||
|
||||
if (!updateManager.IsInstalledApp)
|
||||
return;
|
||||
|
||||
var info = await updateManager.CheckForUpdate();
|
||||
if (info.ReleasesToApply.Count > 0)
|
||||
try
|
||||
{
|
||||
ProgressNotification n = new UpdateProgressNotification
|
||||
if (updateManager == null) updateManager = await UpdateManager.GitHubUpdateManager(@"https://github.com/ppy/osu", @"osulazer", null, null, true);
|
||||
|
||||
var info = await updateManager.CheckForUpdate(!useDeltaPatching);
|
||||
if (info.ReleasesToApply.Count == 0)
|
||||
//no updates available. bail and retry later.
|
||||
return;
|
||||
|
||||
if (notification == null)
|
||||
{
|
||||
Text = @"Downloading update..."
|
||||
};
|
||||
Schedule(() => notification.Post(n));
|
||||
Schedule(() => n.State = ProgressNotificationState.Active);
|
||||
await updateManager.DownloadReleases(info.ReleasesToApply, (int p) => Schedule(() => n.Progress = p / 100f));
|
||||
Schedule(() => n.Text = @"Installing update...");
|
||||
await updateManager.ApplyReleases(info, (int p) => Schedule(() => n.Progress = p / 100f));
|
||||
Schedule(() => n.State = ProgressNotificationState.Completed);
|
||||
notification = new UpdateProgressNotification { State = ProgressNotificationState.Active };
|
||||
Schedule(() => notificationOverlay.Post(notification));
|
||||
}
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
notification.Progress = 0;
|
||||
notification.Text = @"Downloading update...";
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
await updateManager.DownloadReleases(info.ReleasesToApply, p => Schedule(() => notification.Progress = p / 100f));
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
notification.Progress = 0;
|
||||
notification.Text = @"Installing update...";
|
||||
});
|
||||
|
||||
await updateManager.ApplyReleases(info, p => Schedule(() => notification.Progress = p / 100f));
|
||||
|
||||
Schedule(() => notification.State = ProgressNotificationState.Completed);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (useDeltaPatching)
|
||||
{
|
||||
Logger.Error(e, @"delta patching failed!");
|
||||
|
||||
//could fail if deltas are unavailable for full update path (https://github.com/Squirrel/Squirrel.Windows/issues/959)
|
||||
//try again without deltas.
|
||||
checkForUpdateAsync(false, notification);
|
||||
scheduleRetry = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.Error(e, @"update failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception)
|
||||
{
|
||||
//check again every 30 minutes.
|
||||
Scheduler.AddDelayed(updateChecker, 60000 * 30);
|
||||
// we'll ignore this and retry later. can be triggered by no internet connection or thread abortion.
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (scheduleRetry)
|
||||
{
|
||||
//check again in 30 minutes.
|
||||
Scheduler.AddDelayed(() => checkForUpdateAsync(), 60000 * 30);
|
||||
if (notification != null)
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
FadeIn(1000);
|
||||
this.FadeIn(1000);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
}
|
||||
|
||||
class UpdateProgressNotification : ProgressNotification
|
||||
private class UpdateProgressNotification : ProgressNotification
|
||||
{
|
||||
protected override Notification CreateCompletionNotification() => new ProgressCompletionNotification(this)
|
||||
private OsuGame game;
|
||||
|
||||
protected override Notification CreateCompletionNotification() => new ProgressCompletionNotification
|
||||
{
|
||||
Text = @"Update ready to install. Click to restart!",
|
||||
Activated = () =>
|
||||
{
|
||||
UpdateManager.RestartApp();
|
||||
// Squirrel returns execution to us after the update process is started, so it's safe to use Wait() here
|
||||
UpdateManager.RestartAppWhenExited().Wait();
|
||||
game.GracefullyExit();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, OsuGame game)
|
||||
{
|
||||
this.game = game;
|
||||
|
||||
IconContent.AddRange(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow)
|
||||
},
|
||||
new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Icon = FontAwesome.fa_upload,
|
||||
Colour = Color4.White,
|
||||
Size = new Vector2(20),
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user