1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-15 07:42:37 +08:00

Compare commits

...

4188 Commits

1413 changed files with 75275 additions and 14375 deletions
+20 -3
View File
@@ -1,7 +1,7 @@
{
"version": "0.2.0",
"configurations": [{
"name": "osu! (VisualTests)",
"name": "osu! VisualTests (Debug)",
"windows": {
"type": "clr"
},
@@ -18,7 +18,24 @@
"console": "internalConsole"
},
{
"name": "osu! (debug)",
"name": "osu! VisualTests (Release)",
"windows": {
"type": "clr"
},
"type": "mono",
"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"
},
@@ -32,7 +49,7 @@
"console": "internalConsole"
},
{
"name": "osu! (release)",
"name": "osu! (Release)",
"windows": {
"type": "clr"
},
+41 -33
View File
@@ -2,62 +2,70 @@
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"command": "msbuild",
"type": "shell",
"suppressTaskName": true,
"args": [
"/property:GenerateFullPaths=true",
"/property:DebugType=portable",
"/verbosity:minimal",
"/m" //parallel compiling support.
],
"tasks": [{
"taskName": "Build (Debug)",
"label": "Build (Debug)",
"type": "shell",
"command": "msbuild",
"args": [
"/p:GenerateFullPaths=true",
"/p:DebugType=portable",
"/m",
"/v:m"
],
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": [
"$msCompile"
]
"problemMatcher": "$msCompile"
},
{
"taskName": "Build (Release)",
"label": "Build (Release)",
"type": "shell",
"command": "msbuild",
"args": [
"/property:Configuration=Release"
"/p:Configuration=Release",
"/p:DebugType=portable",
"/p:GenerateFullPaths=true",
"/m",
"/v:m"
],
"problemMatcher": [
"$msCompile"
]
"group": "build",
"problemMatcher": "$msCompile"
},
{
"taskName": "Clean (Debug)",
"label": "Clean (Debug)",
"type": "shell",
"command": "msbuild",
"args": [
"/target:Clean"
"/p:DebugType=portable",
"/p:GenerateFullPaths=true",
"/m",
"/t:Clean",
"/v:m"
],
"problemMatcher": [
"$msCompile"
]
"problemMatcher": "$msCompile"
},
{
"taskName": "Clean (Release)",
"label": "Clean (Release)",
"type": "shell",
"command": "msbuild",
"args": [
"/target:Clean",
"/property:Configuration=Release"
"/p:Configuration=Release",
"/p:GenerateFullPaths=true",
"/p:DebugType=portable",
"/m",
"/t:Clean",
"/v:m"
],
"problemMatcher": [
"$msCompile"
]
"problemMatcher": "$msCompile"
},
{
"taskName": "Clean All",
"label": "Clean All",
"dependsOn": [
"Clean (Debug)",
"Clean (Release)"
],
"problemMatcher": [
"$msCompile"
]
"problemMatcher": "$msCompile"
}
]
}
+36
View File
@@ -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
View File
@@ -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 -1
View File
@@ -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
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="opentk-develop" value="https://www.myget.org/F/opentk-develop" />
</packageSources>
</configuration>
+8 -3
View File
@@ -8,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 (tested on macOS, linux and windows). We recommend using [Visual Studio Code](https://code.visualstudio.com/) (all platforms) or [Visual Studio Community Edition](https://www.visualstudio.com/) (windows only), both of which are free.
- Make sure you initialise and keep submodules up-to-date.
- 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://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-framework/issues).
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.
+80
View File
@@ -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;
}
}
}
+63
View File
@@ -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)
{
}
}
}
+23
View File
@@ -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;
}
}
+119
View File
@@ -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
}
}
+23
View File
@@ -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;
}
}
}
+35
View File
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// 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("symcol.Toys")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[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
// 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("f34ac16c-e590-4d70-a069-a748326852bf")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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")]
[assembly: AssemblyFileVersion("1.0.0.0")]
+95
View File
@@ -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)
}
};
}
}
}
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// 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("Symcol.Rulesets.Core")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[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
// 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("552b5940-c647-4060-aa4d-61baac415c72")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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")]
[assembly: AssemblyFileVersion("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();
}
}
}
+15
View File
@@ -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
}
}
+114
View File
@@ -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
}
}
};
}
}
}
+147
View File
@@ -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
};
}
}
}
+59
View File
@@ -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
};
}
}
}
+9 -4
View File
@@ -1,6 +1,7 @@
# 2017-09-14
clone_depth: 1
version: '{branch}-{build}'
image: Visual Studio 2017
configuration: Debug
cache:
- C:\ProgramData\chocolatey\bin -> appveyor.yml
@@ -8,17 +9,21 @@ cache:
- inspectcode -> appveyor.yml
- packages -> **\packages.config
install:
- cmd: git submodule update --init --recursive
- 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.2/CodeFileSanity.exe
- cmd: appveyor DownloadFile https://github.com/peppy/CodeFileSanity/releases/download/v0.2.4/CodeFileSanity.exe
before_build:
- cmd: CodeFileSanity.exe
- cmd: nuget restore
- 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" /caches-home="inspectcode" osu.sln
- cmd: inspectcode --o="inspectcodereport.xml" --projects:osu.Game* --caches-home="inspectcode" osu.sln > NUL
- cmd: NVika parsereport "inspectcodereport.xml" --treatwarningsaserrors
+2 -2
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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
-->
<configuration>
@@ -13,7 +13,7 @@ Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/maste
<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="" />
+2 -2
View File
@@ -1,4 +1,4 @@
// 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 Newtonsoft.Json;
@@ -13,4 +13,4 @@ namespace osu.Desktop.Deploy
[JsonProperty(@"name")]
public string Name;
}
}
}
+2 -2
View File
@@ -1,4 +1,4 @@
// 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 Newtonsoft.Json;
@@ -25,4 +25,4 @@ namespace osu.Desktop.Deploy
[JsonProperty(@"upload_url")]
public string UploadUrl;
}
}
}
+16 -13
View File
@@ -1,4 +1,4 @@
// 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;
@@ -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;
@@ -19,7 +18,7 @@ namespace osu.Desktop.Deploy
{
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)\MSBuild\14.0\Bin\MSBuild.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"];
@@ -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();
@@ -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...");
@@ -228,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();
@@ -391,7 +399,7 @@ namespace osu.Desktop.Deploy
public static void AuthenticatedBlockingPerform(this WebRequest r)
{
r.AddHeader("Authorization", $"token {GitHubAccessToken}");
r.BlockingPerform();
r.Perform();
}
}
@@ -401,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,4 +1,4 @@
// 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.Reflection;
+1 -9
View File
@@ -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>
@@ -22,7 +22,6 @@
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>6</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -102,19 +101,12 @@
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link>
</None>
<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>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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
-->
<packages>
@@ -1,24 +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.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
namespace osu.Desktop.Tests.Beatmaps
{
public class TestWorkingBeatmap : WorkingBeatmap
{
public TestWorkingBeatmap(Beatmap beatmap)
: base(beatmap.BeatmapInfo)
{
this.beatmap = beatmap;
}
private readonly Beatmap beatmap;
protected override Beatmap GetBeatmap() => beatmap;
protected override Texture GetBackground() => null;
protected override Track GetTrack() => null;
}
}
-29
View File
@@ -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.Tests.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,35 +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.Allocation;
using osu.Framework.Graphics;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Catch;
using osu.Game.Rulesets.Catch.UI;
using OpenTK;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseCatcher : OsuTestCase
{
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
Children = new Drawable[]
{
new CatchInputManager(rulesets.GetRuleset(2))
{
RelativeSizeAxes = Axes.Both,
Child = new CatcherArea
{
RelativePositionAxes = Axes.Both,
RelativeSizeAxes = Axes.Both,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Size = new Vector2(1, 0.2f),
}
},
};
}
}
}
@@ -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 osu.Framework.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Edit.Menus;
namespace osu.Desktop.Tests.Visual
{
public class TestCaseEditorMenuBar : OsuTestCase
{
public TestCaseEditorMenuBar()
{
Add(new EditorMenuBar
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Y = 50,
Items = new[]
{
new EditorMenuBarItem("File")
{
Items = new[]
{
new EditorMenuItem("Clear All Notes"),
new EditorMenuItem("Open Difficulty..."),
new EditorMenuItem("Save"),
new EditorMenuItem("Create a new Difficulty..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Revert to Saved"),
new EditorMenuItem("Revert to Saved (Full)"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Test Beatmap"),
new EditorMenuItem("Open AiMod"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Upload Beatmap..."),
new EditorMenuItem("Export Package"),
new EditorMenuItem("Export Map Package"),
new EditorMenuItem("Import from..."),
new EditorMenuItemSpacer(),
new EditorMenuItem("Open Song Folder"),
new EditorMenuItem("Open .osu in Notepad"),
new EditorMenuItem("Open .osb in Notepad"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Exit"),
}
},
new EditorMenuBarItem("Timing")
{
Items = new[]
{
new EditorMenuItem("Time Signature"),
new EditorMenuItem("Metronome Clicks"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Add Timing Section"),
new EditorMenuItem("Add Inheriting Section"),
new EditorMenuItem("Reset Current Section"),
new EditorMenuItem("Delete Timing Section"),
new EditorMenuItem("Resnap Current Section"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Timing Setup"),
new EditorMenuItemSpacer(),
new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive),
new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive),
new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive),
new EditorMenuItemSpacer(),
new EditorMenuItem("Set Current Position as Preview Point"),
}
},
new EditorMenuBarItem("Testing")
{
Items = new[]
{
new EditorMenuItem("Item 1"),
new EditorMenuItem("Item 2"),
new EditorMenuItem("Item 3"),
}
},
}
});
}
}
}
@@ -1,127 +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.Graphics.Containers;
using osu.Framework.Timing;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using OpenTK;
using osu.Game.Rulesets.Osu;
using osu.Framework.Allocation;
using osu.Game.Rulesets;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseHitObjects : OsuTestCase
{
private FramedClock framedClock;
private bool auto;
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
var rateAdjustClock = new StopwatchClock(true);
framedClock = new FramedClock(rateAdjustClock);
AddStep(@"circles", () => loadHitobjects(HitObjectType.Circle));
AddStep(@"slider", () => loadHitobjects(HitObjectType.Slider));
AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner));
AddToggleStep("Auto", state => { auto = state; loadHitobjects(mode); });
AddSliderStep("Playback speed", 0.0, 2.0, 0.5, v => rateAdjustClock.Rate = v);
framedClock.ProcessFrame();
var clockAdjustContainer = new Container
{
RelativeSizeAxes = Axes.Both,
Clock = framedClock,
Children = new[]
{
playfieldContainer = new OsuInputManager(rulesets.GetRuleset(0)) { RelativeSizeAxes = Axes.Both },
approachContainer = new Container { RelativeSizeAxes = Axes.Both }
}
};
Add(clockAdjustContainer);
}
private HitObjectType mode = HitObjectType.Slider;
private Container playfieldContainer;
private Container approachContainer;
private void loadHitobjects(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),
},
Distance = 400,
Position = new Vector2(-200, 0),
Velocity = 1,
TickDistance = 100,
}));
break;
case HitObjectType.Spinner:
add(new DrawableSpinner(new Spinner
{
StartTime = framedClock.CurrentTime + 600,
EndTime = framedClock.CurrentTime + 1600,
Position = new Vector2(0, 0),
}));
break;
}
}
private int depth;
private void add(DrawableOsuHitObject h)
{
h.Anchor = Anchor.Centre;
h.Depth = depth++;
if (auto)
h.State = ArmedState.Hit;
playfieldContainer.Add(h);
var proxyable = h as IDrawableHitObjectWithProxiedApproach;
if (proxyable != null)
approachContainer.Add(proxyable.ProxiedLayer.CreateProxy());
}
private enum HitObjectType
{
Circle,
Slider,
Spinner
}
}
}
@@ -1,162 +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.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Timing;
using osu.Game.Rulesets.Mania;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Timing;
using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Timing;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Objects.Drawables;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseManiaPlayfield : OsuTestCase
{
private const double start_time = 500;
private const double duration = 500;
public override string Description => @"Mania playfield";
protected override double TimePerAction => 200;
private RulesetInfo maniaRuleset;
public TestCaseManiaPlayfield()
{
var rng = new Random(1337);
AddStep("1 column", () => createPlayfield(1, SpecialColumnPosition.Normal));
AddStep("4 columns", () => createPlayfield(4, SpecialColumnPosition.Normal));
AddStep("Left special style", () => createPlayfield(4, SpecialColumnPosition.Left));
AddStep("Right special style", () => createPlayfield(4, SpecialColumnPosition.Right));
AddStep("5 columns", () => createPlayfield(5, SpecialColumnPosition.Normal));
AddStep("8 columns", () => createPlayfield(8, SpecialColumnPosition.Normal));
AddStep("Left special style", () => createPlayfield(8, SpecialColumnPosition.Left));
AddStep("Right special style", () => createPlayfield(8, SpecialColumnPosition.Right));
AddStep("Reversed", () => createPlayfield(4, SpecialColumnPosition.Normal, true));
AddStep("Notes with input", () => createPlayfieldWithNotes(false));
AddStep("Notes with input (reversed)", () => createPlayfieldWithNotes(false, true));
AddStep("Notes with gravity", () => createPlayfieldWithNotes(true));
AddStep("Notes with gravity (reversed)", () => createPlayfieldWithNotes(true, true));
AddStep("Hit explosion", () =>
{
var playfield = createPlayfield(4, SpecialColumnPosition.Normal);
int col = rng.Next(0, 4);
var note = new DrawableNote(new Note { Column = col }, ManiaAction.Key1)
{
AccentColour = playfield.Columns.ElementAt(col).AccentColour
};
playfield.OnJudgement(note, new ManiaJudgement { Result = HitResult.Perfect });
});
}
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
maniaRuleset = rulesets.GetRuleset(3);
}
private SpeedAdjustmentContainer createTimingChange(double time, bool gravity) => new ManiaSpeedAdjustmentContainer(new MultiplierControlPoint(time)
{
TimingPoint = { BeatLength = 1000 }
}, gravity ? ScrollingAlgorithm.Gravity : ScrollingAlgorithm.Basic);
private ManiaPlayfield createPlayfield(int cols, SpecialColumnPosition specialPos, bool inverted = false)
{
Clear();
var inputManager = new ManiaInputManager(maniaRuleset, cols) { RelativeSizeAxes = Axes.Both };
Add(inputManager);
ManiaPlayfield playfield;
inputManager.Add(playfield = new ManiaPlayfield(cols)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
SpecialColumnPosition = specialPos
});
playfield.Inverted.Value = inverted;
return playfield;
}
private void createPlayfieldWithNotes(bool gravity, bool inverted = false)
{
Clear();
var rateAdjustClock = new StopwatchClock(true) { Rate = 1 };
var inputManager = new ManiaInputManager(maniaRuleset, 4) { RelativeSizeAxes = Axes.Both };
Add(inputManager);
ManiaPlayfield playfield;
inputManager.Add(playfield = new ManiaPlayfield(4)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Clock = new FramedClock(rateAdjustClock)
});
playfield.Inverted.Value = inverted;
if (!gravity)
playfield.Columns.ForEach(c => c.Add(createTimingChange(0, false)));
for (double t = start_time; t <= start_time + duration; t += 100)
{
if (gravity)
playfield.Columns.ElementAt(0).Add(createTimingChange(t, true));
playfield.Add(new DrawableNote(new Note
{
StartTime = t,
Column = 0
}, ManiaAction.Key1));
if (gravity)
playfield.Columns.ElementAt(3).Add(createTimingChange(t, true));
playfield.Add(new DrawableNote(new Note
{
StartTime = t,
Column = 3
}, ManiaAction.Key4));
}
if (gravity)
playfield.Columns.ElementAt(1).Add(createTimingChange(start_time, true));
playfield.Add(new DrawableHoldNote(new HoldNote
{
StartTime = start_time,
Duration = duration,
Column = 1
}, ManiaAction.Key2));
if (gravity)
playfield.Columns.ElementAt(2).Add(createTimingChange(start_time, true));
playfield.Add(new DrawableHoldNote(new HoldNote
{
StartTime = start_time,
Duration = duration,
Column = 2
}, ManiaAction.Key3));
}
}
}
@@ -1,25 +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.Graphics.Colour;
using osu.Framework.Graphics.Shapes;
using osu.Game.Screens.Menu;
using OpenTK.Graphics;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseMenuButtonSystem : OsuTestCase
{
public override string Description => @"Main menu button system";
public TestCaseMenuButtonSystem()
{
Add(new Box
{
Colour = ColourInfo.GradientVertical(Color4.Gray, Color4.WhiteSmoke),
RelativeSizeAxes = Framework.Graphics.Axes.Both,
});
Add(new ButtonSystem());
}
}
}
@@ -1,57 +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.Graphics.Containers;
using osu.Framework.Logging;
using osu.Game.Screens.Play;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseMenuOverlays : OsuTestCase
{
public override string Description => @"Tests pause and fail overlays";
public TestCaseMenuOverlays()
{
FailOverlay failOverlay;
PauseContainer.PauseOverlay pauseOverlay;
var retryCount = 0;
Add(pauseOverlay = new PauseContainer.PauseOverlay
{
OnResume = () => Logger.Log(@"Resume"),
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
});
Add(failOverlay = new FailOverlay
{
OnRetry = () => Logger.Log(@"Retry"),
OnQuit = () => Logger.Log(@"Quit"),
});
AddStep(@"Pause", delegate
{
if (failOverlay.State == Visibility.Visible)
{
failOverlay.Hide();
}
pauseOverlay.Show();
});
AddStep("Fail", delegate
{
if (pauseOverlay.State == Visibility.Visible)
{
pauseOverlay.Hide();
}
failOverlay.Show();
});
AddStep("Add Retry", delegate
{
retryCount++;
pauseOverlay.Retries = retryCount;
failOverlay.Retries = retryCount;
});
}
}
}
-56
View File
@@ -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 osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Overlays.Mods;
using osu.Game.Rulesets;
using osu.Game.Screens.Play.HUD;
using OpenTK;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseMods : OsuTestCase
{
public override string Description => @"Mod select overlay and in-game display";
private ModSelectOverlay modSelect;
private ModDisplay modDisplay;
private RulesetStore rulesets;
[BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{
this.rulesets = rulesets;
}
protected override void LoadComplete()
{
base.LoadComplete();
Add(modSelect = new ModSelectOverlay
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
});
Add(modDisplay = new ModDisplay
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Position = new Vector2(0, 25),
});
modDisplay.Current.BindTo(modSelect.SelectedMods);
AddStep("Toggle", modSelect.ToggleVisibility);
foreach (var ruleset in rulesets.AllRulesets)
AddStep(ruleset.CreateInstance().Description, () => modSelect.Ruleset.Value = ruleset);
}
}
}
@@ -1,113 +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.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
namespace osu.Desktop.Tests.Visual
{
[TestFixture]
internal class TestCaseNotificationOverlay : OsuTestCase
{
public override string Description => @"I handle notifications";
private readonly NotificationOverlay manager;
public TestCaseNotificationOverlay()
{
progressingNotifications.Clear();
Content.Add(manager = new NotificationOverlay
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
});
AddToggleStep(@"show", state => manager.State = state ? Visibility.Visible : Visibility.Hidden);
AddStep(@"simple #1", sendNotification1);
AddStep(@"simple #2", sendNotification2);
AddStep(@"progress #1", sendProgress1);
AddStep(@"progress #2", sendProgress2);
AddStep(@"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)
Scheduler.AddDelayed(() => sendBarrage(remaining - 1), 80);
}
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.IsAlive && 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);
}
private readonly 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,102 +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.Tests.Platform;
using osu.Framework.MathUtils;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Rulesets;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
namespace osu.Desktop.Tests.Visual
{
internal class TestCasePlaySongSelect : OsuTestCase
{
private readonly BeatmapManager manager;
public override string Description => @"with fake data";
private readonly RulesetStore rulesets;
public TestCasePlaySongSelect()
{
PlaySongSelect songSelect;
if (manager == null)
{
var storage = new TestStorage(@"TestCasePlaySongSelect");
var backingDatabase = storage.GetDatabase(@"client");
backingDatabase.CreateTable<StoreVersion>();
rulesets = new RulesetStore(backingDatabase);
manager = new BeatmapManager(storage, null, backingDatabase, rulesets, null);
for (int i = 0; i < 100; i += 10)
manager.Import(createTestBeatmapSet(i));
}
Add(songSelect = new PlaySongSelect());
AddStep(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
AddStep(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; });
AddStep(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; });
AddStep(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
}
private BeatmapSetInfo createTestBeatmapSet(int i)
{
return new BeatmapSetInfo
{
OnlineBeatmapSetID = 1234 + i,
Hash = "d8e8fca2dc0f896fd7cb4cb0031ba249",
Metadata = new BeatmapMetadata
{
OnlineBeatmapSetID = 1234 + i,
// Create random metadata, then we can check if sorting works based on these
Artist = "MONACA " + RNG.Next(0, 9),
Title = "Black Song " + RNG.Next(0, 9),
Author = "Some Guy " + RNG.Next(0, 9),
},
Beatmaps = new List<BeatmapInfo>(new[]
{
new BeatmapInfo
{
OnlineBeatmapID = 1234 + i,
Ruleset = rulesets.Query<RulesetInfo>().First(),
Path = "normal.osu",
Version = "Normal",
Difficulty = new BeatmapDifficulty
{
OverallDifficulty = 3.5f,
}
},
new BeatmapInfo
{
OnlineBeatmapID = 1235 + i,
Ruleset = rulesets.Query<RulesetInfo>().First(),
Path = "hard.osu",
Version = "Hard",
Difficulty = new BeatmapDifficulty
{
OverallDifficulty = 5,
}
},
new BeatmapInfo
{
OnlineBeatmapID = 1236 + i,
Ruleset = rulesets.Query<RulesetInfo>().First(),
Path = "insane.osu",
Version = "Insane",
Difficulty = new BeatmapDifficulty
{
OverallDifficulty = 7,
}
},
}),
};
}
}
}
@@ -1,220 +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 NUnit.Framework;
using OpenTK;
using osu.Desktop.Tests.Beatmaps;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Framework.Timing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Timing;
using osu.Game.Rulesets.UI;
namespace osu.Desktop.Tests.Visual
{
/// <summary>
/// The most minimal implementation of a playfield with scrolling hit objects.
/// </summary>
[TestFixture]
public class TestCaseScrollingPlayfield : OsuTestCase
{
public TestCaseScrollingPlayfield()
{
Clock = new FramedClock();
var objects = new List<HitObject>();
int time = 1500;
for (int i = 0; i < 50; i++)
{
objects.Add(new TestHitObject { StartTime = time });
time += 500;
}
Beatmap b = new Beatmap
{
HitObjects = objects,
BeatmapInfo = new BeatmapInfo
{
Difficulty = new BeatmapDifficulty(),
Metadata = new BeatmapMetadata()
}
};
WorkingBeatmap beatmap = new TestWorkingBeatmap(b);
TestRulesetContainer horizontalRulesetContainer;
Add(horizontalRulesetContainer = new TestRulesetContainer(Axes.X, beatmap, true));
TestRulesetContainer verticalRulesetContainer;
Add(verticalRulesetContainer = new TestRulesetContainer(Axes.Y, beatmap, true));
AddStep("Reverse direction", () =>
{
horizontalRulesetContainer.Playfield.Reverse();
verticalRulesetContainer.Playfield.Reverse();
});
}
[Test]
public void TestSpeedAdjustmentOrdering()
{
var hitObjectContainer = new ScrollingPlayfield.ScrollingHitObjectContainer(Axes.X);
var speedAdjustments = new[]
{
new SpeedAdjustmentContainer(new MultiplierControlPoint()),
new SpeedAdjustmentContainer(new MultiplierControlPoint(1000)
{
TimingPoint = new TimingControlPoint { BeatLength = 500 }
}),
new SpeedAdjustmentContainer(new MultiplierControlPoint(2000)
{
TimingPoint = new TimingControlPoint { BeatLength = 1000 },
DifficultyPoint = new DifficultyControlPoint { SpeedMultiplier = 2}
}),
new SpeedAdjustmentContainer(new MultiplierControlPoint(3000)
{
TimingPoint = new TimingControlPoint { BeatLength = 1000 },
DifficultyPoint = new DifficultyControlPoint { SpeedMultiplier = 1}
}),
};
var hitObjects = new[]
{
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = -1000 }),
new DrawableTestHitObject(Axes.X, new TestHitObject()),
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 1000 }),
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 2000 }),
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 3000 }),
new DrawableTestHitObject(Axes.X, new TestHitObject { StartTime = 4000 }),
};
hitObjects.ForEach(h => hitObjectContainer.Add(h));
speedAdjustments.ForEach(hitObjectContainer.AddSpeedAdjustment);
// The 0th index in hitObjectContainer.SpeedAdjustments is the "default" control point
// Check multiplier of the default speed adjustment
Assert.AreEqual(1, hitObjectContainer.SpeedAdjustments[0].ControlPoint.Multiplier);
Assert.AreEqual(1, speedAdjustments[0].ControlPoint.Multiplier);
Assert.AreEqual(2, speedAdjustments[1].ControlPoint.Multiplier);
Assert.AreEqual(2, speedAdjustments[2].ControlPoint.Multiplier);
Assert.AreEqual(1, speedAdjustments[3].ControlPoint.Multiplier);
// Check insertion of hit objects
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[4].Contains(hitObjects[0]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[3].Contains(hitObjects[1]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[2].Contains(hitObjects[2]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[1].Contains(hitObjects[3]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[0].Contains(hitObjects[4]));
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[0].Contains(hitObjects[5]));
hitObjectContainer.RemoveSpeedAdjustment(hitObjectContainer.SpeedAdjustments[3]);
// The hit object contained in this speed adjustment should be resorted into the one occuring before it
Assert.IsTrue(hitObjectContainer.SpeedAdjustments[3].Contains(hitObjects[1]));
}
private class TestRulesetContainer : ScrollingRulesetContainer<TestPlayfield, TestHitObject>
{
private readonly Axes scrollingAxes;
public TestRulesetContainer(Axes scrollingAxes, WorkingBeatmap beatmap, bool isForCurrentRuleset)
: base(null, beatmap, isForCurrentRuleset)
{
this.scrollingAxes = scrollingAxes;
}
public new TestPlayfield Playfield => base.Playfield;
public override ScoreProcessor CreateScoreProcessor() => new TestScoreProcessor();
public override PassThroughInputManager CreateInputManager() => new PassThroughInputManager();
protected override BeatmapConverter<TestHitObject> CreateBeatmapConverter() => new TestBeatmapConverter();
protected override Playfield CreatePlayfield() => new TestPlayfield(scrollingAxes);
protected override DrawableHitObject<TestHitObject> GetVisualRepresentation(TestHitObject h) => new DrawableTestHitObject(scrollingAxes, h);
}
private class TestScoreProcessor : ScoreProcessor<TestHitObject>
{
protected override void OnNewJudgement(Judgement judgement)
{
}
}
private class TestBeatmapConverter : BeatmapConverter<TestHitObject>
{
protected override IEnumerable<Type> ValidConversionTypes => new[] { typeof(HitObject) };
protected override IEnumerable<TestHitObject> ConvertHitObject(HitObject original, Beatmap beatmap)
{
yield return original as TestHitObject;
}
}
private class DrawableTestHitObject : DrawableScrollingHitObject<TestHitObject>
{
public DrawableTestHitObject(Axes scrollingAxes, TestHitObject hitObject)
: base(hitObject)
{
Anchor = scrollingAxes == Axes.Y ? Anchor.TopCentre : Anchor.CentreLeft;
Origin = Anchor.Centre;
AutoSizeAxes = Axes.Both;
Add(new Circle
{
Size = new Vector2(50)
});
}
protected override void UpdateState(ArmedState state)
{
}
}
private class TestPlayfield : ScrollingPlayfield
{
protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content;
public TestPlayfield(Axes scrollingAxes)
: base(scrollingAxes)
{
InternalChildren = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.2f
},
content = new Container { RelativeSizeAxes = Axes.Both }
};
}
public void Reverse() => Reversed.Toggle();
}
private class TestHitObject : HitObject
{
}
}
}
@@ -1,25 +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.Game.Overlays;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseSettings : OsuTestCase
{
public override string Description => @"Tests the settings overlay";
private readonly SettingsOverlay settings;
public TestCaseSettings()
{
Children = new[] { settings = new MainSettings() };
}
protected override void LoadComplete()
{
base.LoadComplete();
settings.ToggleVisibility();
}
}
}
@@ -1,19 +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.Game.Screens.Play;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseSkipButton : OsuTestCase
{
public override string Description => @"Skip skip skippediskip";
protected override void LoadComplete()
{
base.LoadComplete();
Add(new SkipButton(Clock.CurrentTime + 5000));
}
}
}
@@ -1,48 +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.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.MathUtils;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Desktop.Tests.Visual
{
internal class TestCaseTextAwesome : OsuTestCase
{
public override string Description => @"Tests display of icons";
public TestCaseTextAwesome()
{
FillFlowContainer flow;
Add(flow = new FillFlowContainer
{
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 SpriteIcon
{
Icon = fa,
Size = new Vector2(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;
}
}
}
}
-178
View File
@@ -1,178 +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.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>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<LangVersion>6</LangVersion>
</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="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">
<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="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="System.Drawing" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Beatmaps\TestWorkingBeatmap.cs" />
<Compile Include="Platform\TestStorage.cs" />
<Compile Include="Visual\OsuTestCase.cs" />
<Compile Include="Visual\TestCaseBeatmapDetailArea.cs" />
<Compile Include="Visual\TestCaseBeatmapDetails.cs" />
<Compile Include="Visual\TestCaseBeatmapOptionsOverlay.cs" />
<Compile Include="Visual\TestCaseBeatSyncedContainer.cs" />
<Compile Include="Visual\TestCaseBreadcrumbs.cs" />
<Compile Include="Visual\TestCaseCatcher.cs" />
<Compile Include="Visual\TestCaseChatDisplay.cs" />
<Compile Include="Visual\TestCaseContextMenu.cs" />
<Compile Include="Visual\TestCaseDialogOverlay.cs" />
<Compile Include="Visual\TestCaseDirect.cs" />
<Compile Include="Visual\TestCaseDrawableRoom.cs" />
<Compile Include="Visual\TestCaseDrawings.cs" />
<Compile Include="Visual\TestCaseGamefield.cs" />
<Compile Include="Visual\TestCaseGraph.cs" />
<Compile Include="Visual\TestCaseHitObjects.cs" />
<Compile Include="Visual\TestCaseKeyConfiguration.cs" />
<Compile Include="Visual\TestCaseKeyCounter.cs" />
<Compile Include="Visual\TestCaseLeaderboard.cs" />
<Compile Include="Visual\TestCaseManiaHitObjects.cs" />
<Compile Include="Visual\TestCaseManiaPlayfield.cs" />
<Compile Include="Visual\TestCaseMedalOverlay.cs" />
<Compile Include="Visual\TestCaseEditorMenuBar.cs" />
<Compile Include="Visual\TestCaseMenuButtonSystem.cs" />
<Compile Include="Visual\TestCaseMenuOverlays.cs" />
<Compile Include="Visual\TestCaseMods.cs" />
<Compile Include="Visual\TestCaseStoryboard.cs" />
<Compile Include="Visual\TestCaseMusicController.cs" />
<Compile Include="Visual\TestCaseNotificationOverlay.cs" />
<Compile Include="Visual\TestCaseOnScreenDisplay.cs" />
<Compile Include="Visual\TestCasePlayer.cs" />
<Compile Include="Visual\TestCasePlaySongSelect.cs" />
<Compile Include="Visual\TestCaseReplay.cs" />
<Compile Include="Visual\TestCaseReplaySettingsOverlay.cs" />
<Compile Include="Visual\TestCaseResults.cs" />
<Compile Include="Visual\TestCaseRoomInspector.cs" />
<Compile Include="Visual\TestCaseScoreCounter.cs" />
<Compile Include="Visual\TestCaseScrollingPlayfield.cs" />
<Compile Include="Visual\TestCaseSettings.cs" />
<Compile Include="Visual\TestCaseSkipButton.cs" />
<Compile Include="Visual\TestCaseSocial.cs" />
<Compile Include="Visual\TestCaseSongProgress.cs" />
<Compile Include="Visual\TestCaseTabControl.cs" />
<Compile Include="Visual\TestCaseTaikoPlayfield.cs" />
<Compile Include="Visual\TestCaseTextAwesome.cs" />
<Compile Include="Visual\TestCaseTwoLayerButton.cs" />
<Compile Include="Visual\TestCaseUserPanel.cs" />
<Compile Include="Visual\TestCaseUserProfile.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.Testing\osu.Framework.Testing.csproj">
<Project>{007b2356-ab6f-4bd9-96d5-116fc2dce69a}</Project>
<Name>osu.Framework.Testing</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.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
<Project>{58F6C80C-1253-4A0E-A465-B8C85EBEADF3}</Project>
<Name>osu.Game.Rulesets.Catch</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj">
<Project>{48F4582B-7687-4621-9CBE-5C24197CB536}</Project>
<Name>osu.Game.Rulesets.Mania</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{C92A607B-1FDD-4954-9F92-03FF547D9080}</Project>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
<Project>{F167E17A-7DE6-4AF5-B920-A5112296C695}</Project>
<Name>osu.Game.Rulesets.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="OpenTK.dll.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</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>
-13
View File
@@ -1,13 +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="10.0.3" targetFramework="net461" />
<package id="NUnit" version="3.8.1" targetFramework="net461" />
<package id="OpenTK" version="3.0.0-git00009" targetFramework="net461" />
<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>
-27
View File
@@ -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 System;
using osu.Framework.Desktop;
using osu.Framework.Platform;
using osu.Framework.VisualTests;
namespace osu.Desktop.VisualTests
{
public static class Program
{
[STAThread]
public static void Main(string[] args)
{
bool benchmark = args.Length > 0 && args[0] == @"-benchmark";
using (GameHost host = Host.GetSuitableHost(@"osu"))
{
if (benchmark)
host.Run(new AutomatedVisualTestGame());
else
host.Run(new VisualTestGame());
}
}
}
}
-35
View File
@@ -1,35 +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.Platform;
using osu.Framework.VisualTests;
using osu.Game;
using osu.Game.Screens.Backgrounds;
namespace osu.Desktop.VisualTests
{
internal class VisualTestGame : 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.UpdateThread.InactiveHz = host.UpdateThread.ActiveHz;
host.DrawThread.InactiveHz = host.DrawThread.ActiveHz;
host.InputThread.InactiveHz = host.InputThread.ActiveHz;
host.Window.CursorState |= CursorState.Hidden;
}
}
}
@@ -1,214 +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.6.1</TargetFrameworkVersion>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<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>
<LangVersion>6</LangVersion>
</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="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0\lib\net45\OpenTK.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpCompress, Version=0.17.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SharpCompress.0.17.1\lib\net45\SharpCompress.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="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="System.Drawing" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link>
</None>
<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.Testing\osu.Framework.Testing.csproj">
<Project>{007b2356-ab6f-4bd9-96d5-116fc2dce69a}</Project>
<Name>osu.Framework.Testing</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.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{c92a607b-1fdd-4954-9f92-03ff547d9080}</Project>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
<Project>{58f6c80c-1253-4a0e-a465-b8c85ebeadf3}</Project>
<Name>osu.Game.Rulesets.Catch</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Mania\osu.Game.Rulesets.Mania.csproj">
<Project>{48f4582b-7687-4621-9cbe-5c24197cb536}</Project>
<Name>osu.Game.Rulesets.Mania</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
<Project>{f167e17a-7de6-4af5-b920-a5112296c695}</Project>
<Name>osu.Game.Rulesets.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="Program.cs" />
<Compile Include="VisualTestGame.cs" />
</ItemGroup>
<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>
-13
View File
@@ -1,13 +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="10.0.2" targetFramework="net45" />
<package id="ppy.OpenTK" version="3.0" targetFramework="net45" />
<package id="SharpCompress" version="0.17.1" 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>
+22 -44
View File
@@ -1,30 +1,29 @@
// 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 osu.Game;
using System.Linq;
using System.Windows.Forms;
using osu.Framework.Platform;
using osu.Framework.Desktop.Platform;
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.Game.Screens.Menu;
using osu.Framework.Platform;
using osu.Game;
using OpenTK.Input;
namespace osu.Desktop
{
internal class OsuGameDesktop : OsuGame
{
private VersionManager versionManager;
private readonly bool noVersionOverlay;
public OsuGameDesktop(string[] args = null)
: base(args)
{
noVersionOverlay = args?.Any(a => a == "--no-version-overlay") ?? false;
}
public override Storage GetStorageForStableInstall()
@@ -46,7 +45,7 @@ namespace osu.Desktop
{
protected override string LocateBasePath()
{
Func<string, bool> checkExists = p => Directory.Exists(Path.Combine(p, "Songs"));
bool checkExists(string p) => Directory.Exists(Path.Combine(p, "Songs"));
string stableInstallPath;
@@ -83,16 +82,14 @@ namespace osu.Desktop
{
base.LoadComplete();
LoadComponentAsync(versionManager = new VersionManager { Depth = int.MinValue });
ScreenChanged += s =>
if (!noVersionOverlay)
{
if (s is Intro && s.ChildScreen == null)
LoadComponentAsync(new VersionManager { Depth = int.MinValue }, v =>
{
Add(versionManager);
versionManager.State = Visibility.Visible;
}
};
Add(v);
v.State = Visibility.Visible;
});
}
}
public override void SetHost(GameHost host)
@@ -106,38 +103,19 @@ namespace osu.Desktop
desktopWindow.Icon = new Icon(Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico"));
desktopWindow.Title = Name;
desktopWindow.DragEnter += dragEnter;
desktopWindow.DragDrop += dragDrop;
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 = (object[])e.Data.GetData(DataFormats.FileDrop);
var filePaths = dropData.Select(f => f.ToString()).ToArray();
var filePaths = new [] { e.FileName };
if (filePaths.All(f => Path.GetExtension(f) == @".osz"))
Task.Run(() => BeatmapManager.Import(filePaths));
else if (filePaths.All(f => Path.GetExtension(f) == @".osr"))
Task.Run(() =>
{
var score = ScoreStore.ReadReplayFile(filePaths.First());
Schedule(() => LoadScore(score));
});
}
var firstExtension = Path.GetExtension(filePaths.First());
private static readonly string[] allowed_extensions = { @".osz", @".osr" };
if (filePaths.Any(f => Path.GetExtension(f) != firstExtension)) return;
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 = ((object[])e.Data.GetData(DataFormats.FileDrop)).Select(f => f.ToString()).ToArray();
e.Effect = allowed_extensions.Any(ext => paths.All(p => p.EndsWith(ext))) ? DragDropEffects.Copy : DragDropEffects.None;
}
Task.Factory.StartNew(() => Import(filePaths), TaskCreationOptions.LongRunning);
}
}
}
+2 -7
View File
@@ -1,4 +1,4 @@
// 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.Framework.Platform;
@@ -24,12 +24,7 @@ namespace osu.Desktop
public override void SetHost(GameHost host)
{
base.SetHost(host);
host.UpdateThread.InactiveHz = host.UpdateThread.ActiveHz;
host.DrawThread.InactiveHz = host.DrawThread.ActiveHz;
host.InputThread.InactiveHz = host.InputThread.ActiveHz;
host.Window.CursorState |= CursorState.Hidden;
}
}
}
}
+17 -16
View File
@@ -1,26 +1,26 @@
// 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.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
using Squirrel;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
using System.Net.Http;
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 OpenTK;
using OpenTK.Graphics;
using Squirrel;
namespace osu.Desktop.Overlays
{
@@ -31,7 +31,8 @@ namespace osu.Desktop.Overlays
private OsuConfigManager config;
private OsuGameBase game;
public override bool HandleInput => false;
public override bool HandleKeyboardInput => false;
public override bool HandleMouseInput => false;
[BackgroundDependencyLoader]
private void load(NotificationOverlay notification, OsuColour colours, TextureStore textures, OsuGameBase game, OsuConfigManager config)
@@ -70,7 +71,7 @@ namespace osu.Desktop.Overlays
},
new OsuSpriteText
{
Colour = game.IsDebug ? colours.Red : Color4.White,
Colour = DebugUtils.IsDebug ? colours.Red : Color4.White,
Text = game.Version
},
}
@@ -110,7 +111,7 @@ namespace osu.Desktop.Overlays
// only show a notification if we've previously saved a version to the config file (ie. not the first run).
if (!string.IsNullOrEmpty(lastVersion))
Scheduler.AddDelayed(() => notificationOverlay.Post(new UpdateCompleteNotification(version)), 5000);
notificationOverlay.Post(new UpdateCompleteNotification(version));
}
}
@@ -197,10 +198,9 @@ namespace osu.Desktop.Overlays
}
}
}
catch (HttpRequestException)
catch (Exception)
{
//likely have no internet connection.
//we'll ignore this and retry later.
// we'll ignore this and retry later. can be triggered by no internet connection or thread abortion.
}
finally
{
@@ -232,7 +232,8 @@ namespace osu.Desktop.Overlays
Text = @"Update ready to install. Click to restart!",
Activated = () =>
{
UpdateManager.RestartAppWhenExited();
// 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;
}
+16 -5
View File
@@ -1,11 +1,12 @@
// 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.IO;
using System.Linq;
using osu.Framework.Desktop;
using osu.Framework.Desktop.Platform;
using System.Runtime;
using osu.Framework;
using osu.Framework.Platform;
using osu.Game.IPC;
namespace osu.Desktop
@@ -15,6 +16,9 @@ namespace osu.Desktop
[STAThread]
public static int Main(string[] args)
{
if (!RuntimeInfo.IsMono)
useMulticoreJit();
// Back up the cwd before DesktopGameHost changes it
var cwd = Environment.CurrentDirectory;
@@ -22,7 +26,7 @@ namespace osu.Desktop
{
if (!host.IsPrimaryInstance)
{
var importer = new BeatmapIPCChannel(host);
var importer = new ArchiveImportIPCChannel(host);
// Restore the cwd so relative paths given at the command line work correctly
Directory.SetCurrentDirectory(cwd);
foreach (var file in args)
@@ -43,10 +47,17 @@ namespace osu.Desktop
host.Run(new OsuGameDesktop(args));
break;
}
}
return 0;
}
}
private static void useMulticoreJit()
{
var directory = Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Profiles"));
ProfileOptimization.SetProfileRoot(directory.FullName);
ProfileOptimization.StartProfile("Startup.Profile");
}
}
}
+3 -3
View File
@@ -1,4 +1,4 @@
// 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.Reflection;
@@ -12,7 +12,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("ppy Pty Ltd")]
[assembly: AssemblyProduct("osu!lazer")]
[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2017")]
[assembly: AssemblyCopyright("ppy Pty Ltd 2007-2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -22,7 +22,7 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("55e28cb2-7b6c-4595-8dcc-9871d8aad7e9")]
[assembly: Guid("b0cb1d48-e4c2-4612-a347-beea7b1a71e7")]
[assembly: AssemblyVersion("0.0.0")]
[assembly: AssemblyFileVersion("0.0.0")]
+32 -3
View File
@@ -1,15 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" /></startup>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<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>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-10.0.0.0" newVersion="10.0.0.0" />
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Algorithms" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.Compression" publicKeyToken="b77a5c561934e089" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.2.0" newVersion="4.1.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.IO.FileSystem.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Security.Cryptography.Primitives" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
</configuration>
+66 -49
View File
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="14.0">
<Import Project="..\osu.Game.props" />
<PropertyGroup>
<ProjectGuid>{2A66DD92-ADB1-4994-89E2-C94E04ACDA0D}</ProjectGuid>
<ProjectGuid>{419659FD-72EA-4678-9EB8-B22A746CED70}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>WinExe</OutputType>
@@ -57,27 +58,23 @@
<UseVSHostingProcess>false</UseVSHostingProcess>
<PlatformTarget>AnyCPU</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<RunCodeAnalysis>false</RunCodeAnalysis>
<Prefer32Bit>false</Prefer32Bit>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<Commandlineparameters>
</Commandlineparameters>
<LangVersion>6</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>
</DefineConstants>
<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>
@@ -101,11 +98,8 @@
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<UseVSHostingProcess>false</UseVSHostingProcess>
<LangVersion>6</LangVersion>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<StartArguments>--tests</StartArguments>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="DeltaCompressionDotNet, Version=1.1.0.0, Culture=neutral, PublicKeyToken=1d14d6e5194e7f4a, processorArchitecture=MSIL">
@@ -141,8 +135,8 @@
<HintPath>$(SolutionDir)\packages\squirrel.windows.1.7.8\lib\Net45\NuGet.Squirrel.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>
<Reference Include="OpenTK, Version=3.0.0.0, Culture=neutral, PublicKeyToken=bad199fe84eb3df4">
<HintPath>$(SolutionDir)\packages\ppy.OpenTK.3.0.13\lib\net45\OpenTK.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpCompress, Version=0.18.1.0, Culture=neutral, PublicKeyToken=afb0a02973931d96, processorArchitecture=MSIL">
@@ -153,6 +147,18 @@
<HintPath>$(SolutionDir)\packages\Splat.2.0.0\lib\Net45\Splat.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_green, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a84b7dcfb1391f7f, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_green.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.batteries_v2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8226ea5df37bcae9, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.bundle_green.1.1.8\lib\net45\SQLitePCLRaw.batteries_v2.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1488e028ca7ab535, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.core.1.1.8\lib\net45\SQLitePCLRaw.core.dll</HintPath>
</Reference>
<Reference Include="SQLitePCLRaw.provider.e_sqlite3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9c301db686d0bd12, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\SQLitePCLRaw.provider.e_sqlite3.net45.1.1.8\lib\net45\SQLitePCLRaw.provider.e_sqlite3.dll</HintPath>
</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>
@@ -160,21 +166,13 @@
<Reference Include="System" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Extensions.dll</HintPath>
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51">
<HintPath>$(SolutionDir)\packages\System.ValueTuple.4.4.0\lib\net461\System.ValueTuple.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http.Primitives, Version=4.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>$(SolutionDir)\packages\Microsoft.Net.Http.2.2.29\lib\net45\System.Net.Http.Primitives.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
<None Include="..\osu.licenseheader">
<Link>osu.licenseheader</Link>
</None>
<None Include="app.config" />
<None Include="OpenTK.dll.config" />
<None Include="osu!.res" />
@@ -209,14 +207,16 @@
</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.Testing\osu.Framework.Testing.csproj">
<Project>{007B2356-AB6F-4BD9-96D5-116FC2DCE69A}</Project>
<Name>osu.Framework.Testing</Name>
</ProjectReference>
<Compile Include="OsuGameDesktop.cs" />
<Compile Include="OsuTestBrowser.cs" />
<Compile Include="Overlays\VersionManager.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="lazer.ico" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">
<Project>{c76bf5b3-985e-4d39-95fe-97c9c879b83a}</Project>
<Name>osu.Framework</Name>
@@ -225,14 +225,6 @@
<Project>{d9a367c9-4c1a-489f-9b05-a0cea2b53b58}</Project>
<Name>osu.Game.Resources</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Desktop.Tests\osu.Desktop.Tests.csproj">
<Project>{230ac4f3-7783-49fb-9aec-b83cda3b9f3d}</Project>
<Name>osu.Desktop.Tests</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{c92a607b-1fdd-4954-9f92-03ff547d9080}</Project>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Catch\osu.Game.Rulesets.Catch.csproj">
<Project>{58f6c80c-1253-4a0e-a465-b8c85ebeadf3}</Project>
<Name>osu.Game.Rulesets.Catch</Name>
@@ -241,24 +233,38 @@
<Project>{48f4582b-7687-4621-9cbe-5c24197cb536}</Project>
<Name>osu.Game.Rulesets.Mania</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Osu\osu.Game.Rulesets.Osu.csproj">
<Project>{c92a607b-1fdd-4954-9f92-03ff547d9080}</Project>
<Name>osu.Game.Rulesets.Osu</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Shape\osu.Game.Rulesets.Shape.csproj">
<Project>{baf6d7b6-5e48-4278-ab81-f079af640e31}</Project>
<Name>osu.Game.Rulesets.Shape</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Taiko\osu.Game.Rulesets.Taiko.csproj">
<Project>{f167e17a-7de6-4af5-b920-a5112296c695}</Project>
<Name>osu.Game.Rulesets.Taiko</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Rulesets.Vitaru\osu.Game.Rulesets.Vitaru.csproj">
<Project>{9a615027-b2ab-435e-b865-0c7209933457}</Project>
<Name>osu.Game.Rulesets.Vitaru</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj">
<Project>{54377672-20b1-40af-8087-5cf73bf3953a}</Project>
<Name>osu.Game.Tests</Name>
</ProjectReference>
<ProjectReference Include="..\osu.Game\osu.Game.csproj">
<Project>{0d3fbf8a-7464-4cf7-8c90-3e7886df2d4d}</Project>
<Project>{2a66dd92-adb1-4994-89e2-c94e04acda0d}</Project>
<Name>osu.Game</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="OsuGameDesktop.cs" />
<Compile Include="OsuTestBrowser.cs" />
<Compile Include="Overlays\VersionManager.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="lazer.ico" />
<ProjectReference Include="..\Symcol.Core\Symcol.Core.csproj">
<Project>{f34ac16c-e590-4d70-a069-a748326852bf}</Project>
<Name>Symcol.Core</Name>
</ProjectReference>
<ProjectReference Include="..\Symcol.Rulesets.Core\Symcol.Rulesets.Core.csproj">
<Project>{552b5940-c647-4060-aa4d-61baac415c72}</Project>
<Name>Symcol.Rulesets.Core</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
@@ -280,4 +286,15 @@
<PostBuildEvent>
</PostBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.linux.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.linux.targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets'))" />
<Error Condition="!Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets'))" />
</Target>
<Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.osx.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.osx.targets')" />
<Import Project="$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets" Condition="Exists('$(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlite3.v110_xp.1.1.8\build\net35\SQLitePCLRaw.lib.e_sqlite3.v110_xp.targets')" />
</Project>
+4 -6
View File
@@ -12,15 +12,13 @@
<description>click the circles. to the beat.</description>
<summary>click the circles.</summary>
<releaseNotes>testing</releaseNotes>
<copyright>Copyright ppy Pty Ltd 2007-2017</copyright>
<copyright>Copyright ppy Pty Ltd 2007-2018</copyright>
<language>en-AU</language>
</metadata>
<files>
<file src="*.exe" target="lib\net45\" exclude="**vshost**"/>
<file src="*.dll" target="lib\net45\"/>
<file src="*.config" target="lib\net45\"/>
<file src="x86\*.dll" target="lib\net45\x86\"/>
<file src="x64\*.dll" target="lib\net45\x64\"/>
<file src="**.exe" target="lib\net45\" exclude="**vshost**"/>
<file src="**.dll" target="lib\net45\"/>
<file src="**.config" target="lib\net45\"/>
</files>
</package>
+9 -3
View File
@@ -1,14 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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
-->
<packages>
<package id="DeltaCompressionDotNet" version="1.1.0" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.2.29" targetFramework="net45" />
<package id="Mono.Cecil" version="0.9.6.4" targetFramework="net45" />
<package id="OpenTK" version="3.0.0-git00009" targetFramework="net461" />
<package id="ppy.OpenTK" version="3.0.13" targetFramework="net461" />
<package id="SharpCompress" version="0.18.1" targetFramework="net461" />
<package id="Splat" version="2.0.0" targetFramework="net45" />
<package id="SQLitePCLRaw.bundle_green" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.core" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.lib.e_sqlite3.linux" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.lib.e_sqlite3.osx" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.lib.e_sqlite3.v110_xp" version="1.1.8" targetFramework="net461" />
<package id="SQLitePCLRaw.provider.e_sqlite3.net45" version="1.1.8" targetFramework="net461" />
<package id="squirrel.windows" version="1.7.8" targetFramework="net461" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="net461" />
</packages>

Some files were not shown because too many files have changed in this diff Show More