Git Product home page Git Product logo

oshu's Introduction

oshu!

Screenshot #1 Screenshot #2 Screenshot #3 Screenshot #4 Screenshot #5

Welcome to oshu!

This project was born out of frustration from not being able to play osu! on a little Linux box with no graphics card whatsoever. It's aimed at minimalistic people and probably will never contain a hundredth of the official client's features.

osu! is that PC clone of the osu! Tatakae! Ouendan DS rhythm game, occidentalized as Elite Beat Agents. osu! has got tons of cool beatmaps, and a more or less intuitive text file format described at https://osu.ppy.sh/help/wiki/osu!_File_Formats

The main problem with osu! is that it required Windows and a graphics card. Even with that, it sometimes get slow unless the computer is a beast… Hell, the mania and taiko mode could be played in a terminal!

oshu! is currently mostly targeted at Linux users, but it doesn't have to be that way. All it needs are volunteers to build and test the project on the various operating systems and desktop environments out there.

By the way, the name comes from osu! but with the s pronounced sh, because it's a mini-osu.

Getting started

First, you need to download beatmaps. The official beatmap source is https://osu.ppy.sh/beatmapsets, but it requires that you create an account from the official osu! game. If you don’t have an account, you may use a mirror like https://bloodcat.com/osu/.

The beatmaps are distributed as .osz files, which are disguised ZIP files. You need to extract using unzip or a similar tool. Rename them to .zip if your file archiver can't process it. Once extracted, you'll see one or more .osu files with various difficulty levels.

oshu! is meant to be started from the command-line, so go spawn your terminal and run oshu path/to/your/beatmap.osu.

A window will open and you'll see circles appear on the screen. You got to click the crosses when the orange circle reaches the white one. Hold the button pressed for long notes. Most players point with the mouse and press the Z/X keyboard keys instead of clicking.

For more detailed explainations, see: https://www.youtube.com/results?search_query=osu+tutorial

You can use the experimental beatmap collection browser by extracting your beatmaps to the ~/.oshu/beatmaps/ directory, the running oshu-library build-index. Point your browser to the path it tells you and start playing. Note that for your browser to open the beatmaps with oshu!, you need to make sure the desktop integration is properly set up. See the section below.

Install

Note: oshu! is still in an early stage of development. Don't expect it to be amazing. It doesn't even have a menu to select songs, you need to call it from the command line like $ oshu my_beatmap.osu.

First of all, make sure you have the required dependencies. These things are so common that I may assure you they're in your distribution's official repositories.

  • CMake 3.9,
  • a C++14 compiler,
  • pkg-config,
  • SDL2 ≥ 2.0.5,
  • SDL2_image 2.0.1,
  • ffmpeg 3.3.6,
  • cairo 1.14.8,
  • pango 1.40.14.

Note that the versions specified above are indicative. It is very likely your build will work with older or newer versions. If you need support for a specific version, feel free to ask.

To build oshu!, follow the standard CMake procedure:

mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=~/.local -DOSHU_DEFAULT_SKIN=osu ..
make && make install

If you do use the $HOME/.local prefix, make sure you add ~/.local/bin to your PATH, or invoke oshu! by specifying the full path like ~/.local/bin/oshu BEATMAP.osu.

The -DOSHU_DEFAULT_SKIN=osu causes CMake to download the default osu! skin and make it the default. If you're satisfied with the minimal skin, or if you can't connect to Internet, you may leave out this option, or write out explicitly -DOSHU_DEFAULT_SKIN=minimal.

If you want to install skins without making them the default, you can list them like -DOSHU_SKINS=minimal;osu.

The files required for desktop integration are deployed with make install, but you may need to refresh the cache databases yourself. Note that package managers are usually good at refreshing them automatically.

You may force the refreshing with:

update-desktop-database $PREFIX/share/applications
update-mime-database $PREFIX/share/mime

Goals

Let's clarify the goals before we stray too far away from them.

These things are the raison d'être of oshu:

  • All the Osu beatmaps should be playable.
  • The game should run on the lowest-end millenial computer one can find.

This means if you find an unsupported beatmap or a computer too slow to run oshu, feel free to submit a bug report.

The first versions are going to focus on the regular game mode, and hopefully oshu will support more game modes someday.

Since it's a hobby project, the feature set will be probably be quite limited for a while. For example:

  • No health bar.
  • No spinner. (I hate those.)
  • No network play.
  • No video background.
  • No fancy visual effects.

But it just means I probably won't have the time to work on these. These limitations are not a design choice. Contributions are welcome!

Documentation

The user manual's man page is installed in the standard man directory, but you may view it directly from share/man/.

For the technical documentation, please look at CONTRIBUTING.md.

oshu's People

Contributors

cafehaine avatar fmang avatar jamuwu avatar lanodan avatar shir0kamii avatar vperus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

oshu's Issues

Sliders support

After #2.

Once the sliders are parsed, let's display them.

The geometry module already supplies the path methods required to draw any kind of curves, and the graphics module also has a oshu_draw_path and oshu_draw_thick_path routine.

Once they're displayed, let's adapt the game module to support them.

No need to support ticks or accurate scoring. As long the the main idea is there, it will be fine for the next minor release.

Display metadata

Right now there's not even parsed.

Would be nice if at least they appeared in the window's title, and on the terminal output.

Get rid of the terminal

Right now, while it stays playable even without, the console is the only way to see the beatmap's metadata and the score at the end.

These pieces of information should be displayed on screen, but while printing text is easy, printing it right is harder. There are toy libraries like SDL2_ttf and cairo's truetype module. Then there's the full-blown option: pango.

Pango's got a cairo back-end, so it's sane to integrate it.

Errors and warnings will still be printed on the console, to help debugging, but it won't be a requirement anymore.

Consider integrating some C++

C is a great challenge, but I find myself avoiding efficient data containers like maps because it's pain to code and use in C.

I definitely wanna avoid any overkill object-oriented model with design patterns, but modern C++11 with a minimal use of OOP should already make memory management much easier.

Training mode

What if there existed a mode where every time a note is missed, the song is automatically rewinded by a few seconds to replay the missed part.

To be smarter, the game could wait until the combo ends or until there is a tiny break before rewinding abruptly.

When to resume could also be smartly computed by resuming at the previous combo, so that the context is somewhat preserved. Replaying a few notes out of nowhere won't help.

FPS counter

The current FPS rate limiter is a dumb SDL_Delay(20) at every game iteration.

Instead, we should see how long the drawing phase took and adjust the delay. The longer the drawing operation takes, the less we should sleep.

Now, it happens that drawing seems to take so little time it can't be felt, even with that naive rate limiter.

Lint

I haven't used a linter for oshu! so far 😇

Clang-Tidy or CppCheck can probably help detect a few potential errors. I should at least try them out of curiosity.

Windows support

There's no reason oshu! wouldn't work on Windows, but someone has to build it.

A few things probably won't work right away, like getopt or possibly some POSIX function calls here and there.

  1. Tweak the code until it builds.
  2. Port the desktop integrations.
  3. Make an installer.

Continuous Integration

As @lanodan suggested, the linting process #53, but also the test suite #44 could be run automatically through a continuous integration service like Travis.

It's a bit far from now, but it's definitely worth considering.

Update the man page with the new controls

With seeking and the new key event handling, the keys are likely to change.

Let's not forget to update the man page accordingly, as it's the only help the user has so far.

Fancy homepage

Rather than use the README on GitHub as the official homepage of oshu, a hand-made home should prove more welcoming, with download links and everything.

Seeking

You might want to train on a specific part of a song, and be able to play the same 10 seconds over and over until you get it right.

Warn when running below 60 FPS

With the FPS counter, the delay between two game iterations is variable, but aims at maintaining 60 FPS.

When we detect that drawing takes more time than the maximum delay, it means the computer is too slow, and we should print a warning on the user's console. Once, not at every frame.

Game clock, or implement lead in

Currently, the game engine only uses the audio clock.

The problem is that some beatmaps start immediately, and for this reason have a lead in property.

To implement this lead-in feature, let's build a game clock on top of the audio clock.

The game clock starts at negative lead-in, and increases to 0 using the system clock. When it reaches 0, the playback starts and the game clock will relay the audio clock.

Inherit the addition set from sample set?

The extra field may set the sample set but not the addition set, and then it sounds more natural to use that sample rather for the additions too rather than fetch the timing point.

For slider edges, same thing.

Consistent parsing interface

I got a bit confused when making the parser draft. How to split the actual parsing of, say, a hit object, and its linking into the beatmap structure.

To have a clearer scheme, let's call things like that:

int process_thing(struct parser_state *parser);
int parse_thing(struct parser_state *parser, *out);

First, you'll notice these don't include the line pointer, because it should be contained inside the parser state. Each parsing function will consume that buffer in-place with strsep or key_value.

The process functions are going to be actions that dispatch the parsing to somebody else, then store their result in the parser state or parser state's beatmap directly.

The parse functions actually parse things and return a result via a point argument.

Both process and parse functions return an int which is 0 on success and -1 on error. It's always the callee's responsibility to display error messages using oshu_log_error, and guarantee that no memory is leaked on failure.

Fancy graphics with Cairo

Cairo is a nice vector graphics library, though somewhat heavy. We could use it to draw hit objects, especially sliders, and possibly also text.

Desktop integration

Could be nice if we managed to get file managers to detect .osu files and spawn oshu automatically when double-clicking on them.

This issue is specifically targeted at Gnome and KDE users, so we had better test on these two environments. However, it's common XDG stuff.

  1. Make a logo.
  2. Make a oshu.desktop file for share/applications/
  3. Make an x-osu.xml file for share/mime/packages/
  4. Install them with automake.
  5. Make a packaging guideline explaining how to use xdg-mime to make oshu the default application.

Once this is ready, the next step is #35.

Test the beatmap module

Writing unit tests for a game is no easy task, but fortunately some modules are pure and easy to test. In particular, the beatmap parser and the geometry module.

When playing the following beatmaps, I can't help but feel like the sound effects are… weird:

  • 431396 SENTIVE - Tsuki Usagi -Gekkouyoku- [Lyric's Usagi]
  • 651934 Kaori Oda - Zero Tokei (Short ver.) [Shining]
  • 596833 96neko - Aimai Elegy/96neko - Aimai Elegy (Lasse) [Hard]

It's probably gonna be a tedious task, but I believe the best way to validate the hit parser would be to record an autoplay from the official osu! game and manually identify the played sound samples for the first dozens of hit objects. Then, write that using oshu!'s beatmap structure in a unit test, and check that the parser does interpret the correct thing.

Note that the parser module applies inheritance when parsing, so what appears in the resulting structure is ready to use by the game, and not exactly what's written in the beatmap file. Let's really focus on the expected result from the actual osu! game, rather than guess what the beatmap means.

Get standard

The code currently enabled system extensions, and in particular asprintf.

With C++'s standard string streams, we can construct fancy strings with simpler code and with memory management issues.

Let's drop the AC_USE_SYSTEM_EXTENSIONS macro from configure.ac!

Mania mode

After #4.

Considering oshu!'s current player community, maybe supporting the mania mode before the fancy graphics and sound effects is a cool idea.

Autokey & automouse

You know how autoplay shows you a perfect run?

The task could be split into 2 parts: one that controls the mouse, and another that controls the mouse. The mode could be selected used something like --autoplay=key.

This could ease training by letting you focus on either the mouse or the keyboard, though I think autokey is the more useful mode, because in the osu mode, the mouse the harder part. For the keyboard-only modes, automouse makes so sense and autokey is the same as autoplay.

Background pictures

After #7.

The current drawing engine only draws 1-pixel lines, so if we start drawing a complicated picture behind, things are going to get really difficult.

When we have solid filled hit objects, the background is one step away.

Split the beatmap parser

The current beatmap parser is pretty intricate, because the parsing process is not as simple as it sounds.

I'd consider splitting it into two phases:

  1. The first phase reads the beatmap as a character stream, and generates a raw AST, faithful to the original contents.
  2. The second phase interprets the raw AST and builds a high-level beatmap object. In particular, it implements inheritance, slider path normalization, unit conversion.

Pros:

  • Makes the code and the concepts easier to understand by splitting the task into 2 clear units.
  • Makes the parser easier to test. See #44.
  • Supports parsing beatmaps with misordered sections or objects.

Cons:

  • Performance. An all-in-once process will eat less RAM and CPU. Probably a non-issue since the parser represents a tiny fraction of oshu!'s load time.

Alternative: SAX-like parser

SAX is a way to parse XML by reacting to events like “opened ”, “found a text node”.

For a beatmap, those events would be “got a metadata key-value”, “got a hit object”. These would be defined in an abstract class as pure virtual methods. The beatmap parser then calls these methods as it reads the beatmap.

This approach effectively split the raw decoding logic, and the interpreation logic. I gets most of the pros above, without the cons. It won't support unordered objects naively though.

The two ways aren't incompatible, as the AST builder could be easily implemented using that abstract interface.

Composable coordinate system

The current implementation of the game module allow fancy projections in three coordinates systems: window, viewport, and game.

Now, this is never gonna fit the other game modes, so something has to be done.

Here's a sample data structure:

struct oshu_view {
       struct oshu_point origin;
       double width;
       double height;
       double zoom;
};

Then,

oshu_translate_view(view, x, y)
oshu_scale_view(view, zoom)
oshu_fit_view(view, w, h)
oshu_reset_view(view)

Calling fit and translate will update the view's fields, taking into account their previous values, so that you may fit and translate repeatedly with evolving results.

Note that the structure is a mere restriction of a 3×3 transformation matrix for 2D homogeneous coordinates, which forces aspect ratio preservation and prevents rotations.

As for matrices, there remains the issue of the order. Do we multiply transformations on the left, or on the right? I'd say on the right, so that the game coordinate system looks like that:

oshu_fit_view(view, 640, 480)
oshu_translate_view(view, 64, 48)

What's also nice with the restriction is that it's easy to inverse. No need to keep track of an unprojection matrix.

libavfilter pipeline

libavfilter is a graph-based audio filtering library.

It provides in particular:

  • Multi-stream mixing. It's probably more sophisticated than SDL's standard mixing function.
  • Volume management.
  • Buffering. We're currently managing the frame cursor ourselves, while libavfilter provides an audio sink interface of customizable size. If we make it the same size as SDL's audio buffer, the audio callback is going to be trivial.

I'm not sure if libavfilter would let us add or remove branches to our graph, so if we assume we'll never play more than, say, 8 samples at once, we can pre-generate a graph with 8 streams and activate them as needed.

Related to #8, because as soon as we get fuller sample sets, we'd like to play them together.

Variable circle radius

The beatmap tells in the Difficulty section how big the circles should be.

However, the unit is strange. Either we'll try to find out something that gives good enough results, or we'll inspect osu!'s source code to see how it is interpreted.

The game and graphics are are already flexible, so it's really just a matter of tweaking the beatmap parser.

Support lower hardware specs

Today, I've tried to play oshu! on my Raspberry Pi 2. The first try was a disaster, but tweaking the right settings made the game playable.

  1. Accelerated graphics are a lie. By forcing the software renderer in the SDL_Renderer, the performance got much better. Maybe it has to do with my X configuration, or maybe fbturbo isn't meant for that.
  2. The default window size is also a significant factor. The common textures are generated when the game start, taking into account the window size at that time. Starting with a smaller screen will generate smaller textures. Alternatively, an environment variable could control the texture quality disregarding the window size. At 640×480 the game got playable, even though it skipped frames.
  3. The background is currently loaded at full resolution. By scaling it at load time before converting it to a texture, we'd save a lot of video memory, and accelerate the background drawing process by a big factor.
  4. The SDL_HINT_RENDER_SCALE_QUALITY is set to linear, which is pretty expensive. Supporting the nearest algorithm would increase the performance by a large factor, and if the window is not resized, the textures will appear smoothly at 1:1 scale.
  5. If the worst come to worst, decrease the frame rate. I'd rather avoid that, it's like admitting defeat.

Beatmap indexer

We could use the web browser to display a fancy beatmap index, and when the user opens a .osu file, the browser would start oshu.

This could be even generated using a bash script, but for cross-platform support, C remains a better option.

The tool could look like this:

  • oshu-lib browse: spawn the web browser at $LIBRARY/browser/index.html. This is how oshu should appear in an application menu.
  • oshu-lib add beatmap.osz: unpack the beatmap in $LIBRARY/beatmaps/. This should be the default action for .osz files.
  • oshu-lib update: rebuild the HTML documents, in case the library was externally changed.

After #31, oshu should be the default choice for .osu files, and links can be more explicit with:

<a href="beatmap.osu" type="application/x-osu">Beatmap</a>

More verbose logging with -vv

It's common to add more -v to increase the verbosity.

Right now, only the debug level is supported. It could be nice to support the verbose level.

Design a better beatmap format

The format of the .osu files is silly, and sometimes I think it might be worth the effort to make a beatmap compiler.

Because compiling a beatmap doesn't require any kind of performance, this could be written in a super high and slow language, and generate a MessagePack with all the computations done. oshu! would then just load it naively.

In particular:

  • No more silly unit: use seconds or pixels, rather than stars-ish.
  • No more inheritance: keep the sample set explicit.
  • No more mystic constants: write 'clap' for clap, not 8.
  • Normalized paths, instead of keeping a separate path length.
  • Simpler arcs: one center and two angles, rather than three points.
  • Colors defined as #RRGGBB.

That format could hopefully become a candidate for a future official format!

If the MessagePack is limited to scalars, lists and maps, it might as well be JSON, YAML or whatever. The serialization in itself is irrelevant, yay. gzip could be added on top of it, if needed.

But first, I should finish my work on the .osu wiki article: ppy/osu-wiki#811

Maybe then #44 comes first still, to ensure the current parser could be used as a reference. Alternatively, this issue might become handy because comparing a serialized MessagePack with a reference result is super easy.

Mac OS X support

I'd expect it to work with hardly any modification to the code, but I have no idea how to use that Mac thing.

  1. Make sure everything builds.
  2. Find a way to port the desktop integrations.
  3. Package everything into a handy .dmg or whatever Mac uses.

Sound effects

Rather than using only the same high hat sound, oshu! should support a bigger sample set and customizable samples.

These are the whistle, clap sound effects, but also the normal, drum and soft sample sets.

The audio module already has stub for the sampleset sub-module.

Profile the code

Following #43.

Rather than disabling features to get better performance, maybe the code could be optimized to make the features lighter.

Let's try someday to run a profiler to see where the code spends time. We could detect a stupid bottleneck.

Shrink or expand paths for sliders

The special pixelLength value of sliders should be used to adjust the actual length of the paths.

For arcs, this means changing the end_angle. Easy enough.

For linear sliders, even easier.

For Bézier though, this is though. To shrink the path, the normalize function is good enough. All that's needed is to convert the t-coordinates into l-coordinates by dividing them by the pixel length and not the actual computed length.

We could assert at first the the pixelLength is shorter than the curves. Otherwise, the naive solution is to compute the length difference and add an extra straight segment at the end before calling the normalization procedure.

Redesign the game module

The current game module is a rigid prototype, enough to see a working game, but not flexible enough to add more game modes.

The parts specific to the osu! game mode, both graphical and the gameplay should be moved to its own osu.c module.

The remaining common part will handle window events and standard controls, but will call an external module to draw the screen and handle key and mouse events.

We could imagine an interface like that:

struct oshu_game_mode {
    void (*draw)(struct oshu_game *game);
    void (*key_pressed)(struct oshu_game *game);
    void (*mouse_pressed)(struct oshu_game *game);
    ...
};

Alternatively, make a dispatcher function is the game module like that:

void draw(struct game_mode *game)
{
    if (game->mode == OSU)
        oshu_osu_draw(game);
    else if (game->mode == MANIA)
        oshu_mania_draw(game);
}

The thing we wanna avoid at all cost is having a single module handling two different game modes.

Normalize the Bézier slider length

The current Bézier slider implemention assumes that all the segments of a Bézier curve have the same length. Looks like in practice, this doesn't hold.

How does the official client handle this? Is it okay to have some fast segments and some slow segments? Not that we're especially interested in how it's implemented, just how it's supposed to move.

In any case, it's pretty easy to compute the length of a segment. Then all we'll have to do is adjust the t-coordinate mapping to take it into account.

Strict slider release

Following the original gameplay, sliders can be held indefinitely long.

When the slider ends, even if the user keeps holding it, it's marked as a good hit.

I think it would be better, even though it's gonna be admittedly harder, to mark late slider releases as misses.

Cooler parser errors

On error, the parser should print no only the error, but also the line number.

What about a wrapper like that:

void parser_error(struct parser_state *parser, const char *fmt, ...);

Organize the source code in sub-directories

Using automake's subdir-objects, we'll be able to create sub-directories in the src/ directory, and have a tree like that:

  • audio/
    • audio.h
    • audio.c
  • beatmap/
    • geometry.h
    • geometry.c
    • beatmap.h
    • beatmap.c
  • graphics/
    • graphics.h
    • draw.c
    • display.c
  • game/
    • game.h
    • game.c
    • osu.c
    • mania.c
    • taiko.c

As soon as the game module gets complicated with several modes, it's gonna help visualize the project a lot better.

Bézier curve expansion

Looks like some beatmaps do use the slider extension feature.

Now, since only a few of them use it, let's abort the normalization process mid-way when the lengths don't match to add an extra segment, then call the normalization again.

That way, it won't affect most sliders in terms of performance.

Parse sliders

The parser should be able to parse all three kinds of parsers: linear, perfect arcs and Bézier curves.

The additions don't matter though. The most important aspect is the control points array.

Silent mode

Maybe it could be nice to have a quiet / silent mode for people that want to enjoy the music without the sound effects.

More generally, it could be a customizable settings to cut the volume without disabling them completely, through some --sfx-volume command-line argument, for example.

New naming convention for functions

Rather than naming functions like oshu_audio_play, use oshu_play_audio instead. It has a nicer ring to it, even though it won't be as systematical and consistent I guess.

Let's have fun!

Proper freeing of beatmaps

The current beatmap destroyer don't bother with blocks allocated inside it, like Bézier paths. That's bad.

This is the kind of thing to test with a test program and valgrind.

Cool terminal output

Let's display something nice with colors.

Let's use stdout with ANSI escape sequences rather than those crude info log messages.

The user wanna see at least the beatmap's metadata, but information about the audio, especially the duration, would be nice to have too. That's pretty much what's being displayed today, but there are nicer ways to do it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.