commit be3296acb9852725482d0cbb6b502099c9bf5f98 Author: mrbesen Date: Sun May 30 21:56:21 2021 +0200 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1f39b97 --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +*.bin +*.out +build/ +*.exe +.gdb_history + +*.so +*.bmp +*.d +*.a +log.txt + +test +.vscode/settings.json + +fontbot +fontbot_strip + +config.json + + diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..5fcb50c --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/src/", + "${workspaceFolder}/include/beatsaber/", + "${workspaceFolder}/include/beatsaber-impl/" + ], + "defines": [], + "compilerPath": "/usr/bin/g++", + "cStandard": "c11", + "cppStandard": "c++17", + "intelliSenseMode": "gcc-x64" + } + ], + "version": 4 +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..b37f7d1 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,50 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "test Debuggen (gdb)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/test", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Automatische Strukturierung und Einrückung für \"gdb\" aktivieren", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "make test", + "miDebuggerPath": "/usr/bin/gdb" + }, + { + "name": "Debuggen (gdb)", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/fontbot", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Automatische Strukturierung und Einrückung für \"gdb\" aktivieren", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "make all", + "miDebuggerPath": "/usr/bin/gdb" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..e68935d --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,31 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "make all", + "type": "shell", + "command": "make -j all", + "group": { + "kind": "build", + "isDefault": true + }, + "problemMatcher": [ + "$gcc" + ] + }, + { + "label": "make clean", + "type": "shell", + "command": "make clean", + "problemMatcher": [] + }, + { + "label": "make test", + "type": "shell", + "command": "make -j test", + "problemMatcher": ["$gcc"], + } + ] +} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e4d3c9f --- /dev/null +++ b/Makefile @@ -0,0 +1,62 @@ +# Author Yannis Gerlach +# Hochschule Osnabrück +# 13.11.2020 + +# `make clean all` nicht mit -j verwenden! -> race condition im make file +# statdessen: `make clean; make all -j` verwenden + +NAME = libBeatsaber.a +NAMETEST = test +CFLAGS = -std=c++17 -O2 -pipe -Wall -Wextra -Wno-unused-parameter -Wpedantic -rdynamic +CXX = g++ +SRCF = src/ +BUILDDIR = build/ +TESTF = tests/ +DEPF = $(BUILDDIR)deps/ +INCF = ./include/ +INCFS = $(shell find $(INCF) -type d) + +INCLUDES = $(addprefix -I, $(INCFS)) +LDFLAGS = + +SRCFILES = $(shell find $(SRCF) -name "*.cpp") +OBJFILES = $(patsubst $(SRCF)%, $(BUILDDIR)%, $(patsubst %.cpp, %.o, $(SRCFILES))) $(LOGO) +DEPFILES = $(wildcard $(DEPF)*.d) + +SOURCEDIRS = $(shell find $(SRCF) -type d -printf "%p/\n") +BUILDDIRS = $(patsubst $(SRCF)%, $(BUILDDIR)%, $(SOURCEDIRS)) + +OBJFILESTEST = $(OBJFILES) + +INCLUDES += $(addprefix -I, $(SOURCEDIRS)) + +all: $(NAME) runtest + +$(NAME): | $(BUILDDIRS) $(DEPF) $(OBJFILES) + @$(AR) rvs $@ $(filter %.o, $^) + +$(BUILDDIR)%.o: $(SRCF)%.cpp + @echo "Compiling: $@" + @$(CXX) $(CFLAGS) $(INCLUDES) $< -MM -MT $@ > $(DEPF)$(subst /,_,$*).d + @$(CXX) -c -o $@ $(CFLAGS) $(INCLUDES) $< + +%/: + mkdir -p $@ + +clean-depends: + $(RM) -r $(DEPF) + +clean: + $(RM) -r $(NAME) $(BUILDDIR) $(NAMETEST) + +$(NAMETEST): $(BUILDDIRS) $(DEPF) $(TESTF)*.cpp $(OBJFILESTEST) $(NAME) + @echo "Compiling tests" + @$(CXX) -o $@ $(filter %.o, $^) $(filter %.cpp, $^) $(filter %.a, $^) $(CFLAGS) $(INCLUDES) $(LDFLAGS) + +runtest: $(NAMETEST) + @echo "Running tests" + ./$< + +.PHONY: clean all $(NAMETEST) clean-depends runtest + +include $(DEPFILES) diff --git a/include/beatsaber-impl/beatmapimpl.h b/include/beatsaber-impl/beatmapimpl.h new file mode 100644 index 0000000..ee498dd --- /dev/null +++ b/include/beatsaber-impl/beatmapimpl.h @@ -0,0 +1,56 @@ +#pragma once + +#include "beatmap.h" + +#include + +#include "beatset.h" + +using json = nlohmann::json; + +namespace Beatsaber { + +class BeatMapImpl : public BeatMap { + +protected: + const std::string path; + const bool isZip; + + json infobase; + std::vector> beatSets; + + bool load(); + +public: + BeatMapImpl(const std::string& path, bool isZip); + ~BeatMapImpl(); + + virtual std::string getVersion() const override; + virtual std::string getSongName() const override; + virtual std::string getSubName() const override; + virtual std::string getSongAuthorName() const override; + virtual std::string getMapperName() const override; + virtual double getBPM() const override; + virtual double getTimeOffset() const override; + virtual double getSchuffle() const override; + virtual double getSchufflePeriod() const override; + virtual double getPreviewStart() const override; + virtual double getPreviewDuration() const override; + virtual std::string getSongFilename() const override; + virtual std::string getImageFilename() const override; + virtual std::string getEnvName() const override; + virtual std::string get360EnvName() const override; + virtual std::string getCustomData() const override; + + virtual const std::vector>& getBeatSets() const override; + virtual std::uint32_t getBeatSetCount() const override; + virtual const std::shared_ptr getBeatSet(BeatmapCharacteristic::BeatmapCharacteristic characteristic = BeatmapCharacteristic::STANDARD) const override; + virtual std::shared_ptr getBeatSet(BeatmapCharacteristic::BeatmapCharacteristic characteristic = BeatmapCharacteristic::STANDARD) override; + + virtual void printDebug() const override; + + friend std::unique_ptr BeatMap::loadFromFolder(const std::string& folderPath); + friend std::unique_ptr BeatMap::loadFromZip(const std::string& zipPath); +}; + +} diff --git a/include/beatsaber-impl/beatsetimpl.h b/include/beatsaber-impl/beatsetimpl.h new file mode 100644 index 0000000..ce33561 --- /dev/null +++ b/include/beatsaber-impl/beatsetimpl.h @@ -0,0 +1,23 @@ +#include "beatset.h" + +#include + +using json = nlohmann::json; + +namespace Beatsaber { + +class BeatSetImpl : public BeatSet { +protected: + + BeatmapCharacteristic::BeatmapCharacteristic characteristic; + +public: + BeatSetImpl(const json& j); + BeatSetImpl(const BeatSetImpl& c) = default; + BeatSetImpl() = default; + virtual ~BeatSetImpl(); + + virtual BeatmapCharacteristic::BeatmapCharacteristic getCharacteristic() const; +}; + +} \ No newline at end of file diff --git a/include/beatsaber/beatmap.h b/include/beatsaber/beatmap.h new file mode 100644 index 0000000..e6c82cd --- /dev/null +++ b/include/beatsaber/beatmap.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include +#include + +#include "beatmapcharacteristic.h" +#include "beatset.h" + +namespace Beatsaber { + +class BeatLevel { +public: + +}; + +class BeatMap { +public: + virtual ~BeatMap() {} + + virtual std::string getVersion() const = 0; + virtual std::string getSongName() const = 0; + virtual std::string getSubName() const = 0; + virtual std::string getSongAuthorName() const = 0; + virtual std::string getMapperName() const = 0; + virtual double getBPM() const = 0; + virtual double getTimeOffset() const = 0; + virtual double getSchuffle() const = 0; + virtual double getSchufflePeriod() const = 0; + virtual double getPreviewStart() const = 0; //in seconds + virtual double getPreviewDuration() const = 0; //in seconds + virtual std::string getSongFilename() const = 0; + virtual std::string getImageFilename() const = 0; + virtual std::string getEnvName() const = 0; + virtual std::string get360EnvName() const = 0; + virtual std::string getCustomData() const = 0; + + virtual const std::vector>& getBeatSets() const = 0; + virtual std::uint32_t getBeatSetCount() const = 0; + virtual const std::shared_ptr getBeatSet(BeatmapCharacteristic::BeatmapCharacteristic characteristic = BeatmapCharacteristic::STANDARD) const = 0; + virtual std::shared_ptr getBeatSet(BeatmapCharacteristic::BeatmapCharacteristic characteristic = BeatmapCharacteristic::STANDARD) = 0; + + virtual void printDebug() const = 0; + + static std::unique_ptr loadFromFolder(const std::string& folderPath); + static std::unique_ptr loadFromZip(const std::string& zipPath); + +}; + +} \ No newline at end of file diff --git a/include/beatsaber/beatmapcharacteristic.h b/include/beatsaber/beatmapcharacteristic.h new file mode 100644 index 0000000..a5b26a6 --- /dev/null +++ b/include/beatsaber/beatmapcharacteristic.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace Beatsaber { + namespace BeatmapCharacteristic { + enum BeatmapCharacteristic : std::uint8_t { + NONE, + STANDARD, + NOARROWS, + ONESABER, + DEGREE360, + DEGREE90, + LIGHTSHOW, + LAWLESS, + }; + + const std::string characteristicsName[] {"None", "Standard", "NoArrows", "OneSaber", "360Degree", "90Degree", "Lightshow", "Lawless"}; + const std::uint8_t characteristicsNameSize = sizeof(characteristicsName)/sizeof(std::string); + + BeatmapCharacteristic getByString(const std::string& str); + } +} \ No newline at end of file diff --git a/include/beatsaber/beatset.h b/include/beatsaber/beatset.h new file mode 100644 index 0000000..0501a57 --- /dev/null +++ b/include/beatsaber/beatset.h @@ -0,0 +1,15 @@ +#pragma once + + +#include "beatmapcharacteristic.h" + +namespace Beatsaber { + +class BeatSet { +public: + virtual ~BeatSet() {} + + virtual BeatmapCharacteristic::BeatmapCharacteristic getCharacteristic() const = 0; +}; + +} \ No newline at end of file diff --git a/include/beatsaber/difficulties.h b/include/beatsaber/difficulties.h new file mode 100644 index 0000000..95ecc48 --- /dev/null +++ b/include/beatsaber/difficulties.h @@ -0,0 +1,16 @@ +#pragma once + +#include + +namespace Beatsaber { + namespace Difficulty { + enum Difficulty : std::uint8_t { + NONE, + EASY, + NORMAL, + HARD, + EXPERT, + EXPERTP, + }; + } +} \ No newline at end of file diff --git a/src/beatmap.cpp b/src/beatmap.cpp new file mode 100644 index 0000000..cef2930 --- /dev/null +++ b/src/beatmap.cpp @@ -0,0 +1,158 @@ +#include "beatmapimpl.h" + +#include +#include //debug print + +#include "beatsetimpl.h" + +namespace Beatsaber { + +bool BeatMapImpl::load() { + // try to open info.dat + if(isZip) { + return false; + } + std::ifstream info(path + "/info.dat"); //try diffrent filenames if not found? + try { + info >> infobase; + + + //load the beatset + const json& beatsets = infobase["_difficultyBeatmapSets"]; + if(beatsets.is_array()) { + beatSets.reserve(beatsets.size()); + + //load all the beatsets + for(const json& jsonbeatset : beatsets) { + beatSets.push_back(std::make_shared(jsonbeatset)); + } + } + + return true; + } catch(...) {} //catch any json errors + return false; +} + +BeatMapImpl::BeatMapImpl(const std::string& path, bool isZip) : path(path), isZip(isZip) {} + +BeatMapImpl::~BeatMapImpl() {} + +std::string BeatMapImpl::getVersion() const { + return infobase.value("_version", ""); +} + +std::string BeatMapImpl::getSongName() const { + return infobase.value("_songName", ""); +} + +std::string BeatMapImpl::getSubName() const { + return infobase.value("_songSubName", ""); +} + +std::string BeatMapImpl::getSongAuthorName() const { + return infobase.value("_songAuthorName", ""); +} + +std::string BeatMapImpl::getMapperName() const { + return infobase.value("_levelAuthorName", ""); +} + +double BeatMapImpl::getBPM() const { + return infobase.value("_beatsPerMinute", -1); +} + +double BeatMapImpl::getTimeOffset() const { + return infobase.value("_songTimeOffset", 0); +} + +double BeatMapImpl::getSchuffle() const { + return infobase.value("_shuffle", 0); +} + +double BeatMapImpl::getSchufflePeriod() const { + return infobase.value("_shufflePeriod", 0); +} + +double BeatMapImpl::getPreviewStart() const { + return infobase.value("_previewStartTime", 0); +} + +double BeatMapImpl::getPreviewDuration() const { + return infobase.value("_previewDuration", 0); +} + +std::string BeatMapImpl::getSongFilename() const { + return infobase.value("_songFilename", ""); +} + +std::string BeatMapImpl::getImageFilename() const { + return infobase.value("_coverImageFilename", ""); +} + +std::string BeatMapImpl::getEnvName() const { + return infobase.value("_environmentName", ""); +} + +std::string BeatMapImpl::get360EnvName() const { + return infobase.value("_allDirectionsEnvironmentName", ""); +} + +std::string BeatMapImpl::getCustomData() const { + return infobase["_customData"].dump(); +} + +const std::vector>& BeatMapImpl::getBeatSets() const { + return beatSets; +} + +std::uint32_t BeatMapImpl::getBeatSetCount() const { + return beatSets.size(); +} + +const std::shared_ptr BeatMapImpl::getBeatSet(BeatmapCharacteristic::BeatmapCharacteristic characteristic) const { + for(auto it = beatSets.begin(); it != beatSets.end(); ++it) { + if((*it)->getCharacteristic() == characteristic) { + return *it; + } + } + return nullptr; +} + +std::shared_ptr BeatMapImpl::getBeatSet(BeatmapCharacteristic::BeatmapCharacteristic characteristic) { + for(auto it = beatSets.begin(); it != beatSets.end(); ++it) { + if((*it)->getCharacteristic() == characteristic) { + return *it; + } + } + return nullptr; +} + +void BeatMapImpl::printDebug() const { + std::cout << "SongName: " << getSongName() << " - " << getSongAuthorName() << " (" << getSubName() << ")" + << "\nMapper: " << getMapperName() + << "\nVersion: " << getVersion() + << "\nBPM: " << getBPM() << " offset: " << getTimeOffset() + << "\nSchuffle " << getSchuffle() << " period: " << getSchufflePeriod() + << "\nPreviewStart: " << getPreviewStart() << " duration: " << getPreviewDuration() + << "\nSongFile: " << getSongFilename() + << "\nImageFile: " << getImageFilename() + << "\nEnvName: " << getEnvName() << " 360Env: " << get360EnvName() + << "\ncustomData: " << getCustomData() + << "\nBeatSetCount: " << getBeatSetCount() + << std::endl; +} + + +std::unique_ptr BeatMap::loadFromFolder(const std::string& folderPath) { + auto map = std::make_unique(folderPath, false); + if(!map->load()) return nullptr; + return map; +} + +std::unique_ptr BeatMap::loadFromZip(const std::string& zipPath) { + auto map = std::make_unique(zipPath, true); + if(!map->load()) return nullptr; + return map; +} + +} \ No newline at end of file diff --git a/src/beatset.cpp b/src/beatset.cpp new file mode 100644 index 0000000..036847a --- /dev/null +++ b/src/beatset.cpp @@ -0,0 +1,16 @@ +#include "beatsetimpl.h" + +#include + +namespace Beatsaber { + +BeatSetImpl::BeatSetImpl(const json& j) : characteristic(BeatmapCharacteristic::getByString(j["_beatmapCharacteristicName"])) { +} + +BeatSetImpl::~BeatSetImpl() {} + +BeatmapCharacteristic::BeatmapCharacteristic BeatSetImpl::getCharacteristic() const { + return characteristic; +} + +} \ No newline at end of file diff --git a/src/enums.cpp b/src/enums.cpp new file mode 100644 index 0000000..0f5c2dd --- /dev/null +++ b/src/enums.cpp @@ -0,0 +1,16 @@ +#include "beatmapcharacteristic.h" + +namespace Beatsaber { +namespace BeatmapCharacteristic { + +BeatmapCharacteristic getByString(const std::string& str) { + for(uint8_t i = 0; i < characteristicsNameSize; ++i) { + if(str == characteristicsName[i]) { //TODO equals ignore Case + return (BeatmapCharacteristic) i; + } + } + return BeatmapCharacteristic::NONE; +} + +} +} \ No newline at end of file diff --git a/tests/main.cpp b/tests/main.cpp new file mode 100644 index 0000000..0b179c5 --- /dev/null +++ b/tests/main.cpp @@ -0,0 +1,34 @@ +#include +#include "test.h" + +#include "beatmap.h" + +//tests + +test_t tests[] = {NULL}; + +int main(int argc, char** argv) { + + test_t* current = tests; + int failcount = 0; + int testcount = 0; + for(; *current; current++) { + testcount++; + printf("\033[1mRunning test number: %d ", testcount); + if((*current)()) { + printf("\033[1;92msucceeded\033[0;1m!\n"); + } else { + printf("\033[1;91mfailed\033[0;1m\n"); + failcount++; + } + } + + printf("\033[1;93m%d\033[0;1m/%d failed\n", failcount, testcount); + + //simple read test + std::unique_ptr bmap = Beatsaber::BeatMap::loadFromFolder("/media/satassd/steam/steamapps/common/Beat Saber/Beat Saber_Data/CustomLevels/1dd (Portal - Still Alive (Uppermost Remix) - kryptikos)"); + if(!bmap) std::cout << "Could not load File" << std::endl; + else bmap->printDebug(); + + return failcount > 0; +} diff --git a/tests/test.h b/tests/test.h new file mode 100644 index 0000000..890d25b --- /dev/null +++ b/tests/test.h @@ -0,0 +1,11 @@ +#define TESTFAILED 0 +#define TESTGOOD 1 + +#include + +#define TESTDATA "./tests/data/" + +#define ASSERT(BED, ERR) if(!(BED)) { std::cout << __FILE__ << ":" << __LINE__ << " " << ERR << std::endl; return TESTFAILED; } +// #define ASSERT(BED) ASSERT(BED, "") + +typedef int (*test_t)();