reading basic structure

This commit is contained in:
mrbesen 2021-06-01 21:05:33 +02:00
parent 37edb342fa
commit fd6f908671
Signed by: MrBesen
GPG Key ID: 596B2350DCD67504
17 changed files with 214 additions and 35 deletions

View File

@ -7,7 +7,7 @@
NAME = libBeatsaber.a
NAMETEST = test
CFLAGS = -std=c++17 -O2 -pipe -Wall -Wextra -Wno-unused-parameter -Wpedantic -rdynamic
CFLAGS = -std=c++17 -O2 -pipe -Wall -Wextra -Wno-unused-parameter -Wpedantic -rdynamic -g
CXX = g++
SRCF = src/
BUILDDIR = build/
@ -20,25 +20,38 @@ INCLUDES = $(addprefix -I, $(INCFS))
LDFLAGS =
SRCFILES = $(shell find $(SRCF) -name "*.cpp")
OBJFILES = $(patsubst $(SRCF)%, $(BUILDDIR)%, $(patsubst %.cpp, %.o, $(SRCFILES))) $(LOGO)
OBJFILES = $(patsubst $(SRCF)%, $(BUILDDIR)%, $(patsubst %.cpp, %.o, $(SRCFILES)))
DEPFILES = $(wildcard $(DEPF)*.d)
SOURCEDIRS = $(shell find $(SRCF) -type d -printf "%p/\n")
BUILDDIRS = $(patsubst $(SRCF)%, $(BUILDDIR)%, $(SOURCEDIRS))
OBJFILESTEST = $(OBJFILES)
INCLUDES += $(addprefix -I, $(SOURCEDIRS))
# FEATURES
# zipFile support
DEFINES += -DBEATSABERZIPSUPPORT=1
# link zipios dynamic
LDFLAGS += -lzipios
# OR link zipios static (path to static lib)
#OBJFILES += /usr/local/lib/libzipios.a
#LDFLAGS += -lz #libzlib is still required dynamic
OBJFILESTEST = $(OBJFILES)
all: $(NAME) runtest
$(NAME): | $(BUILDDIRS) $(DEPF) $(OBJFILES)
$(NAME): $(OBJFILES) | $(BUILDDIRS) $(DEPF)
@$(AR) rvs $@ $(filter %.o, $^)
$(BUILDDIR)%.o: $(SRCF)%.cpp
$(BUILDDIR)%.o: $(SRCF)%.cpp | $(BUILDDIRS) $(DEPF)
@echo "Compiling: $@"
@$(CXX) $(CFLAGS) $(INCLUDES) $< -MM -MT $@ > $(DEPF)$(subst /,_,$*).d
@$(CXX) -c -o $@ $(CFLAGS) $(INCLUDES) $<
@$(CXX) $(CFLAGS) $(DEFINES) $(INCLUDES) $< -MM -MT $@ > $(DEPF)$(subst /,_,$*).d
@$(CXX) -c -o $@ $(CFLAGS) $(DEFINES) $(INCLUDES) $<
%/:
mkdir -p $@
@ -51,7 +64,7 @@ clean:
$(NAMETEST): $(BUILDDIRS) $(DEPF) $(TESTF)*.cpp $(OBJFILESTEST) $(NAME)
@echo "Compiling tests"
@$(CXX) -o $@ $(filter %.o, $^) $(filter %.cpp, $^) $(filter %.a, $^) $(CFLAGS) $(INCLUDES) $(LDFLAGS)
@$(CXX) -o $@ $(filter %.o, $^) $(filter %.cpp, $^) $(filter %.a, $^) $(CFLAGS) $(DEFINES) $(INCLUDES) $(LDFLAGS)
runtest: $(NAMETEST)
@echo "Running tests"

View File

@ -8,7 +8,7 @@ using json = nlohmann::json;
namespace Beatsaber {
class BeatLevelImpl : public BeatLevel, protected std::enable_shared_from_this<BeatLevelImpl> {
class BeatLevelImpl : public BeatLevel, public std::enable_shared_from_this<BeatLevelImpl> {
protected:
std::weak_ptr<BeatSet> parent;
@ -34,6 +34,8 @@ public:
//TODO: get level content
virtual void printDebug() const override;
virtual std::shared_ptr<BeatSet> getBeatSet() const override;
virtual std::shared_ptr<BeatMap> getBeatMap() const override;
};

View File

@ -11,7 +11,7 @@ using json = nlohmann::json;
namespace Beatsaber {
class BeatMapImpl : public BeatMap, protected std::enable_shared_from_this<BeatMapImpl> {
class BeatMapImpl : public BeatMap, public std::enable_shared_from_this<BeatMapImpl> {
protected:
const std::string path;
@ -50,8 +50,8 @@ public:
virtual void printDebug() const override;
friend std::unique_ptr<BeatMap> BeatMap::loadFromFolder(const std::string& folderPath);
friend std::unique_ptr<BeatMap> BeatMap::loadFromZip(const std::string& zipPath);
friend std::shared_ptr<BeatMap> BeatMap::loadFromFolder(const std::string& folderPath);
friend std::shared_ptr<BeatMap> BeatMap::loadFromZip(const std::string& zipPath);
};
}

View File

@ -6,12 +6,13 @@ using json = nlohmann::json;
namespace Beatsaber {
class BeatSetImpl : public BeatSet, protected std::enable_shared_from_this<BeatSetImpl> {
class BeatSetImpl : public BeatSet, public std::enable_shared_from_this<BeatSetImpl> {
protected:
std::weak_ptr<BeatMap> parent;
BeatmapCharacteristic::BeatmapCharacteristic characteristic;
std::vector<std::shared_ptr<BeatLevel>> level;
public:
BeatSetImpl(std::weak_ptr<BeatMap> p, const json& j);
@ -19,6 +20,8 @@ public:
BeatSetImpl() = default;
virtual ~BeatSetImpl();
virtual void printDebug() const override;
virtual BeatmapCharacteristic::BeatmapCharacteristic getCharacteristic() const override;
virtual std::shared_ptr<BeatMap> getBeatMap() const override;
};

View File

@ -0,0 +1,20 @@
#pragma once
#include <memory>
#include <string>
#include <istream>
// this classes form a abstraction to read from folders and zipfiles the same way. Maybe add other sources too?
namespace Beatsaber {
//Interface
class FileReader {
public:
virtual ~FileReader() {}
virtual std::shared_ptr<std::istream> getFileStream(const std::string& filename) = 0;
};
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "filereader.h"
#if BEATSABERZIPSUPPORT == 1
#include <zipios/zipfile.hpp>
#endif
namespace Beatsaber {
//implementation for folders
class FolderReader : public FileReader {
protected:
std::string path;
public:
FolderReader(const std::string& path);
virtual ~FolderReader();
virtual std::shared_ptr<std::istream> getFileStream(const std::string& filename) override;
};
#if BEATSABERZIPSUPPORT == 1
//implementation for zipfiles
class ZipReader : public FileReader {
protected:
zipios::ZipFile file;
public:
ZipReader(const std::string& path);
virtual ~ZipReader();
virtual std::shared_ptr<std::istream> getFileStream(const std::string& filename) override;
};
#endif
}

View File

@ -25,6 +25,8 @@ public:
//TODO: get level content
virtual void printDebug() const = 0;
virtual std::shared_ptr<BeatSet> getBeatSet() const = 0; // parent
virtual std::shared_ptr<BeatMap> getBeatMap() const = 0; // grandparent

View File

@ -40,8 +40,8 @@ public:
virtual void printDebug() const = 0;
static std::unique_ptr<BeatMap> loadFromFolder(const std::string& folderPath);
static std::unique_ptr<BeatMap> loadFromZip(const std::string& zipPath);
static std::shared_ptr<BeatMap> loadFromFolder(const std::string& folderPath);
static std::shared_ptr<BeatMap> loadFromZip(const std::string& zipPath);
};

View File

@ -20,5 +20,7 @@ namespace Beatsaber {
const std::uint8_t characteristicsNameSize = sizeof(characteristicsName)/sizeof(std::string);
BeatmapCharacteristic getByString(const std::string& str);
const std::string& toString(BeatmapCharacteristic c);
}
}

View File

@ -14,6 +14,8 @@ class BeatSet {
public:
virtual ~BeatSet() {}
virtual void printDebug() const = 0;
virtual BeatmapCharacteristic::BeatmapCharacteristic getCharacteristic() const = 0;
virtual std::shared_ptr<BeatMap> getBeatMap() const = 0;
};

View File

@ -17,5 +17,8 @@ namespace Beatsaber {
const std::uint8_t difficultyNameSize = sizeof(difficultyName)/sizeof(std::string);
Difficulty getByString(const std::string& str);
const std::string& toString(Difficulty d);
}
}

View File

@ -1,5 +1,6 @@
#include "beatlevelimpl.h"
#include <iostream>
#include <nlohmann/json.hpp>
#include "beatset.h"
@ -48,6 +49,14 @@ std::string BeatLevelImpl::getCustomData() const {
return "";
}
void BeatLevelImpl::printDebug() const {
std::cout <<
" Difficulty: " << Difficulty::toString(dif) << " (" << diffRank << ")"
<< "\n Filename: " << getFilename()
<< "\n njs: " << getNoteJumpSpeed() << " nso: " << getNoteStartOffset()
<< std::endl;
}
std::shared_ptr<BeatSet> BeatLevelImpl::getBeatSet() const {
return parent.lock();
}

View File

@ -16,7 +16,6 @@ bool BeatMapImpl::load() {
try {
info >> infobase;
//load the beatset
const json& beatsets = infobase["_difficultyBeatmapSets"];
if(beatsets.is_array()) {
@ -24,12 +23,14 @@ bool BeatMapImpl::load() {
//load all the beatsets
for(const json& jsonbeatset : beatsets) {
beatSets.push_back(std::make_shared<BeatSetImpl>(shared_from_this(), jsonbeatset));
beatSets.push_back(std::make_shared<BeatSetImpl>(weak_from_this(), jsonbeatset));
}
}
return true;
} catch(...) {} //catch any json errors
} catch(const nlohmann::detail::exception& e) { //catch any json errors
std::cout << "Could not Read BeatMap: " << e.what() << std::endl;
}
return false;
}
@ -132,30 +133,40 @@ std::shared_ptr<BeatSet> BeatMapImpl::getBeatSet(BeatmapCharacteristic::BeatmapC
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()
<< "\n Mapper: " << getMapperName()
<< "\n Version: " << getVersion()
<< "\n BPM: " << getBPM() << " offset: " << getTimeOffset()
<< "\n Schuffle " << getSchuffle() << " period: " << getSchufflePeriod()
<< "\n PreviewStart: " << getPreviewStart() << " duration: " << getPreviewDuration()
<< "\n SongFile: " << getSongFilename()
<< "\n ImageFile: " << getImageFilename()
<< "\n EnvName: " << getEnvName() << " 360Env: " << get360EnvName()
<< "\n customData: " << getCustomData()
<< "\n BeatSetCount: " << getBeatSetCount()
<< std::endl;
for(auto it : beatSets) {
it->printDebug();
}
}
std::unique_ptr<BeatMap> BeatMap::loadFromFolder(const std::string& folderPath) {
auto map = std::make_unique<BeatMapImpl>(folderPath, false);
std::shared_ptr<BeatMap> BeatMap::loadFromFolder(const std::string& folderPath) {
auto map = std::make_shared<BeatMapImpl>(folderPath, false);
if(!map->load()) return nullptr;
return map;
}
std::unique_ptr<BeatMap> BeatMap::loadFromZip(const std::string& zipPath) {
auto map = std::make_unique<BeatMapImpl>(zipPath, true);
std::shared_ptr<BeatMap> BeatMap::loadFromZip(const std::string& zipPath) {
#if BEATSABERZIPSUPPORT == 1
auto map = std::make_shared<BeatMapImpl>(zipPath, true);
if(!map->load()) return nullptr;
return map;
#else
// Zip not supported
std::cerr << "Zip not supported" << std::endl;
return nullptr;
#endif
}
}

View File

@ -1,14 +1,41 @@
#include "beatsetimpl.h"
#include <iostream> //debug print
#include <nlohmann/json.hpp>
#include "beatlevelimpl.h"
namespace Beatsaber {
BeatSetImpl::BeatSetImpl(std::weak_ptr<BeatMap> p, const json& j) : parent(p), characteristic(BeatmapCharacteristic::getByString(j["_beatmapCharacteristicName"])) {
BeatSetImpl::BeatSetImpl(std::weak_ptr<BeatMap> p, const json& j) : parent(p) {
try {
characteristic = BeatmapCharacteristic::getByString(j["_beatmapCharacteristicName"]);
//load level
const json& arr = j["_difficultyBeatmaps"];
if(arr.is_array()) {
level.reserve(arr.size());
std::cout << "Try to load: " << arr.size() << std::endl;
for(const json& beat : arr) {
level.push_back(std::make_shared<BeatLevelImpl>(weak_from_this(), beat));
}
}
} catch(std::exception& e) {
std::cout << "Could not read BeatSet: " << e.what() << std::endl;
characteristic = BeatmapCharacteristic::NONE;
}
}
BeatSetImpl::~BeatSetImpl() {}
void BeatSetImpl::printDebug() const {
std::cout << " Characteristic: " << BeatmapCharacteristic::toString(characteristic) << std::endl;
for(auto it : level) {
it->printDebug();
}
}
BeatmapCharacteristic::BeatmapCharacteristic BeatSetImpl::getCharacteristic() const {
return characteristic;
}

View File

@ -13,6 +13,12 @@ BeatmapCharacteristic getByString(const std::string& str) {
return BeatmapCharacteristic::NONE;
}
const std::string& toString(BeatmapCharacteristic c) {
uint8_t ic = (uint8_t) c;
if(ic >= characteristicsNameSize) return characteristicsName[0]; //none
return characteristicsName[ic];
}
}
namespace Difficulty {
@ -24,5 +30,12 @@ Difficulty getByString(const std::string& str) {
}
return Difficulty::NONE;
}
const std::string& toString(Difficulty d) {
uint8_t id = (uint8_t) d;
if(id >= difficultyNameSize) return difficultyName[0]; //none
return difficultyName[id];
}
}
}

34
src/filereader.cpp Normal file
View File

@ -0,0 +1,34 @@
#include "filereaderimpl.h"
#include <fstream>
namespace Beatsaber {
FolderReader::FolderReader(const std::string& path) : path(path) {
// make path end with /
if(path.rfind('/') != path.size()-1)
this->path += "/";
}
FolderReader::~FolderReader() {}
std::shared_ptr<std::istream> FolderReader::getFileStream(const std::string& filename) {
std::shared_ptr<std::istream> stream = std::make_shared<std::ifstream>(path + filename);
return stream;
}
#if BEATSABERZIPSUPPORT == 1
ZipReader::ZipReader(const std::string& path) : file(path) {}
ZipReader::~ZipReader() {
file.close();
}
std::shared_ptr<std::istream> ZipReader::getFileStream(const std::string& filename) {
return file.getInputStream(filename);
}
#endif
}

View File

@ -30,7 +30,7 @@ int main(int argc, char** argv) {
printf("\033[1;93m%d\033[0;1m/%d failed\n", failcount, testcount);
//simple read test
std::unique_ptr<Beatsaber::BeatMap> bmap = Beatsaber::BeatMap::loadFromFolder("/media/satassd/steam/steamapps/common/Beat Saber/Beat Saber_Data/CustomLevels/1dd (Portal - Still Alive (Uppermost Remix) - kryptikos)");
std::shared_ptr<Beatsaber::BeatMap> 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();