From c784e184af75ea1aba35191d320c71d6b8a63c8c Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Thu, 11 Apr 2024 00:09:48 +0700 Subject: [PATCH 01/83] refactor(rhythmengine): adjusted delay --- Engine/src/Game.cpp | 2 +- Engine/src/Texture/Texture2D.cpp | 102 ++++++++++++------------------- Game/src/Engine/RhythmEngine.cpp | 4 +- 3 files changed, 43 insertions(+), 65 deletions(-) diff --git a/Engine/src/Game.cpp b/Engine/src/Game.cpp index cad829e1..eff016fe 100644 --- a/Engine/src/Game.cpp +++ b/Engine/src/Game.cpp @@ -372,7 +372,7 @@ void Game::Stop() m_running = false; { - std::lock_guard lock(m_mutex); // TODO: Fix game does not properly exit while crash (if not just revert back to SDL_Delay Sleep) + std::lock_guard lock(m_mutex); m_notify = true; } m_conditionVariable.notify_one(); diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index ab682e18..211fad61 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -35,36 +35,28 @@ Texture2D::Texture2D() Size = UDim2::fromScale(1, 1); } -Texture2D::Texture2D(std::string fileName) : Texture2D() + +Texture2D::Texture2D(std::string fileName) : Texture2D() { - if (!std::filesystem::exists(fileName)) { - fileName = std::filesystem::current_path().string() + fileName; + std::filesystem::path filePath(fileName); + if (!std::filesystem::exists(filePath)) { + throw std::runtime_error(filePath.string() + " not found!"); } - if (!std::filesystem::exists(fileName)) { - throw std::runtime_error(fileName + " not found!"); + std::ifstream file(filePath, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + throw std::runtime_error(filePath.string() + " cannot be opened!"); } - std::fstream fs(fileName, std::ios::binary | std::ios::in); - if (!fs.is_open()) { - throw std::runtime_error(fileName + " cannot opened!"); - } + std::streamsize size = file.tellg(); + file.seekg(0, std::ios::beg); - fs.seekg(0, std::ios::end); - size_t size = fs.tellg(); - fs.seekg(0, std::ios::beg); - - uint8_t *buffer = new uint8_t[size]; - fs.read((char *)buffer, size); - fs.close(); - - Rotation = 0; - Transparency = 0.0f; - m_actualSize = { 0, 0, 0, 0 }; - m_bDisposeTexture = true; - TintColor = { 1.0f, 1.0f, 1.0f }; + std::vector buffer(size); + if (!file.read(reinterpret_cast(buffer.data()), size)) { + throw std::runtime_error("Failed to read file: " + filePath.string()); + } - LoadImageResources(buffer, size); + LoadImageResources(buffer.data(), buffer.size()); } Texture2D::Texture2D(std::filesystem::path path) : Texture2D() @@ -131,21 +123,17 @@ Texture2D::Texture2D(Texture2D_Vulkan *texture) : Texture2D() m_ready = true; } -Texture2D::~Texture2D() +Texture2D::~Texture2D() { if (m_bDisposeTexture) { if (Renderer::GetInstance()->IsVulkan() && m_vk_tex) { - auto vk_tex = m_vk_tex; - - vkTexture::ReleaseTexture(vk_tex); - + vkTexture::ReleaseTexture(m_vk_tex); m_vk_tex = nullptr; } else { if (m_sdl_tex) { SDL_DestroyTexture(m_sdl_tex); m_sdl_tex = nullptr; } - if (m_sdl_surface) { SDL_FreeSurface(m_sdl_surface); m_sdl_surface = nullptr; @@ -415,44 +403,34 @@ Texture2D *Texture2D::FromPNG(std::string fileName) return nullptr; } -void Texture2D::LoadImageResources(uint8_t *buffer, size_t size) +void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) { - if (Renderer::GetInstance()->IsVulkan()) { - auto tex_data = vkTexture::TexLoadImage(buffer, size); - - m_actualSize = { 0, 0, tex_data->Width, tex_data->Height }; - m_vk_tex = tex_data; - - m_bDisposeTexture = true; - m_ready = true; - } else { - SDL_RWops *rw = SDL_RWFromMem(buffer, (int)size); - - // check if buffer magic is BMP - if (buffer[0] == 0x42 && buffer[1] == 0x4D) { - m_sdl_surface = SDL_LoadBMP_RW(rw, 1); + try { + if (Renderer::GetInstance()->IsVulkan()) { + auto tex_data = vkTexture::TexLoadImage(buffer, size); + m_actualSize = { 0, 0, tex_data->Width, tex_data->Height }; + m_vk_tex = tex_data; + m_bDisposeTexture = true; + m_ready = true; } else { - m_sdl_surface = IMG_Load_RW(rw, 1); - } + SDL_RWops* rw = SDL_RWFromMem(buffer, static_cast(size)); + m_sdl_surface = (buffer[0] == 0x42 && buffer[1] == 0x4D) ? + SDL_LoadBMP_RW(rw, 1) : IMG_Load_RW(rw, 1); - if (!m_sdl_surface) { - throw SDLException(); - } - - m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), m_sdl_surface); - if (!m_sdl_tex) { - throw SDLException(); - } - - // sdl get texture resolution - int w, h; - SDL_QueryTexture(m_sdl_tex, nullptr, nullptr, &w, &h); + if (!m_sdl_surface) throw SDLException(); - m_bDisposeTexture = true; - m_actualSize = { 0, 0, w, h }; + m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), m_sdl_surface); + if (!m_sdl_tex) throw SDLException(); - m_ready = true; + int w, h; + SDL_QueryTexture(m_sdl_tex, nullptr, nullptr, &w, &h); + m_bDisposeTexture = true; + m_actualSize = { 0, 0, w, h }; + m_ready = true; + } + } catch (...) { + delete[] buffer; + throw; } - delete[] buffer; } diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 3c8351dd..878e7da7 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -318,7 +318,7 @@ void RhythmEngine::SetKeys(Keys *keys) bool RhythmEngine::Start() { // no, use update event instead - m_currentAudioPosition -= 3000; + m_currentAudioPosition -= 5000; m_state = GameState::Playing; //m_startClock = std::chrono::system_clock::now(); return true; @@ -579,7 +579,7 @@ double RhythmEngine::GetGameFrame() const int RhythmEngine::GetPlayTime() const { - return static_cast(m_PlayTime - 3); + return static_cast(m_PlayTime - 5); } int RhythmEngine::GetNoteImageIndex() From 10bd83d7cb52278131cdaeab9644c406f67e0142 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Fri, 12 Apr 2024 18:33:12 +0700 Subject: [PATCH 02/83] refactor some codes --- Engine/include/Texture/Sprite2D.h | 13 +++++++------ Engine/include/Texture/Texture2D.h | 2 +- Engine/src/Texture/Sprite2D.cpp | 26 +++++++++++++------------- Engine/src/Texture/Texture2D.cpp | 18 +++++++++--------- Game/src/Engine/DrawableNote.cpp | 2 +- Game/src/Engine/FrameTimer.cpp | 12 ++++++------ Game/src/Engine/FrameTimer.hpp | 2 +- Game/src/Engine/Note.cpp | 3 +-- 8 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Engine/include/Texture/Sprite2D.h b/Engine/include/Texture/Sprite2D.h index 479f2435..2c3ae760 100644 --- a/Engine/include/Texture/Sprite2D.h +++ b/Engine/include/Texture/Sprite2D.h @@ -18,10 +18,10 @@ class Sprite2D public: Sprite2D() = default; - Sprite2D(std::vector textures, float delay = 1.0f); - Sprite2D(std::vector textures, float delay = 1.0f); - Sprite2D(std::vector textures, float delay = 1.0f); - Sprite2D(std::vector textures, float delay = 1.0f); + Sprite2D(std::vector textures, double delay = 1.0); + Sprite2D(std::vector textures, double delay = 1.0); + Sprite2D(std::vector textures, double delay = 1.0); + Sprite2D(std::vector textures, double delay = 1.0); ~Sprite2D(); @@ -37,11 +37,12 @@ class Sprite2D void DrawOnce(double delta, bool manual = false); Texture2D *GetTexture(); - void SetFPS(float fps); + void SetFPS(double fps); void Reset(); -private: double m_spritespeed = 1.0; + +private: float m_currentTime = 0; int m_currentIndex = 0; diff --git a/Engine/include/Texture/Texture2D.h b/Engine/include/Texture/Texture2D.h index 8596abd0..7fd24b05 100644 --- a/Engine/include/Texture/Texture2D.h +++ b/Engine/include/Texture/Texture2D.h @@ -51,7 +51,7 @@ class Texture2D Rect GetOriginalRECT(); void SetOriginalRECT(Rect size); - static Texture2D *FromTexture2D(Texture2D *tex); + // static Texture2D *FromTexture2D(Texture2D *tex); static Texture2D *FromBMP(uint8_t *fileData, size_t size); static Texture2D *FromBMP(std::string fileName); diff --git a/Engine/src/Texture/Sprite2D.cpp b/Engine/src/Texture/Sprite2D.cpp index c18e661e..e9d29c33 100644 --- a/Engine/src/Texture/Sprite2D.cpp +++ b/Engine/src/Texture/Sprite2D.cpp @@ -2,11 +2,11 @@ #include "Rendering/Window.h" #include "Texture/Texture2D.h" -Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::Sprite2D() +Sprite2D::Sprite2D(std::vector textures, double delay) : Sprite2D::Sprite2D() { m_textures = textures; m_spritespeed = delay; - m_currentTime = 0.0f; + m_currentTime = 0.0; m_currentIndex = 0; Size = UDim2::fromScale(1, 1); @@ -14,7 +14,7 @@ Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::S AnchorPoint = { 0, 0 }; } -Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::Sprite2D() +Sprite2D::Sprite2D(std::vector textures, double delay) : Sprite2D::Sprite2D() { m_spritespeed = delay; Size = UDim2::fromScale(1, 1); @@ -26,7 +26,7 @@ Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::S } } -Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::Sprite2D() +Sprite2D::Sprite2D(std::vector textures, double delay) : Sprite2D::Sprite2D() { m_spritespeed = delay; Size = UDim2::fromScale(1, 1); @@ -40,7 +40,7 @@ Sprite2D::Sprite2D(std::vector textures, float delay) : S } } -Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::Sprite2D() +Sprite2D::Sprite2D(std::vector textures, double delay) : Sprite2D::Sprite2D() { m_spritespeed = delay; Size = UDim2::fromScale(1, 1); @@ -84,10 +84,10 @@ void Sprite2D::Draw(double delta, Rect *rect, bool manual) // Original code, pla tex->AnchorPoint = AnchorPoint; tex->Draw(rect, manual ? false : true); - if (m_spritespeed > 0.0f) { + if (m_spritespeed > 0.0) { m_currentTime += static_cast(delta); if (m_currentTime >= m_spritespeed) { - m_currentTime = 0.0f; + m_currentTime = 0.0; m_currentIndex = (m_currentIndex + 1) % m_textures.size(); } } @@ -116,10 +116,10 @@ void Sprite2D::DrawOnce(double delta, bool manual) { // Play whole image sprite tex->AnchorPoint = AnchorPoint; tex->Draw(); - if (m_spritespeed > 0.0f) { + if (m_spritespeed > 0.0) { m_currentTime += static_cast(delta); if (m_currentTime >= m_spritespeed) { - m_currentTime = 0.0f; + m_currentTime = 0.0; m_currentIndex++; if (m_currentIndex == m_textures.size() && m_drawOnce) { @@ -152,10 +152,10 @@ void Sprite2D::DrawStop(double delta, bool manual) { // Play image sprite once a tex->AnchorPoint = AnchorPoint; tex->Draw(); - if (m_spritespeed > 0.0f) { + if (m_spritespeed > 0.0) { m_currentTime += static_cast(delta); if (m_currentTime >= m_spritespeed) { - m_currentTime = 0.0f; + m_currentTime = 0.0; m_currentIndex++; if (m_currentIndex == m_textures.size() && m_drawOnce) { @@ -169,7 +169,7 @@ void Sprite2D::DrawStop(double delta, bool manual) { // Play image sprite once a void Sprite2D::Reset() { m_currentIndex = 0; - m_currentTime = 0.0f; + m_currentTime = 0.0; } Texture2D *Sprite2D::GetTexture() @@ -182,7 +182,7 @@ Texture2D *Sprite2D::GetTexture() return tex; } -void Sprite2D::SetFPS(float fps) +void Sprite2D::SetFPS(double fps) { m_spritespeed = 1.0f / fps; } \ No newline at end of file diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 211fad61..27749418 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -363,15 +363,15 @@ void Texture2D::SetOriginalRECT(Rect size) m_actualSize = size; } -Texture2D *Texture2D::FromTexture2D(Texture2D *tex) -{ - auto copy = new Texture2D(tex->m_sdl_tex); - copy->m_actualSize = tex->m_actualSize; - copy->Position = tex->Position; - copy->Size = tex->Size; - - return copy; -} +//Texture2D *Texture2D::FromTexture2D(Texture2D *tex) +//{ +// auto copy = new Texture2D(tex->m_sdl_tex); +// copy->m_actualSize = tex->m_actualSize; +// copy->Position = tex->Position; +// copy->Size = tex->Size; +// +// return copy; +//} Texture2D *Texture2D::FromBMP(uint8_t *fileData, size_t size) { diff --git a/Game/src/Engine/DrawableNote.cpp b/Game/src/Engine/DrawableNote.cpp index db4f9b1e..b1ca5554 100644 --- a/Game/src/Engine/DrawableNote.cpp +++ b/Game/src/Engine/DrawableNote.cpp @@ -22,5 +22,5 @@ DrawableNote::DrawableNote(NoteImage* frame) : FrameTimer::FrameTimer() AnchorPoint = { 0.0, 1.0 }; - SetFPS(0); // slighly fix stupid glitch + SetFPS(60.0); // slighly fix stupid glitch } diff --git a/Game/src/Engine/FrameTimer.cpp b/Game/src/Engine/FrameTimer.cpp index f015773e..1f5e7d24 100644 --- a/Game/src/Engine/FrameTimer.cpp +++ b/Game/src/Engine/FrameTimer.cpp @@ -6,7 +6,7 @@ FrameTimer::FrameTimer() { Repeat = false; m_currentFrame = 0; - m_frameTime = 1.0f / 60.0f; + m_frameTime = 1.0 / 60.0; m_currentTime = 0; AlphaBlend = false; Size = UDim2::fromScale(1, 1); @@ -72,9 +72,9 @@ void FrameTimer::Draw(double delta, Rect *clip) m_currentFrame++; } - if (Repeat && m_currentFrame >= m_frames.size()) { - m_currentFrame = 0; - } + if (Repeat && m_currentFrame >= m_frames.size()) { + m_currentFrame = 0; + } if (m_currentFrame < m_frames.size()) { CalculateSize(); @@ -91,9 +91,9 @@ void FrameTimer::Draw(double delta, Rect *clip) } } -void FrameTimer::SetFPS(float fps) +void FrameTimer::SetFPS(double fps) { - m_frameTime = 1.0f / fps; + m_frameTime = 1.0 / fps; } void FrameTimer::ResetIndex() diff --git a/Game/src/Engine/FrameTimer.hpp b/Game/src/Engine/FrameTimer.hpp index b0d5efab..cd6b4f61 100644 --- a/Game/src/Engine/FrameTimer.hpp +++ b/Game/src/Engine/FrameTimer.hpp @@ -36,7 +36,7 @@ class FrameTimer void Draw(double delta); void Draw(double delta, Rect *clip); - void SetFPS(float fps); + void SetFPS(double fps); void ResetIndex(); void LastIndex(); void SetIndexAt(int idx); diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 7c92c744..ad900947 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -206,8 +206,7 @@ void Note::Update(double delta) } } } - bool pressed = IsPassed(); - if (pressed) { + if (IsPassed()) { m_state = NoteState::DO_REMOVE; } } From 97a87a637a583de14ef923e64c9ad8c242fcfc4d Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Wed, 10 Apr 2024 12:32:15 +0700 Subject: [PATCH 03/83] Rebase --- Engine/src/Rendering/Renderer.cpp | 4 +- .../src/Rendering/Vulkan/Texture2DVulkan.cpp | 38 +-- Engine/src/Scenes/SceneManager.cpp | 27 +- Engine/src/Texture/Color3.cpp | 96 +++---- Engine/src/Texture/Texture2D.cpp | 48 ++-- Engine/src/Threading/GameThread.cpp | 1 + Game/src/Data/Chart.cpp | 170 ++++++++---- Game/src/Data/Chart.hpp | 3 + Game/src/Data/OJM.cpp | 2 +- Game/src/Engine/Autoplay.cpp | 77 ++---- Game/src/Engine/BGMPreview.cpp | 6 +- Game/src/Engine/DrawableNote.cpp | 18 +- Game/src/Engine/FrameTimer.cpp | 10 +- Game/src/Engine/FrameTimer.hpp | 3 +- Game/src/Engine/GameTrack.cpp | 2 +- Game/src/Engine/Note.cpp | 12 +- Game/src/Engine/NoteImageCacheManager.cpp | 197 ++++++-------- Game/src/Engine/NoteImageCacheManager.hpp | 27 +- Game/src/Engine/RhythmEngine.cpp | 52 ++-- Game/src/Engine/RhythmEngine.hpp | 6 +- Game/src/Engine/ScoreManager.cpp | 27 +- Game/src/Engine/Timing/TimingBase.cpp | 19 +- Game/src/EnvironmentSetup.cpp | 50 ++-- Game/src/MyGame.cpp | 2 +- Game/src/Scenes/GameplayScene.cpp | 118 +++++--- Game/src/Scenes/GameplayScene.h | 3 + Game/src/Scenes/LoadingScene.cpp | 42 ++- Game/src/Scenes/LoadingScene.h | 2 +- Game/src/Scenes/MainMenu.cpp | 253 +++++++++--------- Game/src/Scenes/Overlays/Settings.cpp | 2 +- Game/src/Scenes/ResultScene.cpp | 42 ++- Game/src/Scenes/SongSelectScene.cpp | 76 ++++-- Game/src/Scenes/SongSelectScene.h | 3 +- Game/src/Version.h | 4 +- GameResources | 1 - 35 files changed, 798 insertions(+), 645 deletions(-) delete mode 160000 GameResources diff --git a/Engine/src/Rendering/Renderer.cpp b/Engine/src/Rendering/Renderer.cpp index 294d2065..13c56937 100644 --- a/Engine/src/Rendering/Renderer.cpp +++ b/Engine/src/Rendering/Renderer.cpp @@ -96,10 +96,10 @@ bool Renderer::Create(RendererMode mode, GameWindow *window, bool failed) } SDL_SetHint(SDL_HINT_RENDER_DRIVER, rendererName.c_str()); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); // STOP CHANGING THIS, LEAVE IT "as is" + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "Linear"); } - m_renderer = SDL_CreateRenderer(window->GetWindow(), -1, SDL_RENDERER_ACCELERATED); + m_renderer = SDL_CreateRenderer(window->GetWindow(), -1, SDL_RENDERER_ACCELERATED /*| SDL_RENDERER_PRESENTVSYNC*/); if (!m_renderer) { throw SDLException(); } diff --git a/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp b/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp index 3ff2d798..85fb06d7 100644 --- a/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp +++ b/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp @@ -17,7 +17,7 @@ static int m_textureCount static std::mutex m_textureMutex; static std::unique_ptr m_dummyTexture; -Texture2D_Vulkan *CreateTexture() +Texture2D_Vulkan* CreateTexture() { // find the empty slot for (int i = 0; i < m_textureCount; i++) { @@ -53,7 +53,7 @@ uint32_t vkTexture::FindMemoryType(uint32_t type_filter, uint32_t properties) return findMemoryType(VulkanEngine::GetInstance()->_chosenGPU, type_filter, properties); } -Texture2D_Vulkan *vkTexture::TexLoadImage(std::filesystem::path imagePath) +Texture2D_Vulkan* vkTexture::TexLoadImage(std::filesystem::path imagePath) { std::fstream fs(imagePath, std::ios::binary | std::ios::in); if (!fs.is_open()) { @@ -135,8 +135,8 @@ void InternalLoad( { VkSamplerCreateInfo samplerInfo = {}; samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerInfo.magFilter = VK_FILTER_NEAREST; - samplerInfo.minFilter = VK_FILTER_NEAREST; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; @@ -184,7 +184,7 @@ void InternalLoad( } { - void *map = NULL; + void* map = NULL; err = vkMapMemory(vulkan_driver->_device, tex_data->UploadBufferMemory, 0, image_size, 0, &map); if (err != VK_SUCCESS) { throw std::runtime_error("Vulkan: Failed to create mapped image memory"); @@ -240,17 +240,17 @@ void InternalLoad( use_barrier[0].subresourceRange.levelCount = 1; use_barrier[0].subresourceRange.layerCount = 1; vkCmdPipelineBarrier(cmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, use_barrier); - }); + }); } -Texture2D_Vulkan *vkTexture::TexLoadImage(void *buffer, size_t size) +Texture2D_Vulkan* vkTexture::TexLoadImage(void* buffer, size_t size) { auto vulkan_driver = VulkanEngine::GetInstance(); auto tex_data = CreateTexture(); tex_data->Channels = 4; - unsigned char *image_data = stbi_load_from_memory( - (uint8_t *)buffer, + unsigned char* image_data = stbi_load_from_memory( + (uint8_t*)buffer, (int)size, &tex_data->Width, &tex_data->Height, @@ -265,7 +265,7 @@ Texture2D_Vulkan *vkTexture::TexLoadImage(void *buffer, size_t size) return tex_data; } -Texture2D_Vulkan *vkTexture::GetDummyImage() +Texture2D_Vulkan* vkTexture::GetDummyImage() { if (m_dummyTexture) { return m_dummyTexture.get(); @@ -278,8 +278,8 @@ Texture2D_Vulkan *vkTexture::GetDummyImage() // Generate file 1 Pixel Bitmap Image, with header std::vector buffer = ImageGenerator::GenerateImage(40, 40, { 255, 255, 255, 255 }); - unsigned char *image_data = stbi_load_from_memory( - (uint8_t *)buffer.data(), + unsigned char* image_data = stbi_load_from_memory( + (uint8_t*)buffer.data(), (int)buffer.size(), &m_dummyTexture->Width, &m_dummyTexture->Height, @@ -297,18 +297,18 @@ Texture2D_Vulkan *vkTexture::GetDummyImage() return m_dummyTexture.get(); } -VkDescriptorSet vkTexture::GetVkDescriptorSet(Texture2D_Vulkan *handle) +VkDescriptorSet vkTexture::GetVkDescriptorSet(Texture2D_Vulkan* handle) { return handle->DS; } -void vkTexture::QueryTexture(Texture2D_Vulkan *handle, int &outWidth, int &outHeight) +void vkTexture::QueryTexture(Texture2D_Vulkan* handle, int& outWidth, int& outHeight) { outWidth = handle->Width; outHeight = handle->Height; } -void vkTexture::ReleaseTexture(Texture2D_Vulkan *tex_data) +void vkTexture::ReleaseTexture(Texture2D_Vulkan* tex_data) { if (tex_data == nullptr) { return; @@ -326,14 +326,14 @@ void vkTexture::ReleaseTexture(Texture2D_Vulkan *tex_data) ImGui_ImplVulkan_RemoveTexture(tex_data->DS); - auto it = std::find_if(m_textures.begin(), m_textures.end(), [&](auto &pair) { + auto it = std::find_if(m_textures.begin(), m_textures.end(), [&](auto& pair) { return pair.second != nullptr && pair.second->Id == tex_data->Id; - }); + }); if (it != m_textures.end()) { it->second.reset(); } - }); + }); } // This must be called from VulkanEngine! @@ -344,7 +344,7 @@ void vkTexture::Cleanup() std::cout << "[Info] Cleaning up Vulkan textures: " << m_textures.size() << std::endl; - for (auto &[id, tex_data] : m_textures) { + for (auto& [id, tex_data] : m_textures) { if (tex_data == nullptr) { continue; } diff --git a/Engine/src/Scenes/SceneManager.cpp b/Engine/src/Scenes/SceneManager.cpp index 2443a80d..c0121a8b 100644 --- a/Engine/src/Scenes/SceneManager.cpp +++ b/Engine/src/Scenes/SceneManager.cpp @@ -113,9 +113,10 @@ void SceneManager::Render(double delta) { if (m_currentScene) m_currentScene->Render(delta); + if (m_currentOverlay && !MsgBox::Any()) { ImguiUtil::NewFrame(); - auto &io = ImGui::GetIO(); + auto& io = ImGui::GetIO(); ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(m_currentOverlay->GetSize(), ImGuiCond_Always); @@ -332,7 +333,7 @@ void SceneManager::DisplayFade(int transparency, std::function callback) } callback(); - }).detach(); + }).detach(); } void SceneManager::ExecuteAfter(int ms_time, std::function callback) @@ -357,17 +358,19 @@ void SceneManager::GameExecuteAfter(ExecuteThread thread, int ms_time, std::func game->GetMainThread()->QueueAction(callback); } else { switch (thread) { - case ExecuteThread::UPDATE: - { - game->GetRenderThread()->QueueAction(callback); - break; - } + case ExecuteThread::UPDATE: + { + game->GetRenderThread()->QueueAction(callback); + game->GetMainThread()->QueueAction(callback); // w + break; + } - case ExecuteThread::WINDOW: - { - game->GetMainThread()->QueueAction(callback); - break; - } + case ExecuteThread::WINDOW: + { + game->GetRenderThread()->QueueAction(callback); // w + game->GetMainThread()->QueueAction(callback); + break; + } } } } diff --git a/Engine/src/Texture/Color3.cpp b/Engine/src/Texture/Color3.cpp index 02c2917b..92307587 100644 --- a/Engine/src/Texture/Color3.cpp +++ b/Engine/src/Texture/Color3.cpp @@ -1,6 +1,8 @@ #include "Texture/Color3.h" #include #include +#include +#include template T clamp(T value, T min, T max) @@ -8,10 +10,6 @@ T clamp(T value, T min, T max) return std::min(std::max(value, min), max); } -#if defined(__GNUC__) || defined(__GNUG__) -#include -#endif - Color3::Color3(float r, float g, float b) { R = clamp(r, 0.0f, 1.0f); @@ -24,48 +22,50 @@ Color3 Color3::FromRGB(float r, float g, float b) return { r / 255.0f, g / 255.0f, b / 255.0f }; } -Color3 Color3::FromHSV(int hue, int saturnation, int value) +Color3 Color3::FromHSV(int hue, int saturation, int value) { - float R, G, B; + float h = static_cast(hue % 360); + float s = clamp(static_cast(saturation), 0.0f, 100.0f) / 100.0f; + float v = clamp(static_cast(value), 0.0f, 100.0f) / 100.0f; - float h = hue / 60.0f; - float s = saturnation / 100.0f; - float v = value / 100.0f; float c = v * s; - float x = c * (1.0f - std::abs(fmod(h, 2.0f) - 1.0f)); + float x = c * (1.0f - std::abs(std::fmod(h / 60.0f, 2.0f) - 1.0f)); float m = v - c; - if (h >= 0 && h < 1) { - R = c; - G = x; - B = 0; - } else if (h >= 1 && h < 2) { - R = x; - G = c; - B = 0; - } else if (h >= 2 && h < 3) { - R = 0; - G = c; - B = x; - } else if (h >= 3 && h < 4) { - R = 0; - G = x; - B = c; - } else if (h >= 4 && h < 5) { - R = x; - G = 0; - B = c; - } else if (h >= 5 && h < 6) { - R = c; - G = 0; - B = x; - } else { - R = 0; - G = 0; - B = 0; + float r, g, b; + + if (0 <= h && h < 60) { + r = c; + g = x; + b = 0; + } + else if (60 <= h && h < 120) { + r = x; + g = c; + b = 0; + } + else if (120 <= h && h < 180) { + r = 0; + g = c; + b = x; + } + else if (180 <= h && h < 240) { + r = 0; + g = x; + b = c; + } + else if (240 <= h && h < 300) { + r = x; + g = 0; + b = c; + } + else { + r = c; + g = 0; + b = x; } - return { R, G, B }; + return { r + m, g + m, b + m }; } Color3 Color3::FromHex(std::string hexValue) @@ -82,7 +82,7 @@ Color3 Color3::FromHex(std::string hexValue) return { 0, 0, 0 }; } - int r = std::stoi(hexValue.substr(0, 2), nullptr, 16); + int r = std::stoi(hexValue.substr(0, 2), nullptr, 16); int g = std::stoi(hexValue.substr(2, 2), nullptr, 16); int b = std::stoi(hexValue.substr(4, 2), nullptr, 16); @@ -111,27 +111,31 @@ std::string Color3::ToHex() } // operator -Color3 Color3::operator+(Color3 const &color) +Color3 Color3::operator+(Color3 const& color) { return { this->R + color.R, this->G + color.G, this->B + color.B }; } -Color3 Color3::operator-(Color3 const &color) +Color3 Color3::operator-(Color3 const& color) { return { this->R - color.R, this->G - color.G, this->B - color.B }; } -Color3 Color3::operator*(Color3 const &color) +Color3 Color3::operator*(Color3 const& color) { return { this->R * color.R, this->G * color.G, this->B * color.B }; } -Color3 Color3::operator/(Color3 const &color) +Color3 Color3::operator/(Color3 const& color) { + // Handle division by zero + if (color.R == 0 || color.G == 0 || color.B == 0) { + return { 0, 0, 0 }; + } return { this->R / color.R, this->G / color.G, this->B / color.B }; } -Color3 Color3::operator*(float const &value) +Color3 Color3::operator*(float const& value) { return { this->R * value, this->G * value, this->B * value }; -} \ No newline at end of file +} diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 6de909ac..ab682e18 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -233,30 +233,30 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) for (int i = 0; i < 6; i++) { ImDrawVert &vertex = vertexData[i]; switch (i) { - case 0: - vertex.pos = ImVec2(x1, y1); - vertex.uv = uv1; - break; - case 1: - vertex.pos = ImVec2(x2, y1); - vertex.uv = uv2; - break; - case 2: - vertex.pos = ImVec2(x2, y2); - vertex.uv = uv3; - break; - case 3: - vertex.pos = ImVec2(x1, y1); - vertex.uv = uv1; - break; - case 4: - vertex.pos = ImVec2(x2, y2); - vertex.uv = uv3; - break; - case 5: - vertex.pos = ImVec2(x1, y2); - vertex.uv = uv4; - break; + case 0: + vertex.pos = ImVec2(x1, y1); + vertex.uv = uv1; + break; + case 1: + vertex.pos = ImVec2(x2, y1); + vertex.uv = uv2; + break; + case 2: + vertex.pos = ImVec2(x2, y2); + vertex.uv = uv3; + break; + case 3: + vertex.pos = ImVec2(x1, y1); + vertex.uv = uv1; + break; + case 4: + vertex.pos = ImVec2(x2, y2); + vertex.uv = uv3; + break; + case 5: + vertex.pos = ImVec2(x1, y2); + vertex.uv = uv4; + break; } vertex.col = color; } diff --git a/Engine/src/Threading/GameThread.cpp b/Engine/src/Threading/GameThread.cpp index 522abb31..f3f04fd9 100644 --- a/Engine/src/Threading/GameThread.cpp +++ b/Engine/src/Threading/GameThread.cpp @@ -88,3 +88,4 @@ void GameThread::Stop() } } } + diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index 41c8c522..b7c24283 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -7,6 +7,7 @@ #include #include #include +#include float float_floor(float value) { @@ -86,7 +87,12 @@ Chart::Chart(Osu::Beatmap &beatmap) { AutoSample sample = {}; - sample.StartTime = beatmap.AudioLeadIn; + if (beatmap.AudioLeadIn = 0) { + sample.StartTime = beatmap.AudioLeadIn - 1; // Handle if offset 0 that causing audio delay + } + else { + sample.StartTime = beatmap.AudioLeadIn; + } sample.Index = beatmap.GetCustomSampleIndex(beatmap.AudioFilename); sample.Volume = 1; sample.Pan = 0; @@ -166,22 +172,9 @@ Chart::Chart(Osu::Beatmap &beatmap) } } - m_bpms[0].Beat = 0; - for (int i = 1; i < m_bpms.size(); i++) { - m_bpms[i].Beat = m_bpms[i - 1].CalculateBeat(m_bpms[i].StartTime); - } + CalculateBeat(); - std::sort(m_autoSamples.begin(), m_autoSamples.end(), [](const AutoSample &a, const AutoSample &b) { - return a.StartTime < b.StartTime; - }); - - std::sort(m_bpms.begin(), m_bpms.end(), [](const TimingInfo &a, const TimingInfo &b) { - return a.StartTime < b.StartTime; - }); - - std::sort(m_svs.begin(), m_svs.end(), [](const TimingInfo &a, const TimingInfo &b) { - return a.StartTime < b.StartTime; - }); + SortTimings(); NormalizeTimings(); ComputeHash(); @@ -288,22 +281,9 @@ Chart::Chart(BMS::BMSFile &file) m_bpms.push_back(info); } - m_bpms[0].Beat = 0; - for (int i = 1; i < m_bpms.size(); i++) { - m_bpms[i].Beat = m_bpms[i - 1].CalculateBeat(m_bpms[i].StartTime); - } - - std::sort(m_autoSamples.begin(), m_autoSamples.end(), [](const AutoSample &a, const AutoSample &b) { - return a.StartTime < b.StartTime; - }); - - std::sort(m_bpms.begin(), m_bpms.end(), [](const TimingInfo &a, const TimingInfo &b) { - return a.StartTime < b.StartTime; - }); + CalculateBeat(); - std::sort(m_svs.begin(), m_svs.end(), [](const TimingInfo &a, const TimingInfo &b) { - return a.StartTime < b.StartTime; - }); + SortTimings(); PredefinedAudioLength = file.AudioLength; NormalizeTimings(); @@ -368,10 +348,7 @@ Chart::Chart(O2::OJN &file, int diffIndex) m_bpms.push_back(info); } - m_bpms[0].Beat = 0; - for (int i = 1; i < m_bpms.size(); i++) { - m_bpms[i].Beat = m_bpms[i - 1].CalculateBeat(m_bpms[i].StartTime); - } + CalculateBeat(); for (auto &autoSample : diff.AutoSamples) { AutoSample sm = {}; @@ -392,17 +369,7 @@ Chart::Chart(O2::OJN &file, int diffIndex) m_samples.push_back(sm); } - std::sort(m_autoSamples.begin(), m_autoSamples.end(), [](const AutoSample &a, const AutoSample &b) { - return a.StartTime < b.StartTime; - }); - - std::sort(m_bpms.begin(), m_bpms.end(), [](const TimingInfo &a, const TimingInfo &b) { - return a.StartTime < b.StartTime; - }); - - std::sort(m_svs.begin(), m_svs.end(), [](const TimingInfo &a, const TimingInfo &b) { - return a.StartTime < b.StartTime; - }); + SortTimings(); PredefinedAudioLength = diff.AudioLength; NormalizeTimings(); @@ -410,6 +377,31 @@ Chart::Chart(O2::OJN &file, int diffIndex) ComputeHash(); } + + +void Chart::CalculateBeat() +{ + m_bpms[0].Beat = 0; + for (size_t i = 1; i < m_bpms.size(); i++) { + m_bpms[i].Beat = m_bpms[i - 1].CalculateBeat(m_bpms[i].StartTime); + } +} + +void Chart::SortTimings() +{ + std::sort(m_autoSamples.begin(), m_autoSamples.end(), [](const AutoSample& a, const AutoSample& b) { + return a.StartTime < b.StartTime; + }); + + std::sort(m_bpms.begin(), m_bpms.end(), [](const TimingInfo& a, const TimingInfo& b) { + return a.StartTime < b.StartTime; + }); + + std::sort(m_svs.begin(), m_svs.end(), [](const TimingInfo& a, const TimingInfo& b) { + return a.StartTime < b.StartTime; + }); +} + Chart::~Chart() { } @@ -444,7 +436,7 @@ void Chart::ApplyMod(Mod mod, void *data) case Mod::RANDOM: { std::vector lanes(m_keyCount); - for (int i = 0; i < 7; i++) { + for (int i = 0; i < m_keyCount; i++) { lanes[i] = i; } @@ -453,9 +445,91 @@ void Chart::ApplyMod(Mod mod, void *data) std::shuffle(std::begin(lanes), std::end(lanes), rng); - for (auto ¬e : m_notes) { + for (auto& note : m_notes) { note.LaneIndex = lanes[note.LaneIndex]; } + + /*std::stringstream pattern; + for (int lane : lanes) { + pattern << lane; + } + + Logs::Puts("[Chart] Set lane pattern to: %s", pattern.str().c_str());*/ + + break; + } + + case Mod::PANIC: + { + std::vector lanes(m_keyCount); + for (int i = 0; i < m_keyCount; i++) { + lanes[i] = i; + } + + auto rng = std::default_random_engine{}; + rng.seed((uint32_t)time(NULL)); + + std::unordered_map> measureLane; + + // Keep track of BPM changes + std::unordered_map measureBPM; + for (const auto& bpm : m_bpms) { + int measure = static_cast(bpm.StartTime / bpm.TimeSignature); + measureBPM[measure] = bpm.Value; + } + + for (auto& note : m_notes) { + int measure = -1; + for (size_t i = 0; i < m_bpms.size(); i++) { + if (m_bpms[i].StartTime > note.StartTime) { + measure = static_cast(m_bpms[i - 1].CalculateBeat(note.StartTime) / m_bpms[i - 1].TimeSignature); + break; + } + } + + if (measure == -1) { + measure = static_cast(m_bpms.back().CalculateBeat(note.StartTime) / m_bpms.back().TimeSignature); + } + + for (int i = measure; i > 0; i--) { + if (measureBPM.find(i) == measureBPM.end()) { + measureBPM[i] = measureBPM[i - 1]; + } + } + + if (measureLane.find(measure) == measureLane.end()) { + std::shuffle(std::begin(lanes), std::end(lanes), rng); + measureLane[measure] = lanes; + } + + note.LaneIndex = measureLane[measure][note.LaneIndex]; + + int nextMeasure = measure + 1; + if (note.EndTime > nextMeasure * measureBPM[nextMeasure]) { + if (measureLane.find(nextMeasure) == measureLane.end()) { + measureLane[nextMeasure] = measureLane[measure]; + } + } + } + + // Log the randomization pattern for each measure + //int prevMeasure = -1; + //std::vector prevPattern; + //for (const auto& [measure, randomizedLane] : measureLane) { + // if (prevMeasure != -1 && prevPattern == randomizedLane) { + // continue; // Skip logging if the pattern is the same as the previous measure + // } + // std::stringstream pattern; + // for (int lane : randomizedLane) { + // pattern << lane; + // } + // int startMeasure = prevMeasure == -1 ? 0 : prevMeasure + 1; + // int endMeasure = measure; + // Logs::Puts("[Chart] Randomized Lane from Measure %d to %d with pattern: %s", startMeasure, endMeasure, pattern.str().c_str()); + // prevMeasure = measure; + // prevPattern = randomizedLane; + //} + break; } diff --git a/Game/src/Data/Chart.hpp b/Game/src/Data/Chart.hpp index fd5b25bc..3515ce63 100644 --- a/Game/src/Data/Chart.hpp +++ b/Game/src/Data/Chart.hpp @@ -75,6 +75,7 @@ struct AutoSample enum class Mod { MIRROR, RANDOM, + PANIC, REARRANGE }; @@ -85,6 +86,8 @@ class Chart Chart(Osu::Beatmap &beatmap); Chart(BMS::BMSFile &bmsfile); Chart(O2::OJN &ojnfile, int diffIndex = 2); + void CalculateBeat(); + void SortTimings(); ~Chart(); void ApplyMod(Mod mod, void *data = NULL); diff --git a/Game/src/Data/OJM.cpp b/Game/src/Data/OJM.cpp index fd20194c..c6a38ced 100644 --- a/Game/src/Data/OJM.cpp +++ b/Game/src/Data/OJM.cpp @@ -182,7 +182,7 @@ void OJM::LoadM30Data(std::fstream &fs) fs.read((char *)&Header, sizeof(M30Header)); - for (int i = 0; i < Header.sampleCount; i++) { // This fix no sound in few OJM + for (int i = 0; i < Header.sampleSize; i++) { struct M30SampleHeader { char sampleName[32]; diff --git a/Game/src/Engine/Autoplay.cpp b/Game/src/Engine/Autoplay.cpp index 747c0fee..648ed1cf 100644 --- a/Game/src/Engine/Autoplay.cpp +++ b/Game/src/Engine/Autoplay.cpp @@ -1,13 +1,10 @@ #include "Autoplay.h" #include "./Timing/TimingBase.h" -constexpr int kReleaseDelay = 25; - -const double kBaseBPM = 240.0; -const double kMaxTicks = 192.0; +constexpr double kReleaseDelay = 33.34; const double kNoteCoolHitRatio = 6.0; -NoteInfo *GetNextHitObject(std::vector &hitObject, int index) +NoteInfo* GetNextHitObject(std::vector& hitObject, int index) { int lane = hitObject[index].LaneIndex; @@ -20,30 +17,30 @@ NoteInfo *GetNextHitObject(std::vector &hitObject, int index) return nullptr; } -double CalculateReleaseTime(NoteInfo *currentHitObject, NoteInfo *nextHitObject) +double CalculateReleaseTime(NoteInfo* currentHitObject, NoteInfo* nextHitObject) { if (currentHitObject->Type == NoteType::HOLD) { return currentHitObject->EndTime; } double Time = currentHitObject->Type == NoteType::HOLD ? currentHitObject->EndTime - : currentHitObject->StartTime; + : currentHitObject->StartTime; bool canDelayFully = nextHitObject == nullptr || - nextHitObject->StartTime > Time + kReleaseDelay; + nextHitObject->StartTime > Time + kReleaseDelay; return Time + (canDelayFully ? kReleaseDelay : (nextHitObject->StartTime - Time) * 0.9); } -std::vector Autoplay::CreateReplay(Chart *chart) +std::vector Autoplay::CreateReplay(Chart* chart) { std::vector result; TimingBase timingBase(chart->m_bpms, chart->m_svs, chart->InitialSvMultiplier); for (int i = 0; i < chart->m_notes.size(); i++) { - auto ¤tHitObject = chart->m_notes[i]; - auto nextHitObject = GetNextHitObject(chart->m_notes, i); + auto& currentHitObject = chart->m_notes[i]; + auto nextHitObject = GetNextHitObject(chart->m_notes, i); double HitTime = currentHitObject.StartTime; double ReleaseTime = CalculateReleaseTime(¤tHitObject, nextHitObject); @@ -51,56 +48,26 @@ std::vector Autoplay::CreateReplay(Chart *chart) double bpmAtHit = timingBase.GetBPMAt(HitTime); double bpmAtRelease = timingBase.GetBPMAt(ReleaseTime); - int tries = 0; - - while (true) { - double beat = kBaseBPM / kMaxTicks / bpmAtHit * 1000.0; - double cool = beat * kNoteCoolHitRatio; - double late_cool = -cool; - - double _HIT = currentHitObject.StartTime - HitTime; - - if (_HIT >= late_cool && _HIT <= cool) { - break; - } - - if (_HIT > cool) { - HitTime++; - } else { - HitTime--; - } + double beat = 60000.0 / bpmAtHit; + double coolWindow = beat * kNoteCoolHitRatio; + double hitError = currentHitObject.StartTime - HitTime; - if (++tries >= 500) { - break; - } + while (std::abs(hitError) > coolWindow) { + HitTime += hitError > 0 ? 1 : -1; + hitError = currentHitObject.StartTime - HitTime; } - tries = 0; - - while (true) { - double beat = kBaseBPM / kMaxTicks / bpmAtRelease * 1000.0; - double cool = beat * kNoteCoolHitRatio; - double late_cool = -cool; - - double _HIT = (currentHitObject.Type == NoteType::HOLD ? currentHitObject.EndTime : currentHitObject.StartTime) - ReleaseTime; - - if (_HIT >= late_cool && _HIT <= cool) { - break; - } - - if (_HIT > cool) { - ReleaseTime++; - } else { - ReleaseTime--; - } + beat = 60000.0 / bpmAtRelease; + coolWindow = beat * kNoteCoolHitRatio; + double releaseError = (currentHitObject.Type == NoteType::HOLD ? currentHitObject.EndTime : currentHitObject.StartTime) - ReleaseTime; - if (++tries >= 500) { - break; - } + while (std::abs(releaseError) > coolWindow) { + ReleaseTime += releaseError > 0 ? 1 : -1; + releaseError = (currentHitObject.Type == NoteType::HOLD ? currentHitObject.EndTime : currentHitObject.StartTime) - ReleaseTime; } - result.push_back({ HitTime, (int)currentHitObject.LaneIndex, ReplayHitType::KEY_DOWN }); - result.push_back({ ReleaseTime, (int)currentHitObject.LaneIndex, ReplayHitType::KEY_UP }); + result.push_back({ HitTime, static_cast(currentHitObject.LaneIndex), ReplayHitType::KEY_DOWN }); + result.push_back({ ReleaseTime, static_cast(currentHitObject.LaneIndex), ReplayHitType::KEY_UP }); } return result; diff --git a/Game/src/Engine/BGMPreview.cpp b/Game/src/Engine/BGMPreview.cpp index 5d9adc0b..1f37b144 100644 --- a/Game/src/Engine/BGMPreview.cpp +++ b/Game/src/Engine/BGMPreview.cpp @@ -71,7 +71,7 @@ void BGMPreview::Load() m_autoSamples.clear(); for (auto &sample : m_currentChart->m_autoSamples) { - m_autoSamples.push_back(sample); + m_autoSamples.emplace_back(sample); } for (auto ¬e : m_currentChart->m_notes) { @@ -82,7 +82,7 @@ void BGMPreview::Load() sm.Volume = note.Volume; sm.Pan = note.Pan; - m_autoSamples.push_back(sm); + m_autoSamples.emplace_back(sm); } } @@ -118,7 +118,7 @@ void BGMPreview::Update(double delta) auto &sample = m_autoSamples[i]; if (m_currentAudioPosition >= sample.StartTime) { if (sample.StartTime - m_currentAudioPosition < 5) { - GameAudioSampleCache::Play(sample.Index, (int)::round(sample.Volume * 50.0f), (int)::round(sample.Pan * 100.0f)); + GameAudioSampleCache::Play(sample.Index, (int)::round(sample.Volume * 100.0f), (int)::round(sample.Pan * 100.0f)); } m_currentSampleIndex++; diff --git a/Game/src/Engine/DrawableNote.cpp b/Game/src/Engine/DrawableNote.cpp index e10f6f6c..db4f9b1e 100644 --- a/Game/src/Engine/DrawableNote.cpp +++ b/Game/src/Engine/DrawableNote.cpp @@ -5,24 +5,22 @@ DrawableNote::DrawableNote(NoteImage* frame) : FrameTimer::FrameTimer() { - m_frames = std::vector(); + m_frames.reserve(frame->Texture.size()); // Reserve memory for frames vector if (Renderer::GetInstance()->IsVulkan()) { - for (auto& frame : frame->VulkanTexture) { - m_frames.push_back(new Texture2D(frame)); + for (auto& texture : frame->VulkanTexture) { + m_frames.emplace_back(new Texture2D(texture)); + m_frames.back()->SetOriginalRECT(frame->TextureRect); // Set original RECT for each texture } } else { - for (auto& frame : frame->Texture) { - m_frames.push_back(new Texture2D(frame)); + for (auto& texture : frame->Texture) { + m_frames.emplace_back(new Texture2D(texture)); + m_frames.back()->SetOriginalRECT(frame->TextureRect); // Set original RECT for each texture } } AnchorPoint = { 0.0, 1.0 }; - for (auto& _frame : m_frames) { - _frame->SetOriginalRECT(frame->TextureRect); - } - - SetFPS(0); // FIXME: i had to use this value otherwise it has glitch + SetFPS(0); // slighly fix stupid glitch } diff --git a/Game/src/Engine/FrameTimer.cpp b/Game/src/Engine/FrameTimer.cpp index 246d455c..f015773e 100644 --- a/Game/src/Engine/FrameTimer.cpp +++ b/Game/src/Engine/FrameTimer.cpp @@ -6,7 +6,7 @@ FrameTimer::FrameTimer() { Repeat = false; m_currentFrame = 0; - m_frameTime = 1.0f / 60; + m_frameTime = 1.0f / 60.0f; m_currentTime = 0; AlphaBlend = false; Size = UDim2::fromScale(1, 1); @@ -22,7 +22,7 @@ FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer { m_frames = std::vector(); for (auto frame : frames) { - m_frames.push_back(new Texture2D(frame)); + m_frames.emplace_back(new Texture2D(frame)); } } @@ -30,7 +30,7 @@ FrameTimer::FrameTimer(std::vector frames) : FrameTimer:: { m_frames = std::vector(); for (auto frame : frames) { - m_frames.push_back(new Texture2D(frame)); + m_frames.emplace_back(new Texture2D(frame)); } } @@ -38,7 +38,7 @@ FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTim { m_frames = std::vector(); for (auto frame : frames) { - m_frames.push_back(new Texture2D(frame)); + m_frames.emplace_back(new Texture2D(frame)); } } @@ -46,7 +46,7 @@ FrameTimer::FrameTimer(std::vector frames) : FrameTimer::Fra { m_frames = std::vector(); for (auto frame : frames) { - m_frames.push_back(new Texture2D(frame)); + m_frames.emplace_back(new Texture2D(frame)); } } diff --git a/Game/src/Engine/FrameTimer.hpp b/Game/src/Engine/FrameTimer.hpp index 2d73dc62..b0d5efab 100644 --- a/Game/src/Engine/FrameTimer.hpp +++ b/Game/src/Engine/FrameTimer.hpp @@ -43,8 +43,9 @@ class FrameTimer void CalculateSize(); + std::vector m_frames; + protected: - std::vector m_frames; int m_currentFrame; double m_frameTime; double m_currentTime; diff --git a/Game/src/Engine/GameTrack.cpp b/Game/src/Engine/GameTrack.cpp index b03396b1..12a3e84b 100644 --- a/Game/src/Engine/GameTrack.cpp +++ b/Game/src/Engine/GameTrack.cpp @@ -71,7 +71,7 @@ void GameTrack::Update(double delta) if (note->IsRemoveable()) { note->Release(); - m_noteCaches.push_back(note); + m_noteCaches.emplace_back(note); _note = m_inactive_notes.erase(_note); } else { note->Update(delta); diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 547e299f..7c92c744 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -91,7 +91,7 @@ Note::Note(RhythmEngine *engine, GameTrack *track) m_hitPos = 0; m_relPos = 0; - m_keyVolume = 50; + m_keyVolume = 100; m_keyPan = 0; m_lastScoreTime = -1; @@ -206,6 +206,10 @@ void Note::Update(double delta) } } } + bool pressed = IsPassed(); + if (pressed) { + m_state = NoteState::DO_REMOVE; + } } void Note::Render(double delta) @@ -489,8 +493,8 @@ void Note::OnRelease(NoteResult result) m_lastScoreTime = -1; if (result == NoteResult::MISS) { - GameAudioSampleCache::Stop(m_keysoundIndex); - m_state = NoteState::HOLD_MISSED_ACTIVE; + //GameAudioSampleCache::Stop(m_keysoundIndex); + m_state = NoteState::DO_REMOVE; m_track->HandleHoldScore(HoldResult::HoldBreak); m_track->HandleScore({ result, @@ -541,7 +545,7 @@ bool Note::IsRemoveable() bool Note::IsPassed() { - return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED; + return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED || IsRemoveable(); } bool Note::IsHeadHit() diff --git a/Game/src/Engine/NoteImageCacheManager.cpp b/Game/src/Engine/NoteImageCacheManager.cpp index d2a7d9bf..b148740c 100644 --- a/Game/src/Engine/NoteImageCacheManager.cpp +++ b/Game/src/Engine/NoteImageCacheManager.cpp @@ -1,154 +1,121 @@ #include "NoteImageCacheManager.hpp" -#include #include -constexpr int MAX_OBJECTS = 50; +constexpr int MAX_OBJECTS = 64; -NoteImageCacheManager::NoteImageCacheManager() -{ - m_noteTextures = std::unordered_map>(); +NoteImageCacheManager::NoteImageCacheManager() { + m_totalCount = 0; + m_totalNoteCount = 0; + m_totalHoldCount = 0; + m_totalTrailCount = 0; } -NoteImageCacheManager::~NoteImageCacheManager() -{ - for (auto &it : m_noteTextures) { - for (auto &it2 : it.second) { - delete it2; - } - } +NoteImageCacheManager::~NoteImageCacheManager() { - for (auto &it : m_holdTextures) { - for (auto &it2 : it.second) { - delete it2; - } - } +} - for (auto &it : m_trailTextures) { - for (auto &it2 : it.second) { - delete it2; - } +NoteImageCacheManager* NoteImageCacheManager::s_instance = nullptr; + +NoteImageCacheManager* NoteImageCacheManager::GetInstance() { + if (s_instance == nullptr) { + s_instance = new NoteImageCacheManager(); } + return s_instance; } -NoteImageCacheManager *NoteImageCacheManager::s_instance = nullptr; +void NoteImageCacheManager::Release() { + if (s_instance) { + // Clean up all note textures + for (auto& pair : s_instance->m_noteTextures) { + for (auto& note : pair.second) { + delete note; + } + } + s_instance->m_noteTextures.clear(); -void NoteImageCacheManager::Repool(DrawableNote *image, NoteImageType noteType) -{ - if (image == nullptr) - return; + // Clean up all hold textures + for (auto& pair : s_instance->m_holdTextures) { + for (auto& note : pair.second) { + delete note; + } + } + s_instance->m_holdTextures.clear(); - auto &it = m_noteTextures[noteType]; + // Clean up all trail textures + for (auto& pair : s_instance->m_trailTextures) { + for (auto& note : pair.second) { + delete note; + } + } + s_instance->m_trailTextures.clear(); - if (it.size() >= MAX_OBJECTS) { - delete image; - return; + delete s_instance; + s_instance = nullptr; } - - it.push_back(image); } -void NoteImageCacheManager::RepoolHold(DrawableNote *image, NoteImageType noteType) -{ - if (image == nullptr) +void NoteImageCacheManager::Repool(DrawableNote* image, NoteImageType noteType) { + if (image == nullptr || m_noteTextures[noteType].size() >= MAX_OBJECTS) return; - auto &it = m_holdTextures[noteType]; - - if (it.size() >= MAX_OBJECTS) { - delete image; - return; - } - - it.push_back(image); + m_noteTextures[noteType].push_back(image); + m_totalNoteCount++; } -void NoteImageCacheManager::RepoolTrail(DrawableNote *image, NoteImageType noteType) -{ - if (image == nullptr) +void NoteImageCacheManager::RepoolHold(DrawableNote* image, NoteImageType noteType) { + if (image == nullptr || m_holdTextures[noteType].size() >= MAX_OBJECTS) return; - auto &it = m_trailTextures[noteType]; + m_holdTextures[noteType].push_back(image); + m_totalHoldCount++; +} - if (it.size() >= MAX_OBJECTS) { - delete image; +void NoteImageCacheManager::RepoolTrail(DrawableNote* image, NoteImageType noteType) { + if (image == nullptr || m_trailTextures[noteType].size() >= MAX_OBJECTS) return; - } - it.push_back(image); + m_trailTextures[noteType].push_back(image); + m_totalTrailCount++; } -DrawableNote *NoteImageCacheManager::Depool(NoteImageType noteType) -{ - if (noteType >= NoteImageType::LANE_1 && noteType <= NoteImageType::LANE_7) { - auto &it = m_noteTextures[noteType]; - DrawableNote *image = nullptr; - if (it.size() > 0) { - image = it.back(); - it.pop_back(); - } else { - image = new DrawableNote(GameNoteResource::GetNoteTexture(noteType)); - image->Repeat = true; - } - - return image; +DrawableNote* NoteImageCacheManager::Depool(NoteImageType noteType) { + auto& textureMap = m_noteTextures[noteType]; + if (!textureMap.empty()) { + DrawableNote* note = textureMap.back(); + textureMap.pop_back(); + return note; } else { - return nullptr; + // Create a new note if the pool is empty + DrawableNote* note = new DrawableNote(GameNoteResource::GetNoteTexture(noteType)); + note->Repeat = true; + return note; } } -DrawableNote *NoteImageCacheManager::DepoolHold(NoteImageType noteType) -{ - if (noteType >= NoteImageType::HOLD_LANE_1 && noteType <= NoteImageType::HOLD_LANE_7) { - auto &it = m_holdTextures[noteType]; - DrawableNote *image = nullptr; - if (it.size() > 0) { - image = it.back(); - it.pop_back(); - } else { - image = new DrawableNote(GameNoteResource::GetNoteTexture(noteType)); - image->Repeat = true; - } - - return image; +DrawableNote* NoteImageCacheManager::DepoolHold(NoteImageType noteType) { + auto& textureMap = m_holdTextures[noteType]; + if (!textureMap.empty()) { + DrawableNote* note = textureMap.back(); + textureMap.pop_back(); + return note; } else { - return nullptr; + // Create a new hold note if the pool is empty + DrawableNote* note = new DrawableNote(GameNoteResource::GetNoteTexture(noteType)); + note->Repeat = true; + return note; } } -DrawableNote *NoteImageCacheManager::DepoolTrail(NoteImageType noteType) -{ - if (noteType >= NoteImageType::TRAIL_UP && noteType <= NoteImageType::TRAIL_DOWN) { - auto &it = m_trailTextures[noteType]; - DrawableNote *image = nullptr; - if (it.size() > 0) { - image = it.back(); - it.pop_back(); - } else { - image = new DrawableNote(GameNoteResource::GetNoteTexture(noteType)); - image->Repeat = true; - } - - return image; +DrawableNote* NoteImageCacheManager::DepoolTrail(NoteImageType noteType) { + auto& textureMap = m_trailTextures[noteType]; + if (!textureMap.empty()) { + DrawableNote* note = textureMap.back(); + textureMap.pop_back(); + return note; } else { - return nullptr; - } -} - -NoteImageCacheManager *NoteImageCacheManager::GetInstance() -{ - if (s_instance == nullptr) { - s_instance = new NoteImageCacheManager(); - } - - return s_instance; -} - -void NoteImageCacheManager::Release() -{ - if (s_instance) { - Logs::Puts("[NoteImageCacheManager] Release about: hold=%d, note=%d, trail=%d", s_instance->m_holdTextures.size(), s_instance->m_noteTextures.size(), s_instance->m_trailTextures.size()); - - delete s_instance; - s_instance = nullptr; + // Create a new trail note if the pool is empty + DrawableNote* note = new DrawableNote(GameNoteResource::GetNoteTexture(noteType)); + note->Repeat = true; + return note; } } diff --git a/Game/src/Engine/NoteImageCacheManager.hpp b/Game/src/Engine/NoteImageCacheManager.hpp index b72333e8..37957fa7 100644 --- a/Game/src/Engine/NoteImageCacheManager.hpp +++ b/Game/src/Engine/NoteImageCacheManager.hpp @@ -12,22 +12,27 @@ class NoteImageCacheManager ~NoteImageCacheManager(); // Store a note texture in the cache - void Repool(DrawableNote *image, NoteImageType noteType); - void RepoolHold(DrawableNote *image, NoteImageType noteType); - void RepoolTrail(DrawableNote *image, NoteImageType noteType); + void Repool(DrawableNote* image, NoteImageType noteType); + void RepoolHold(DrawableNote* image, NoteImageType noteType); + void RepoolTrail(DrawableNote* image, NoteImageType noteType); // Get a note texture from the cache if exists, otherwise create a new one - DrawableNote *Depool(NoteImageType noteType); - DrawableNote *DepoolHold(NoteImageType noteType); - DrawableNote *DepoolTrail(NoteImageType noteType); + DrawableNote* Depool(NoteImageType noteType); + DrawableNote* DepoolHold(NoteImageType noteType); + DrawableNote* DepoolTrail(NoteImageType noteType); - static NoteImageCacheManager *GetInstance(); + static NoteImageCacheManager* GetInstance(); static void Release(); private: - static NoteImageCacheManager *s_instance; + size_t m_totalCount; + size_t m_totalNoteCount; + size_t m_totalHoldCount; + size_t m_totalTrailCount; - std::unordered_map> m_noteTextures; - std::unordered_map> m_holdTextures; - std::unordered_map> m_trailTextures; + static NoteImageCacheManager* s_instance; + + std::unordered_map> m_noteTextures; + std::unordered_map> m_holdTextures; + std::unordered_map> m_trailTextures; }; \ No newline at end of file diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 66635d28..3c8351dd 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -17,8 +17,8 @@ #include "Judgements/BeatBasedJudge.h" #include "Judgements/MsBasedJudge.h" -#include -#include +//#include +//#include #define MAX_BUFFER_TXT_SIZE 256 @@ -62,7 +62,10 @@ namespace { int trackOffset[] = { 5, 33, 55, 82, 114, 142, 164 }; } // namespace -RhythmEngine::RhythmEngine() +RhythmEngine::RhythmEngine() : + m_lanePos{ 0 }, + m_laneSize{ 0 }, + m_playRectangle{ 0, 0, 0, 0 } { m_currentAudioGamePosition = 0; m_currentVisualPosition = 0; @@ -70,8 +73,10 @@ RhythmEngine::RhythmEngine() m_rate = 1; m_offset = 0; m_scrollSpeed = 180; - + m_PlayTime = 0.0; m_timingPositionMarkers = std::vector(); + m_baseBPM = 0; + m_currentChart = nullptr; } RhythmEngine::~RhythmEngine() @@ -93,7 +98,7 @@ bool RhythmEngine::Load(Chart *chart) m_noteMaxImageIndex = 99; int currentX = m_laneOffset; - for (int i = 0; i < 7; i++) { + for (int i = 0; i < chart->m_keyCount; i++) { m_tracks.push_back(new GameTrack(this, i, currentX)); m_autoHitIndex[i] = 0; @@ -103,10 +108,10 @@ bool RhythmEngine::Load(Chart *chart) }); } - auto noteTex = GameNoteResource::GetNoteTexture(Key2Type[i]); + auto noteImage = GameNoteResource::GetNoteTexture(Key2Type[i]); - int size = noteTex->TextureRect.right; - m_noteMaxImageIndex = (std::min)(noteTex->MaxFrames, m_noteMaxImageIndex); + int size = noteImage->TextureRect.right; + m_noteMaxImageIndex = (std::min)(noteImage->MaxFrames, m_noteMaxImageIndex); m_lanePos[i] = static_cast(currentX); m_laneSize[i] = static_cast(size); @@ -124,9 +129,10 @@ bool RhythmEngine::Load(Chart *chart) chart->ApplyMod(Mod::MIRROR); } else if (EnvironmentSetup::GetInt("Random")) { chart->ApplyMod(Mod::RANDOM); + } else if (EnvironmentSetup::GetInt("Panic")) { + chart->ApplyMod(Mod::PANIC); } else if (EnvironmentSetup::GetInt("Rearrange")) { void *lane_data = EnvironmentSetup::GetObj("LaneData"); - chart->ApplyMod(Mod::REARRANGE, lane_data); } else if (EnvironmentSetup::GetInt("NoSV")) { isSV = true; @@ -296,7 +302,7 @@ bool RhythmEngine::Load(Chart *chart) m_timingLineManager = chart->m_customMeasures.size() > 0 ? new TimingLineManager(this, chart->m_customMeasures) : new TimingLineManager(this); m_scoreManager = new ScoreManager(); - m_startClock = std::chrono::system_clock::now(); + //m_startClock = std::chrono::system_clock::now(); m_timingLineManager->Init(); m_state = GameState::NotGame; @@ -314,15 +320,16 @@ bool RhythmEngine::Start() { // no, use update event instead m_currentAudioPosition -= 3000; m_state = GameState::Playing; - - m_startClock = std::chrono::system_clock::now(); + //m_startClock = std::chrono::system_clock::now(); return true; } bool RhythmEngine::Stop() { m_state = GameState::PosGame; + GameAudioSampleCache::StopAll(); return true; + m_PlayTime = 0.0; } bool RhythmEngine::Ready() @@ -347,9 +354,9 @@ void RhythmEngine::Update(double delta) // assert(false); // TODO: Handle this } - if (m_currentAudioPosition > m_audioLength + 2500) { // Avoid game ended too early + if (m_currentAudioPosition > m_audioLength + 2000) { // Avoid game ended too early m_state = GameState::PosGame; - ::printf("Audio stopped!\n"); + GameAudioSampleCache::StopAll(); } if (static_cast(m_currentAudioPosition) % 1000 == 0) { @@ -392,9 +399,10 @@ void RhythmEngine::Update(double delta) } } - auto currentTime = std::chrono::system_clock::now(); - auto elapsedTime = std::chrono::duration_cast(currentTime - m_startClock); - m_PlayTime = static_cast(elapsedTime.count() - 2); + //auto currentTime = std::chrono::system_clock::now(); + //auto elapsedTime = std::chrono::duration_cast(currentTime - m_startClock); + //m_PlayTime = static_cast(elapsedTime.count() - 4); + m_PlayTime += delta; } void RhythmEngine::Render(double delta) @@ -564,14 +572,14 @@ std::vector RhythmEngine::GetSVs() const return m_currentChart->m_svs; } -double RhythmEngine::GetElapsedTime() const -{ // Get game frame +double RhythmEngine::GetGameFrame() const +{ return static_cast(SDL_GetTicks()) / 1000.0; } int RhythmEngine::GetPlayTime() const -{ // Get game time - return m_PlayTime; +{ + return static_cast(m_PlayTime - 3); } int RhythmEngine::GetNoteImageIndex() @@ -682,7 +690,7 @@ ReplayFrameData RhythmEngine::GetAutoplayAtThisFrame(double offset) } } - return std::move(data); + return data; } const float *RhythmEngine::GetLaneSizes() const diff --git a/Game/src/Engine/RhythmEngine.hpp b/Game/src/Engine/RhythmEngine.hpp index 7e00cf97..c3f0e9ab 100644 --- a/Game/src/Engine/RhythmEngine.hpp +++ b/Game/src/Engine/RhythmEngine.hpp @@ -76,7 +76,7 @@ class RhythmEngine std::vector GetBPMs() const; std::vector GetSVs() const; - double GetElapsedTime() const; + double GetGameFrame() const; int GetPlayTime() const; int GetNoteImageIndex(); @@ -140,8 +140,8 @@ class RhythmEngine std::vector m_autoFrames; /* clock system */ - int m_PlayTime = 0; - std::chrono::system_clock::time_point m_startClock; + double m_PlayTime; + //std::chrono::system_clock::time_point m_startClock; TimingBase *m_timings = nullptr; JudgeBase *m_judge = nullptr; diff --git a/Game/src/Engine/ScoreManager.cpp b/Game/src/Engine/ScoreManager.cpp index b456ddf4..f63cac49 100644 --- a/Game/src/Engine/ScoreManager.cpp +++ b/Game/src/Engine/ScoreManager.cpp @@ -32,7 +32,7 @@ ScoreManager::~ScoreManager() { } -void ScoreManager::OnHit(NoteHitInfo info) // Fuck it, just leave it max HP 100 and divided that by 10 +void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 and divided that by 10 { int difficulty = EnvironmentSetup::GetInt("Difficulty"); switch (difficulty) { @@ -178,8 +178,7 @@ void ScoreManager::OnHit(NoteHitInfo info) // Fuck it, just leave it max HP 100 m_coolCombo = 0; m_numOfPills = std::clamp(m_numOfPills + 1, 0, 5); } - } - else { + } else { m_coolCombo = 0; } @@ -210,17 +209,17 @@ void ScoreManager::OnHit(NoteHitInfo info) // Fuck it, just leave it max HP 100 void ScoreManager::OnLongNoteHold(HoldResult result) { switch (result) { - case HoldResult::HoldBreak: - { - m_lnCombo = 0; - break; - } + case HoldResult::HoldBreak: + { + m_lnCombo = 0; + break; + } - case HoldResult::HoldAdd: - { - m_lnCombo += 1; - break; - } + case HoldResult::HoldAdd: + { + m_lnCombo += 1; + break; + } } m_lnMaxCombo = (std::max)(m_lnCombo, m_lnMaxCombo); @@ -271,4 +270,4 @@ void ScoreManager::AddLife(float sz) m_life += sz; m_life = std::clamp(m_life, 0.0f, 100.0f); } -} \ No newline at end of file +} diff --git a/Game/src/Engine/Timing/TimingBase.cpp b/Game/src/Engine/Timing/TimingBase.cpp index 98a58f72..287b3230 100644 --- a/Game/src/Engine/Timing/TimingBase.cpp +++ b/Game/src/Engine/Timing/TimingBase.cpp @@ -7,7 +7,7 @@ TimingBase::TimingBase(std::vector &_timings, std::vector &timings, double offset) +static TimingInfo& FindTimingAt(std::vector& timings, double offset) { int min = 0, max = (int)timings.size() - 1; int left = min, right = max; @@ -16,13 +16,15 @@ TimingInfo &FindTimingAt(std::vector &timings, double offset) int mid = (left + right) / 2; bool afterMid = mid < 0 || timings[mid].StartTime < offset; - bool beforeMid = mid + 1 >= timings.size() || offset < timings[mid + 1].StartTime; + bool beforeMid = static_cast(mid) + 1 >= timings.size() || offset < timings[static_cast>::size_type>(mid) + 1].StartTime; if (afterMid && beforeMid) { return timings[mid]; - } else if (afterMid) { + } + else if (afterMid) { left = mid + 1; - } else { + } + else { right = mid - 1; } } @@ -37,7 +39,14 @@ double TimingBase::GetBeatAt(double offset) double TimingBase::GetBPMAt(double offset) { - return FindTimingAt(timings, offset).Value; + double BPM = FindTimingAt(timings, offset).Value; + + // Handle BPM overflow at int32_t range + if (BPM >= INT_MAX || BPM <= -INT_MAX) { + BPM = fmod(BPM, INT_MAX); + } + + return BPM; } double TimingBase::GetOffsetAt(double offset) diff --git a/Game/src/EnvironmentSetup.cpp b/Game/src/EnvironmentSetup.cpp index f4a3733b..421ac62b 100644 --- a/Game/src/EnvironmentSetup.cpp +++ b/Game/src/EnvironmentSetup.cpp @@ -3,54 +3,58 @@ namespace { std::unordered_map m_stores; - std::unordered_map m_storesPtr; + std::unordered_map m_storesPtr; std::unordered_map m_paths; std::unordered_map m_ints; } // namespace void EnvironmentSetup::OnExitCheck() { - for (auto &[key, value] : m_stores) { - value = ""; - } - - for (auto &[key, value] : m_paths) { - value = ""; - } - - for (auto &[key, value] : m_ints) { - value = 0; - } + m_stores.clear(); + m_paths.clear(); + m_ints.clear(); } void EnvironmentSetup::Set(std::string key, std::string value) { - m_stores[key] = value; + m_stores[key] = std::move(value); } std::string EnvironmentSetup::Get(std::string key) { - return m_stores[key]; + auto it = m_stores.find(key); + if (it != m_stores.end()) { + return it->second; + } + return ""; } -void EnvironmentSetup::SetObj(std::string key, void *ptr) +void EnvironmentSetup::SetObj(std::string key, void* ptr) { m_storesPtr[key] = ptr; } -void *EnvironmentSetup::GetObj(std::string key) +void* EnvironmentSetup::GetObj(std::string key) { - return m_storesPtr[key]; + auto it = m_storesPtr.find(key); + if (it != m_storesPtr.end()) { + return it->second; + } + return nullptr; } void EnvironmentSetup::SetPath(std::string key, std::filesystem::path path) { - m_paths[key] = path; + m_paths[key] = std::move(path); } std::filesystem::path EnvironmentSetup::GetPath(std::string key) { - return m_paths[key]; + auto it = m_paths.find(key); + if (it != m_paths.end()) { + return it->second; + } + return {}; } void EnvironmentSetup::SetInt(std::string key, int value) @@ -60,5 +64,9 @@ void EnvironmentSetup::SetInt(std::string key, int value) int EnvironmentSetup::GetInt(std::string key) { - return m_ints[key]; -} + auto it = m_ints.find(key); + if (it != m_ints.end()) { + return it->second; + } + return 0; +} \ No newline at end of file diff --git a/Game/src/MyGame.cpp b/Game/src/MyGame.cpp index 316a4966..2eb2b500 100644 --- a/Game/src/MyGame.cpp +++ b/Game/src/MyGame.cpp @@ -68,7 +68,7 @@ bool MyGame::Init() /* Overlays */ SceneManager::AddOverlay(GameOverlay::SETTINGS, new SettingsOverlay()); - std::string title = std::string(O2GAME_TITLE) + " " + std::string(O2GAME_VERSION); + std::string title = std::string(O2GAME_TITLE) + "" + ""/*std::string(O2GAME_VERSION)*/; m_window->SetWindowTitle(title); if (EnvironmentSetup::GetPath("FILE").empty()) { diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 2664e692..3a3b4604 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -70,15 +70,22 @@ void GameplayScene::Update(double delta) } if (!m_starting) { + EnvironmentSetup::SetInt("FillStart", 1); m_starting = true; m_game->Start(); } if (m_game->GetState() == GameState::PosGame && !m_ended) { - m_ended = true; - SceneManager::DisplayFade(100, [] { - SceneManager::ChangeScene(GameScene::RESULT); - }); + m_counter += delta; + m_minuteNum->DrawNumber(0); + m_secondNum->DrawNumber(0); + + if (m_counter > 10.0) { + m_ended = true; + SceneManager::DisplayFade(100, [] { + SceneManager::ChangeScene(GameScene::RESULT); + }); + } } int difficulty = EnvironmentSetup::GetInt("Difficulty"); @@ -87,15 +94,22 @@ void GameplayScene::Update(double delta) if (health <= 0) { m_game->Stop(); - } + EnvironmentSetup::SetInt("Failed", 1); + } } if (m_doExit && !m_ended) { m_ended = true; - + auto scores = m_game->GetScoreManager()->GetScore(); if (std::get<1>(scores) != 0 || std::get<2>(scores) != 0 || std::get<3>(scores) != 0 || std::get<4>(scores) != 0) { + if (m_game->GetState() == GameState::PosGame) { + EnvironmentSetup::SetInt("Failed", 0); + } + else { + EnvironmentSetup::SetInt("Failed", 1); + } SceneManager::DisplayFade(100, [] { SceneManager::ChangeScene(GameScene::RESULT); }); @@ -127,6 +141,7 @@ void GameplayScene::Render(double delta) if (useSongBG) { auto songBG = (Texture2D*)EnvironmentSetup::GetObj("SongBackground"); if (songBG) { + songBG->TintColor = Color3::FromRGB(128, 128, 128); songBG->Draw(); } } @@ -184,28 +199,55 @@ void GameplayScene::Render(double delta) m_pills[i]->Draw(); } - auto curLifeTex = m_lifeBar->GetTexture(); // Move lifebar to here so it will not overlapping - curLifeTex->CalculateSize(); - - Rect rc = {}; - rc.left = static_cast(curLifeTex->AbsolutePosition.X); - rc.top = static_cast(curLifeTex->AbsolutePosition.Y); - rc.right = static_cast(rc.left + curLifeTex->AbsoluteSize.X); - rc.bottom = static_cast(rc.top + curLifeTex->AbsoluteSize.Y + 10); // Add + value because of the wiggle effect - float alpha = (float)(kMaxLife - m_game->GetScoreManager()->GetLife()) / kMaxLife; - - // Add wiggle effect - float yOffset = 0.0f; - // Wiggle effect after the first second - yOffset = sinf((float)m_game->GetElapsedTime() * 75.0f) * 10.0f; - - int topCur = (int)::round((1.0f - alpha) * rc.top + alpha * rc.bottom); - rc.top = topCur + static_cast(::round(yOffset)); - if (rc.top >= rc.bottom) { - rc.top = rc.bottom - 1; + bool fillstart = EnvironmentSetup::GetInt("FillStart") == 1; + + if (fillstart) { + lifeFillDuration += delta; + + float fillRatio = ((lifeFillDuration - 0.5) / 1.0 < 1.0f) ? static_cast((lifeFillDuration - 0.5) / 1.0) : 1.0f; + float alpha = 1.0f - fillRatio; + + auto curLifeTex = m_lifeBar->GetTexture(); + curLifeTex->CalculateSize(); + + Rect rc = {}; + rc.left = static_cast(curLifeTex->AbsolutePosition.X); + rc.top = static_cast(curLifeTex->AbsolutePosition.Y + curLifeTex->AbsoluteSize.Y * (1.0f - fillRatio)); + rc.right = static_cast(rc.left + curLifeTex->AbsoluteSize.X); + rc.bottom = static_cast(rc.top + curLifeTex->AbsoluteSize.Y); + + m_lifeBar->Draw(delta, &rc); + + if (lifeFillDuration > 1.5) { + EnvironmentSetup::SetInt("FillStart", 0); + } } + else { + lifeFillDuration = 0.0; + + float alpha = (float)(kMaxLife - m_game->GetScoreManager()->GetLife()) / kMaxLife; + + auto curLifeTex = m_lifeBar->GetTexture(); + curLifeTex->CalculateSize(); + + float offset = 10.0f; + + Rect rc = {}; + rc.left = static_cast(curLifeTex->AbsolutePosition.X); + rc.top = static_cast(curLifeTex->AbsolutePosition.Y); + rc.right = static_cast(rc.left + curLifeTex->AbsoluteSize.X); + rc.bottom = static_cast(rc.top + curLifeTex->AbsoluteSize.Y + offset); + + double wiggle = sinf(static_cast(m_game->GetGameFrame()) * 60.0f) * offset; - m_lifeBar->Draw(delta, &rc); + int topCur = (int)::round((1.0f - alpha) * rc.top + alpha * rc.bottom); + rc.top = topCur + static_cast(::round(wiggle)); + if (rc.top >= rc.bottom) { + rc.top = rc.bottom - 1; + } + + m_lifeBar->Draw(delta, &rc); + } if (m_drawJudge && m_judgement[m_judgeIndex] != nullptr) { m_judgement[m_judgeIndex]->Size = UDim2::fromScale(m_judgeSize, m_judgeSize); @@ -325,9 +367,7 @@ void GameplayScene::Render(double delta) int currentMinutes = PlayTime / 60; int currentSeconds = PlayTime % 60; - m_minuteNum->SetValue(currentMinutes); m_minuteNum->DrawNumber(currentMinutes); - m_secondNum->SetValue(currentSeconds); m_secondNum->DrawNumber(currentSeconds); for (int i = 0; i < 7; i++) { @@ -348,9 +388,9 @@ void GameplayScene::Render(double delta) m_autoText->Position = m_autoTextPos; m_autoText->Draw(AUTOPLAY_TEXT); - m_autoTextPos.X.Offset -= delta * 50.0; - if (m_autoTextPos.X.Offset < (-m_autoTextSize + 20)) { - m_autoTextPos = UDim2::fromOffset(GameWindow::GetInstance()->GetBufferWidth(), 50); + m_autoTextPos.X.Offset -= delta * 30.0; + if (m_autoTextPos.X.Offset < (-m_autoTextSize + 30)) { + m_autoTextPos = UDim2::fromOffset(GameWindow::GetInstance()->GetBufferWidth(), 60); } } @@ -1098,12 +1138,6 @@ bool GameplayScene::Attach() m_game->GetScoreManager()->ListenLongNote(OnLongComboEvent); - if (arena != -1) { - auto obj = (Texture2D*)EnvironmentSetup::GetObj("SongBackground"); - if (obj) { - obj->TintColor = Color3::FromRGB(128, 128, 128); - } - } } catch (SDLException& e) { @@ -1187,12 +1221,10 @@ bool GameplayScene::Detach() m_title.reset(); m_exitButtonFunc.reset(); - int arena = EnvironmentSetup::GetInt("Arena"); - if (arena) { - auto obj = (Texture2D*)EnvironmentSetup::GetObj("SongBackground"); - if (obj) { - obj->TintColor = Color3::FromRGB(255, 255, 255); - } + + auto songBG = (Texture2D*)EnvironmentSetup::GetObj("SongBackground"); + if (songBG) { + songBG->TintColor = Color3::FromRGB(255, 255, 255); } SceneManager::GetInstance()->SetFrameLimitMode(FrameLimitMode::MENU); diff --git a/Game/src/Scenes/GameplayScene.h b/Game/src/Scenes/GameplayScene.h index 7377f0dc..d4d20bb3 100644 --- a/Game/src/Scenes/GameplayScene.h +++ b/Game/src/Scenes/GameplayScene.h @@ -95,6 +95,7 @@ class GameplayScene : public Scene double m_judgeTimer; double m_comboTimer; double m_lnTimer; + double m_counter; /* other stuff */ double m_judgeSize; @@ -107,6 +108,8 @@ class GameplayScene : public Scene bool m_drawExitButton; bool m_doExit; + double lifeFillDuration; + /* auto text size */ bool m_autoPlay; int m_autoTextSize; diff --git a/Game/src/Scenes/LoadingScene.cpp b/Game/src/Scenes/LoadingScene.cpp index c9e3d461..217fc103 100644 --- a/Game/src/Scenes/LoadingScene.cpp +++ b/Game/src/Scenes/LoadingScene.cpp @@ -39,7 +39,7 @@ void LoadingScene::Update(double delta) int diffIndex = EnvironmentSetup::GetInt("Difficulty"); bool IsO2Jam = false; - Chart* chart = (Chart*)EnvironmentSetup::GetObj("SONG"); + Chart *chart = (Chart *)EnvironmentSetup::GetObj("SONG"); if (chart == nullptr || chart->GetO2JamId() != songId) { if (!fucked) { std::filesystem::path file; @@ -47,8 +47,7 @@ void LoadingScene::Update(double delta) if (songId != -1) { file = GameDatabase::GetInstance()->GetPath(); file /= "o2ma" + std::to_string(songId) + ".ojn"; - } - else { + } else { file = EnvironmentSetup::GetPath("FILE"); IsFile = true; @@ -61,8 +60,8 @@ void LoadingScene::Update(double delta) EnvironmentSetup::SetInt("Difficulty", 2); // Hard difficulty it's fun (fucked) } - const char* bmsfile[] = { ".bms", ".bme", ".bml", ".bmsc" }; - const char* ojnfile = ".ojn"; + const char *bmsfile[] = { ".bms", ".bme", ".bml", ".bmsc" }; + const char *ojnfile = ".ojn"; if (file.extension() == bmsfile[0] || file.extension() == bmsfile[1] || file.extension() == bmsfile[2] || file.extension() == bmsfile[3]) { BMS::BMSFile beatmap; @@ -75,8 +74,7 @@ void LoadingScene::Update(double delta) } chart = new Chart(beatmap); - } - else if (file.extension() == ojnfile) { + } else if (file.extension() == ojnfile) { O2::OJN o2jamFile; o2jamFile.Load(file); @@ -91,8 +89,7 @@ void LoadingScene::Update(double delta) chart = new Chart(o2jamFile, diffIndex); IsO2Jam = true; - } - else { + } else { Osu::Beatmap beatmap(file); if (!beatmap.IsValid()) { @@ -106,8 +103,7 @@ void LoadingScene::Update(double delta) EnvironmentSetup::SetObj("SONG", chart); } - } - else { + } else { IsO2Jam = chart->GetO2JamId() == songId; // TODO: refactor this } @@ -127,14 +123,14 @@ void LoadingScene::Update(double delta) if (!fucked) { try { if (m_background == nullptr) { - GameWindow* window = GameWindow::GetInstance(); + GameWindow *window = GameWindow::GetInstance(); if (chart->m_backgroundFile.size() > 0 && std::filesystem::exists(dirPath)) { m_background = new Texture2D(dirPath.string()); m_background->Size = UDim2::fromOffset(window->GetBufferWidth(), window->GetBufferHeight()); } if (chart->m_backgroundBuffer.size() > 0 && m_background == nullptr) { - m_background = new Texture2D((uint8_t*)chart->m_backgroundBuffer.data(), chart->m_backgroundBuffer.size()); + m_background = new Texture2D((uint8_t *)chart->m_backgroundBuffer.data(), chart->m_backgroundBuffer.size()); m_background->Size = UDim2::fromOffset(window->GetBufferWidth(), window->GetBufferHeight()); } @@ -149,28 +145,26 @@ void LoadingScene::Update(double delta) } } } - } - catch (SDLException& e) { + } catch (SDLException &e) { MsgBox::Show("FailChart", "Error", "Failed to create texture: " + std::string(e.what())); fucked = true; } } - if (m_counter > 2.5 && chart != nullptr) { + if (m_counter > 3.0 && chart != nullptr) { if (IsFile) { EnvironmentSetup::SetObj("SongBackground", m_background); } SceneManager::ChangeScene(GameScene::GAMEPLAY); - } - else { + EnvironmentSetup::SetInt("FillStart", 1); + } else { if (fucked) { std::string songId = EnvironmentSetup::Get("Key"); if (songId.size() > 0) { if (m_counter > 1) { SceneManager::ChangeScene(GameScene::MAINMENU); } - } - else { + } else { if (MsgBox::GetResult("FailChart") == 4) { SceneManager::GetInstance()->StopGame(); } @@ -190,12 +184,14 @@ bool LoadingScene::Attach() { SceneManager::DisplayFade(0, [] {}); + EnvironmentSetup::SetInt("FillStart", 0); + fucked = false; is_shown = false; is_ready = true; m_counter = 0; - m_background = (Texture2D*)EnvironmentSetup::GetObj("SongBackground"); + m_background = (Texture2D *)EnvironmentSetup::GetObj("SongBackground"); dont_dispose = m_background != nullptr; return true; } @@ -207,5 +203,7 @@ bool LoadingScene::Detach() m_background = nullptr; } + EnvironmentSetup::SetInt("FillStart", 1); + return true; -} \ No newline at end of file +} diff --git a/Game/src/Scenes/LoadingScene.h b/Game/src/Scenes/LoadingScene.h index 796cc64a..c3ad174c 100644 --- a/Game/src/Scenes/LoadingScene.h +++ b/Game/src/Scenes/LoadingScene.h @@ -26,5 +26,5 @@ class LoadingScene : public Scene std::u8string m_title; double m_counter; - Texture2D* m_background; + Texture2D *m_background; }; \ No newline at end of file diff --git a/Game/src/Scenes/MainMenu.cpp b/Game/src/Scenes/MainMenu.cpp index 819ac3f4..5d618869 100644 --- a/Game/src/Scenes/MainMenu.cpp +++ b/Game/src/Scenes/MainMenu.cpp @@ -21,129 +21,138 @@ void MainMenu::Update(double delta) { } +//void MainMenu::Render(double delta) +//{ +// ImguiUtil::NewFrame(); +// +// auto window = GameWindow::GetInstance(); +// ImGui::SetNextWindowPos(ImVec2(0, 0)); +// +// auto windowNextSz = ImVec2((float)window->GetBufferWidth(), (float)window->GetBufferHeight()); +// ImGui::SetNextWindowSize(MathUtil::ScaleVec2(windowNextSz)); +// ImGui::SetWindowPos(ImVec2(0, 0)); +// +// if (m_background) { +// m_background->Draw(); +// } +// +// auto flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBringToFrontOnFocus; +// +// int nextScene = -1; +// if (ImGui::Begin("###BEGIN", nullptr, flags)) { +// if (ImGui::BeginMenuBar()) { +// std::string title = std::string(O2GAME_TITLE) + " " + std::string(O2GAME_VERSION); +// ImGui::Text("%s", title.c_str()); +// +// std::string text = "No Account!"; +// auto textWidth = ImGui::CalcTextSize(text.c_str()).x; +// +// ImGui::SameLine(MathUtil::ScaleVec2(ImVec2(windowNextSz.x, 0)).x - textWidth - 15); +// ImGui::Text(text.c_str()); +// +// ImGui::EndMenuBar(); +// } +// +// { +// ImFont *font = FontResources::GetButtonFont(); +// ImGui::PushFont(font); +// ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); +// auto ButtonColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); +// ButtonColor.w = 0.25f; +// ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ButtonColor); +// ButtonColor.w = 0.15f; +// ImGui::PushStyleColor(ImGuiCol_ButtonActive, ButtonColor); +// ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); +// +// auto ButtonSize = MathUtil::ScaleVec2(window->GetBufferWidth(), 40); +// +// for (int i = 0; i < 5; i++) { +// ImGui::NewLine(); +// } +// +// ImGui::Spacing(); +// if (ImGui::Button("Single player", ButtonSize)) { +// nextScene = 0; +// } +// +// if (ImGui::Button("Play", ButtonSize)) { +// nextScene = 0; +// } +// +// ImGui::Spacing(); +// if (ImGui::Button("Multi player", ButtonSize)) { +// MsgBox::Show("Multiplayer", "Error", "Multiplayer is not implemented yet!"); +// } +// +// ImGui::NewLine(); +// ImGui::Spacing(); +// if (ImGui::Button("Editor", ButtonSize)) { +// nextScene = 2; +// } +// +// ImGui::NewLine(); +// ImGui::Spacing(); +// if (ImGui::Button("Options", ButtonSize)) { +// nextScene = 3; +// } +// +// ImGui::Spacing(); +// if (ImGui::Button("Quit", ButtonSize)) { +// nextScene = 4; +// } +// +// ImGui::PopStyleVar(); +// ImGui::PopStyleColor(3); +// ImGui::PopFont(); +// } +// +// ImGui::End(); +// } +// +// if (nextScene != -1) { +// switch (nextScene) { +// case 0: +// { +// SceneManager::DisplayFade(100, [this]() { +// SceneManager::ChangeScene(GameScene::SONGSELECT); +// }); +// break; +// } +// +// case 1: +// { +// break; +// } +// +// case 2: +// { +// SceneManager::DisplayFade(100, [this]() { +// SceneManager::ChangeScene(GameScene::EDITOR); +// }); +// break; +// } +// +// case 3: +// { +// SceneManager::OverlayShow(GameOverlay::SETTINGS); +// break; +// } +// +// case 4: +// { +// SDL_Event e = {}; +// e.type = SDL_QUIT; +// +// SDL_PushEvent(&e); +// break; +// } +// } +// } +//} + void MainMenu::Render(double delta) { - ImguiUtil::NewFrame(); - - auto window = GameWindow::GetInstance(); - ImGui::SetNextWindowPos(ImVec2(0, 0)); - - auto windowNextSz = ImVec2((float)window->GetBufferWidth(), (float)window->GetBufferHeight()); - ImGui::SetNextWindowSize(MathUtil::ScaleVec2(windowNextSz)); - ImGui::SetWindowPos(ImVec2(0, 0)); - - if (m_background) { - m_background->Draw(); - } - - auto flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBringToFrontOnFocus; - - int nextScene = -1; - if (ImGui::Begin("###BEGIN", nullptr, flags)) { - if (ImGui::BeginMenuBar()) { - std::string title = std::string(O2GAME_TITLE) + " " + std::string(O2GAME_VERSION); - ImGui::Text("%s", title.c_str()); - - std::string text = "No Account!"; - auto textWidth = ImGui::CalcTextSize(text.c_str()).x; - - ImGui::SameLine(MathUtil::ScaleVec2(ImVec2(windowNextSz.x, 0)).x - textWidth - 15); - ImGui::Text(text.c_str()); - - ImGui::EndMenuBar(); - } - - { - ImFont *font = FontResources::GetButtonFont(); - ImGui::PushFont(font); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); - auto ButtonColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); - ButtonColor.w = 0.25f; - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ButtonColor); - ButtonColor.w = 0.15f; - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ButtonColor); - ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); - - auto ButtonSize = MathUtil::ScaleVec2(window->GetBufferWidth(), 40); - - for (int i = 0; i < 5; i++) { - ImGui::NewLine(); - } - - ImGui::Spacing(); - if (ImGui::Button("Single player", ButtonSize)) { - nextScene = 0; - } - - ImGui::Spacing(); - if (ImGui::Button("Multi player", ButtonSize)) { - MsgBox::Show("Multiplayer", "Error", "Multiplayer is not implemented yet!"); - } - - ImGui::NewLine(); - ImGui::Spacing(); - if (ImGui::Button("Editor", ButtonSize)) { - nextScene = 2; - } - - ImGui::NewLine(); - ImGui::Spacing(); - if (ImGui::Button("Options", ButtonSize)) { - nextScene = 3; - } - - ImGui::Spacing(); - if (ImGui::Button("Quit", ButtonSize)) { - nextScene = 4; - } - - ImGui::PopStyleVar(); - ImGui::PopStyleColor(3); - ImGui::PopFont(); - } - - ImGui::End(); - } - - if (nextScene != -1) { - switch (nextScene) { - case 0: - { - SceneManager::DisplayFade(100, [this]() { - SceneManager::ChangeScene(GameScene::SONGSELECT); - }); - break; - } - - case 1: - { - break; - } - - case 2: - { - SceneManager::DisplayFade(100, [this]() { - SceneManager::ChangeScene(GameScene::EDITOR); - }); - break; - } - - case 3: - { - SceneManager::OverlayShow(GameOverlay::SETTINGS); - break; - } - - case 4: - { - SDL_Event e = {}; - e.type = SDL_QUIT; - - SDL_PushEvent(&e); - break; - } - } - } + SceneManager::ChangeScene(GameScene::SONGSELECT); } bool MainMenu::Attach() @@ -170,7 +179,7 @@ bool MainMenu::Attach() } if (bgm && !bgm->IsPlaying()) { - bgm->SetVolume(50); + bgm->SetVolume(100); bgm->Play(0, true); } } diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index 81d74ad6..cc501e8f 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -453,7 +453,7 @@ void SettingsOverlay::LoadConfiguration() auto fps = m_fps[currentFPSIndex]; if (fps == *(m_fps.end() - 1)) { - fps = "-1"; // Unlimited + fps = "-1";// Unlimited } SceneManager::GetInstance()->SetFrameLimit(std::atof(fps.c_str())); diff --git a/Game/src/Scenes/ResultScene.cpp b/Game/src/Scenes/ResultScene.cpp index f9895233..83146054 100644 --- a/Game/src/Scenes/ResultScene.cpp +++ b/Game/src/Scenes/ResultScene.cpp @@ -154,25 +154,35 @@ bool ResultScene::Attach() SceneManager::DisplayFade(0, [] {}); m_backButton = m_retryButton = false; - Audio *audio = AudioManager::GetInstance()->Get("FINISH"); - if (!audio) { - auto BGMPath = SkinManager::GetInstance()->GetPath() / "Audio"; - BGMPath /= "FINISH.ogg"; + Audio* previousAudio = AudioManager::GetInstance()->Get("FINISH"); + if (previousAudio) { + previousAudio->Stop(); + AudioManager::GetInstance()->Remove("FINISH"); + } - if (std::filesystem::exists(BGMPath)) { - AudioManager::GetInstance()->Create("FINISH", BGMPath, &audio); - } + Audio* audio = nullptr; + auto BGMPath = SkinManager::GetInstance()->GetPath() / "Audio"; + + bool failed = EnvironmentSetup::GetInt("Failed") == 1; + if (failed && std::filesystem::exists(BGMPath / "FAILED.ogg")) { + BGMPath /= "FAILED.ogg"; + } + else { + BGMPath /= "FINISH.ogg"; } - if (audio) { - audio->SetVolume(100); - audio->Play(); + if (std::filesystem::exists(BGMPath)) { + AudioManager::GetInstance()->Create("FINISH", BGMPath, &audio); + if (audio) { + audio->SetVolume(100); + audio->Play(); + } } - Chart *chart = (Chart *)EnvironmentSetup::GetObj("SONG"); + Chart* chart = (Chart*)EnvironmentSetup::GetObj("SONG"); EnvironmentSetup::SetObj("SONG", nullptr); - m_background = (Texture2D *)EnvironmentSetup::GetObj("SongBackground"); + m_background = (Texture2D*)EnvironmentSetup::GetObj("SongBackground"); delete chart; @@ -181,15 +191,19 @@ bool ResultScene::Attach() bool ResultScene::Detach() { - Audio *audio = AudioManager::GetInstance()->Get("FINISH"); + Audio* audio = AudioManager::GetInstance()->Get("FINISH"); if (audio) { audio->Stop(); + AudioManager::GetInstance()->Remove("FINISH"); } if (!m_retryButton) { EnvironmentSetup::SetObj("SongBackground", nullptr); } + EnvironmentSetup::SetInt("Failed", 0); + EnvironmentSetup::SetInt("FillStart", 0); + m_background = nullptr; return true; -} +} \ No newline at end of file diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index be3703a1..68e8776a 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -28,7 +28,26 @@ #include "../Data/Chart.hpp" #include "../Data/Util/Util.hpp" -static std::array Mods = { "Mirror", "Random", "Panic (FixMe)", "Rearrange", "Autoplay", "Hidden", "Flashlight", "Sudden", "Song BG", "Black BG" }; +static std::wstring OpenFilePrompt() { + OPENFILENAMEW ofn; + wchar_t szFile[MAX_PATH] = { 0 }; + + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = NULL; + ofn.lpstrFilter = L"All Supported Files (*.ojn;*.osu;*.bms;*.bme;*.bml;*)\0*.ojn;*.osu;*.bms;*.bme;*.bml\0"; + ofn.lpstrFile = szFile; + ofn.nMaxFile = MAX_PATH; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + if (GetOpenFileNameW(&ofn)) { + return szFile; + } + else { + return L""; + } +} + +static std::array Mods = { "Mirror", "Random", "Panic", "Rearrange", "Autoplay", "Hidden", "Flashlight", "Sudden", "Song BG", "Black BG"}; static std::array Arena = { "Random", "Arena 1", "Arena 2", "Arena 3", "Arena 4", "Arena 5", "Arena 6", "Arena 7", "Arena 8", "Arena 9", "Arena 10", "Arena 11", "Arena 12" }; @@ -61,12 +80,13 @@ void SongSelectScene::Render(double delta) auto window = GameWindow::GetInstance(); bPlay = false; - bExitPopup = false; + bOpenFile = false; bOptionPopup = false; bSelectNewSong = false; bOpenSongContext = false; bOpenEditor = false; bOpenRearrange = false; + bQuit = false; bScaleOutput = window->IsScaleOutput(); auto windowNextSz = ImVec2((float)window->GetBufferWidth(), (float)window->GetBufferHeight()); @@ -90,19 +110,25 @@ void SongSelectScene::Render(double delta) nullptr, flags)) { if (ImGui::BeginMenuBar()) { - if (ImGui::Button("Back", MathUtil::ScaleVec2(ImVec2(50, 0)))) { - bExitPopup = true; + + if (ImGui::Button("Quit", MathUtil::ScaleVec2(ImVec2(50, 0)))) { + bQuit = true; } + /*if (ImGui::Button("Open File", MathUtil::ScaleVec2(ImVec2(50, 0)))) { + bOpenFile = true; + }*/ // FIXME: Plz Fix This + if (ImGui::Button("Options", MathUtil::ScaleVec2(ImVec2(50, 0)))) { bOptionPopup = true; } ImGuiIO &io = ImGui::GetIO(); - ImGui::Text("Song Selection...."); + ImGui::Text("Select Song"); - std::string text = "No Account!"; + /*std::string text = "No Account!";*/ + std::string text = "O2Jam Simulator, Base game by Estrol, Effect by Albet"; auto textWidth = ImGui::CalcTextSize(text.c_str()).x; ImGui::SameLine(MathUtil::ScaleVec2(ImVec2(windowNextSz.x, 0)).x - textWidth - 15); @@ -325,11 +351,31 @@ void SongSelectScene::Render(double delta) }); } - if (bExitPopup) { - SaveConfiguration(); - SceneManager::DisplayFade(100, [this]() { - SceneManager::ChangeScene(GameScene::MAINMENU); - }); + if (bOpenFile) { + std::wstring songfile = OpenFilePrompt(); + if (!songfile.empty()) { + EnvironmentSetup::SetPath("FILE", songfile); + is_departing = true; + SaveConfiguration(); + + if (m_songBackground) { + EnvironmentSetup::SetObj("SongBackground", m_songBackground.get()); + } + + nextAlpha = 0; + SceneManager::ExecuteAfter(600, [this]() { + SceneManager::ChangeScene(GameScene::LOADING); + }); + } + else { + MsgBox::Show("MustSelectFile", "Error", "You must select a file!", MsgBoxType::OK); + } + } + + if (bQuit) { + SDL_Event e = {}; + e.type = SDL_QUIT; + SDL_PushEvent(&e); } } @@ -431,7 +477,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) } if (ImGui::BeginChild("#test2", MathUtil::ScaleVec2(ImVec2(200, 290)), true)) { - std::vector difficulty = { "EZ", "NM", "HD" }; + std::vector difficulty = { "EZ", "NM", "HD" }; ImGui::Text("Note difficulty"); for (int i = 0; i < difficulty.size(); i++) { @@ -443,7 +489,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) } if (ImGui::Button(difficulty[i].c_str(), MathUtil::ScaleVec2(ImVec2(30, 30)))) { - EnvironmentSetup::SetInt("Difficulty", i); // 0 EZ, 1 NM, 2 HD + EnvironmentSetup::SetInt("Difficulty", i); // 0 EZ, 1 NM, 2 HD } if (index == i) { @@ -659,7 +705,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) if (ImGui::BeginChild("###CHILD", ImVec2(0, 0), false, 0)) { ImGui::PushItemWidth(ImGui::GetWindowSize().x); ImGui::Text("Search:"); - ImGui::InputTextEx("###Search", "Search by Title, Artist, Noter or Id....", search, sizeof(search), ImVec2(0, 0), ImGuiInputTextFlags_AutoSelectAll); + ImGui::InputTextEx("###Search", "Search by Title, Artist, Notecharter or ID...", search, sizeof(search), ImVec2(0, 0), ImGuiInputTextFlags_AutoSelectAll); // if press Enter if (ImGui::IsKeyPressed(ImGuiKey_Enter)) { @@ -801,7 +847,7 @@ bool SongSelectScene::Attach() } if (bgm && !bgm->IsPlaying()) { - bgm->SetVolume(50); + bgm->SetVolume(100); bgm->Play(0, true); } } diff --git a/Game/src/Scenes/SongSelectScene.h b/Game/src/Scenes/SongSelectScene.h index 9a798f00..e3c95560 100644 --- a/Game/src/Scenes/SongSelectScene.h +++ b/Game/src/Scenes/SongSelectScene.h @@ -54,13 +54,14 @@ class SongSelectScene : public Scene bool imgui_modal_quit_confirm = false; bool bPlay = false; - bool bExitPopup = false; + bool bOpenFile = false; bool bOptionPopup = false; bool bSelectNewSong = false; bool bOpenSongContext = false; bool bOpenEditor = false; bool bOpenRearrange = false; bool bScaleOutput = true; + bool bQuit = false; char lanePos[8] = {}; diff --git a/Game/src/Version.h b/Game/src/Version.h index a7253686..395ce7bb 100644 --- a/Game/src/Version.h +++ b/Game/src/Version.h @@ -1,9 +1,9 @@ #pragma once -#define O2GAME_TITLE "Unnamed O2 Clone" +#define O2GAME_TITLE "O2Clone" #if _DEBUG #define O2GAME_VERSION "Debug" #else -#define O2GAME_VERSION "0.1.9" +#define O2GAME_VERSION "(O2Jam Simulator)" #endif \ No newline at end of file diff --git a/GameResources b/GameResources deleted file mode 160000 index 30425e6f..00000000 --- a/GameResources +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 30425e6f57b1cc0ee0464a5d992db9f18bdd76f0 From 28ad7aed21f7af22de55a336e0fc06cf90284551 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sat, 13 Apr 2024 14:09:46 +0700 Subject: [PATCH 04/83] fix: note has render glitching and inconsistent frame index --- Game/src/Engine/DrawableNote.cpp | 3 +- Game/src/Engine/Note.cpp | 265 +++++++++++++++++++----------- Game/src/Engine/RhythmEngine.cpp | 20 ++- Game/src/Scenes/GameplayScene.cpp | 3 +- 4 files changed, 188 insertions(+), 103 deletions(-) diff --git a/Game/src/Engine/DrawableNote.cpp b/Game/src/Engine/DrawableNote.cpp index b1ca5554..84562e1b 100644 --- a/Game/src/Engine/DrawableNote.cpp +++ b/Game/src/Engine/DrawableNote.cpp @@ -5,6 +5,7 @@ DrawableNote::DrawableNote(NoteImage* frame) : FrameTimer::FrameTimer() { + SetFPS(0.0); // HACK: Stop note glitching by force it to 0 FPS (idk why it still initialized by itself if i remove SETFPS) m_frames.reserve(frame->Texture.size()); // Reserve memory for frames vector if (Renderer::GetInstance()->IsVulkan()) { @@ -21,6 +22,4 @@ DrawableNote::DrawableNote(NoteImage* frame) : FrameTimer::FrameTimer() } AnchorPoint = { 0.0, 1.0 }; - - SetFPS(60.0); // slighly fix stupid glitch } diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index ad900947..f5382c59 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -213,119 +213,75 @@ void Note::Update(double delta) void Note::Render(double delta) { - if (IsRemoveable()) - return; - if (!m_drawAble) + if (IsRemoveable() || !m_drawAble) return; - auto resolution = m_engine->GetResolution(); - auto hitPos = m_engine->GetHitPosition(); + auto resolution = m_engine->GetResolution(); + auto hitPos = m_engine->GetHitPosition(); double trackPosition = m_engine->GetTrackPosition(); - int min = -100, max = hitPos + 25; + int min = -100, max = hitPos + 25; auto playRect = m_engine->GetPlayRectangle(); int guideLineIndex = m_engine->GetGuideLineIndex(); - int guideLineLength = 24 * length_multiplier[guideLineIndex]; + double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; + double headPosY = lerp(0.0, static_cast(hitPos), static_cast(y1)); + bool isHeadVisible = isWithinRange(headPosY, min, max); + if (m_type == NoteType::HOLD) { - double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; + double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); + bool isTailVisible = isWithinRange(tailPosY, min, max); - m_head->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y1)); - m_tail->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y2)); - - float Transparency = 0.9f; + double bodyPosY = (headPosY + tailPosY) / 2.0; + double bodyHeight = std::abs(headPosY - tailPosY); + m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY); + m_body->Size = { 1, 0, 0, bodyHeight }; + float transparency = 0.9f; if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { - // m_head->Position.Y.Offset = hitPos; - Transparency = 1.0f; - } - - m_head->CalculateSize(); - m_tail->CalculateSize(); - - double headPos = m_head->AbsolutePosition.Y + (m_head->AbsoluteSize.Y / 2.0); - double tailPos = m_tail->AbsolutePosition.Y + (m_tail->AbsoluteSize.Y / 2.0); - - double height = headPos - tailPos; - double position = (height / 2.0) + tailPos; - - m_body->Position = UDim2::fromOffset(m_laneOffset, position); - m_body->Size = { 1, 0, 0, height }; - - m_body->TintColor = { Transparency, Transparency, Transparency }; - - bool b1 = isWithinRange(m_head->Position.Y.Offset, min, max); - bool b2 = isWithinRange(m_tail->Position.Y.Offset, min, max); - - if (isCollision(m_tail->Position.Y.Offset, m_head->Position.Y.Offset, min, max)) { - m_body->SetIndexAt(m_engine->GetNoteImageIndex()); - m_body->Draw(delta, &playRect); + transparency = 1.0f; } + m_body->TintColor = { transparency, transparency, transparency }; + m_body->SetIndexAt(m_engine->GetNoteImageIndex()); + m_body->Draw(delta, &playRect); - if (b1) { - if (guideLineLength > 0) { - m_trail_down->Position = m_head->Position; - m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_down->AnchorPoint = { 0, 0 }; - m_trail_down->Draw(delta, &playRect); - - m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); - m_trail_down->AnchorPoint = { 1, 0 }; - m_trail_down->Draw(delta, &playRect); - } - - m_head->SetIndexAt(m_engine->GetNoteImageIndex()); - m_head->Draw(delta, &playRect); - } - - if (b2) { - if (guideLineLength > 0) { - m_trail_up->Position = m_tail->Position + UDim2::fromOffset(0, -m_tail->AbsoluteSize.Y); - m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_up->AnchorPoint = { 0, 1 }; - m_trail_up->Draw(delta, &playRect); - - m_trail_up->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, -m_tail->AbsoluteSize.Y); - m_trail_up->AnchorPoint = { 1, 1 }; - m_trail_up->Draw(delta, &playRect); - } - + if (isTailVisible) { + m_tail->Position = UDim2::fromOffset(m_laneOffset, tailPosY); m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); m_tail->Draw(delta, &playRect); } - } else { - double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; - m_head->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y1)); - m_head->CalculateSize(); - - bool b1 = isWithinRange(m_head->Position.Y.Offset, min, max); - - if (b1) { - if (guideLineLength > 0) { - m_trail_down->Position = m_head->Position; - m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_down->AnchorPoint = { 0, 0 }; - m_trail_down->Draw(delta, &playRect); - - m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); - m_trail_down->AnchorPoint = { 1, 0 }; - m_trail_down->Draw(delta, &playRect); - - m_trail_up->Position = m_head->Position + UDim2::fromOffset(0, -m_head->AbsoluteSize.Y); - m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_up->AnchorPoint = { 0, 1 }; - m_trail_up->Draw(delta, &playRect); - - m_trail_up->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, -m_head->AbsoluteSize.Y); - m_trail_up->AnchorPoint = { 1, 1 }; - m_trail_up->Draw(delta, &playRect); - } + } - m_head->SetIndexAt(m_engine->GetNoteImageIndex()); - m_head->Draw(delta, &playRect); + if (isHeadVisible) { + m_head->Position = UDim2::fromOffset(m_laneOffset, headPosY); + m_head->SetIndexAt(m_engine->GetNoteImageIndex()); + m_head->Draw(delta, &playRect); + + if (guideLineLength > 0) { + m_trail_down->Position = m_head->Position; + m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_down->AnchorPoint = { 0, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); + m_trail_down->AnchorPoint = { 1, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_up->Position = m_head->Position + UDim2::fromOffset(0, -m_head->AbsoluteSize.Y); + m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_up->AnchorPoint = { 0, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + + m_trail_up->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, -m_head->AbsoluteSize.Y); + m_trail_up->AnchorPoint = { 1, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); } } } @@ -583,4 +539,125 @@ void Note::Release() cacheManager->Repool(m_head, m_imageType); m_head = nullptr; } -} \ No newline at end of file +} + +// Old code +//void Note::Render(double delta) +//{ +// if (IsRemoveable()) +// return; +// if (!m_drawAble) +// return; +// +// auto resolution = m_engine->GetResolution(); +// auto hitPos = m_engine->GetHitPosition(); +// double trackPosition = m_engine->GetTrackPosition(); +// +// int min = -100, max = hitPos + 25; +// auto playRect = m_engine->GetPlayRectangle(); +// +// int guideLineIndex = m_engine->GetGuideLineIndex(); +// +// int guideLineLength = 24 * length_multiplier[guideLineIndex]; +// +// if (m_type == NoteType::HOLD) { +// double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; +// double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; +// +// m_head->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y1)); +// m_tail->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y2)); +// +// float Transparency = 0.9f; +// +// if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { +// // m_head->Position.Y.Offset = hitPos; +// Transparency = 1.0f; +// } +// +// m_head->CalculateSize(); +// m_tail->CalculateSize(); +// +// double headPos = m_head->AbsolutePosition.Y + (m_head->AbsoluteSize.Y / 2.0); +// double tailPos = m_tail->AbsolutePosition.Y + (m_tail->AbsoluteSize.Y / 2.0); +// +// double height = headPos - tailPos; +// double position = (height / 2.0) + tailPos; +// +// m_body->Position = UDim2::fromOffset(m_laneOffset, position); +// m_body->Size = { 1, 0, 0, height }; +// +// m_body->TintColor = { Transparency, Transparency, Transparency }; +// +// bool b1 = isWithinRange(m_head->Position.Y.Offset, min, max); +// bool b2 = isWithinRange(m_tail->Position.Y.Offset, min, max); +// +// if (isCollision(m_tail->Position.Y.Offset, m_head->Position.Y.Offset, min, max)) { +// m_body->SetIndexAt(m_engine->GetNoteImageIndex()); +// m_body->Draw(delta, &playRect); +// } +// +// if (b1) { +// if (guideLineLength > 0) { +// m_trail_down->Position = m_head->Position; +// m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); +// m_trail_down->AnchorPoint = { 0, 0 }; +// m_trail_down->Draw(delta, &playRect); +// +// m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); +// m_trail_down->AnchorPoint = { 1, 0 }; +// m_trail_down->Draw(delta, &playRect); +// } +// +// m_head->SetIndexAt(m_engine->GetNoteImageIndex()); +// m_head->Draw(delta, &playRect); +// } +// +// if (b2) { +// if (guideLineLength > 0) { +// m_trail_up->Position = m_tail->Position + UDim2::fromOffset(0, -m_tail->AbsoluteSize.Y); +// m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); +// m_trail_up->AnchorPoint = { 0, 1 }; +// m_trail_up->Draw(delta, &playRect); +// +// m_trail_up->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, -m_tail->AbsoluteSize.Y); +// m_trail_up->AnchorPoint = { 1, 1 }; +// m_trail_up->Draw(delta, &playRect); +// } +// +// m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); +// m_tail->Draw(delta, &playRect); +// } +// } +// else { +// double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; +// m_head->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y1)); +// m_head->CalculateSize(); +// +// bool b1 = isWithinRange(m_head->Position.Y.Offset, min, max); +// +// if (b1) { +// if (guideLineLength > 0) { +// m_trail_down->Position = m_head->Position; +// m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); +// m_trail_down->AnchorPoint = { 0, 0 }; +// m_trail_down->Draw(delta, &playRect); +// +// m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); +// m_trail_down->AnchorPoint = { 1, 0 }; +// m_trail_down->Draw(delta, &playRect); +// +// m_trail_up->Position = m_head->Position + UDim2::fromOffset(0, -m_head->AbsoluteSize.Y); +// m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); +// m_trail_up->AnchorPoint = { 0, 1 }; +// m_trail_up->Draw(delta, &playRect); +// +// m_trail_up->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, -m_head->AbsoluteSize.Y); +// m_trail_up->AnchorPoint = { 1, 1 }; +// m_trail_up->Draw(delta, &playRect); +// } +// +// m_head->SetIndexAt(m_engine->GetNoteImageIndex()); +// m_head->Draw(delta, &playRect); +// } +// } +//} \ No newline at end of file diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 878e7da7..778baa62 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -17,9 +17,6 @@ #include "Judgements/BeatBasedJudge.h" #include "Judgements/MsBasedJudge.h" -//#include -//#include - #define MAX_BUFFER_TXT_SIZE 256 struct ManiaKeyState @@ -354,13 +351,24 @@ void RhythmEngine::Update(double delta) // assert(false); // TODO: Handle this } - if (m_currentAudioPosition > m_audioLength + 2000) { // Avoid game ended too early - m_state = GameState::PosGame; + if (m_currentAudioPosition > m_audioLength + 3000) { // Avoid game ended too early GameAudioSampleCache::StopAll(); + m_state = GameState::PosGame; } - if (static_cast(m_currentAudioPosition) % 1000 == 0) { + //if (static_cast(m_currentAudioPosition) % 1000 == 0) { // THIS CAUSING ISSUES NOTE FPS DOES NOT CORRECTLY APPLIED + // m_noteImageIndex = (m_noteImageIndex + 1) % m_noteMaxImageIndex; + //} + + // HACK: I had to use std chrono on this, otherwise it will not accurate and has weird inconsistent frame index + static std::chrono::steady_clock::time_point lastUpdateTime = std::chrono::steady_clock::now(); + auto currentTime = std::chrono::steady_clock::now(); + auto lastUpdate = std::chrono::duration_cast(currentTime - lastUpdateTime); + + // Check if it's time to update the note image index + if (lastUpdate.count() >= 100) { m_noteImageIndex = (m_noteImageIndex + 1) % m_noteMaxImageIndex; + lastUpdateTime = currentTime; } UpdateVirtualResolution(); diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 3a3b4604..47acab7a 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -48,6 +48,8 @@ GameplayScene::GameplayScene() : Scene::Scene() m_keyState = {}; m_game = nullptr; m_drawJam = false; + m_counter = 0.0; + lifeFillDuration = 0.0; } void GameplayScene::Update(double delta) @@ -314,7 +316,6 @@ void GameplayScene::Render(double delta) } } - float gaugeVal = (float)m_game->GetScoreManager()->GetJamGauge() / kMaxJamGauge; if (gaugeVal > 0) { m_jamGauge->CalculateSize(); From 96f0a3e977de8f023cdc88a7b259cc5be0dff4e9 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sat, 13 Apr 2024 15:06:16 +0700 Subject: [PATCH 05/83] --- Engine/src/Texture/Texture2D.cpp | 41 ++++++++++++++------------------ 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 27749418..aab5eb7c 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -405,32 +405,27 @@ Texture2D *Texture2D::FromPNG(std::string fileName) void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) { - try { - if (Renderer::GetInstance()->IsVulkan()) { - auto tex_data = vkTexture::TexLoadImage(buffer, size); - m_actualSize = { 0, 0, tex_data->Width, tex_data->Height }; - m_vk_tex = tex_data; - m_bDisposeTexture = true; - m_ready = true; - } else { - SDL_RWops* rw = SDL_RWFromMem(buffer, static_cast(size)); - m_sdl_surface = (buffer[0] == 0x42 && buffer[1] == 0x4D) ? - SDL_LoadBMP_RW(rw, 1) : IMG_Load_RW(rw, 1); + if (Renderer::GetInstance()->IsVulkan()) { + auto tex_data = vkTexture::TexLoadImage(buffer, size); + m_actualSize = { 0, 0, tex_data->Width, tex_data->Height }; + m_vk_tex = tex_data; + m_bDisposeTexture = true; + m_ready = true; + } else { + SDL_RWops* rw = SDL_RWFromMem(buffer, static_cast(size)); + m_sdl_surface = (buffer[0] == 0x42 && buffer[1] == 0x4D) ? + SDL_LoadBMP_RW(rw, 1) : IMG_Load_RW(rw, 1); - if (!m_sdl_surface) throw SDLException(); + if (!m_sdl_surface) throw SDLException(); - m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), m_sdl_surface); - if (!m_sdl_tex) throw SDLException(); + m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), m_sdl_surface); + if (!m_sdl_tex) throw SDLException(); - int w, h; - SDL_QueryTexture(m_sdl_tex, nullptr, nullptr, &w, &h); - m_bDisposeTexture = true; - m_actualSize = { 0, 0, w, h }; - m_ready = true; - } - } catch (...) { - delete[] buffer; - throw; + int w, h; + SDL_QueryTexture(m_sdl_tex, nullptr, nullptr, &w, &h); + m_bDisposeTexture = true; + m_actualSize = { 0, 0, w, h }; + m_ready = true; } delete[] buffer; } From 3f75ebf4927a8b1deac087fa20eb2dedc7666f0f Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sat, 13 Apr 2024 17:13:49 +0700 Subject: [PATCH 06/83] fix --- Engine/include/Texture/Texture2D.h | 6 +- Engine/src/Texture/Texture2D.cpp | 88 ++++++++++++------------------ 2 files changed, 39 insertions(+), 55 deletions(-) diff --git a/Engine/include/Texture/Texture2D.h b/Engine/include/Texture/Texture2D.h index 7fd24b05..72a4d7fa 100644 --- a/Engine/include/Texture/Texture2D.h +++ b/Engine/include/Texture/Texture2D.h @@ -20,9 +20,9 @@ class Texture2D public: Texture2D(); - Texture2D(std::string fileName); - Texture2D(std::filesystem::path path); - Texture2D(uint8_t *fileData, size_t size); + Texture2D(const std::string& fileName); + Texture2D(const std::filesystem::path& path); + Texture2D(const uint8_t *fileData, size_t size); Texture2D(SDL_Texture *texture); Texture2D(Texture2D_Vulkan *texture); ~Texture2D(); diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index aab5eb7c..369ade58 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -35,75 +35,54 @@ Texture2D::Texture2D() Size = UDim2::fromScale(1, 1); } +Texture2D::Texture2D(const std::string& fileName) : Texture2D() { + std::string filePath = fileName; + if (!std::filesystem::exists(filePath)) { + filePath = std::filesystem::current_path().string() + fileName; + } -Texture2D::Texture2D(std::string fileName) : Texture2D() -{ - std::filesystem::path filePath(fileName); if (!std::filesystem::exists(filePath)) { - throw std::runtime_error(filePath.string() + " not found!"); + throw std::runtime_error(fileName + " not found!"); } std::ifstream file(filePath, std::ios::binary | std::ios::ate); if (!file.is_open()) { - throw std::runtime_error(filePath.string() + " cannot be opened!"); + throw std::runtime_error(fileName + " cannot be opened!"); } - std::streamsize size = file.tellg(); + size_t size = file.tellg(); file.seekg(0, std::ios::beg); - std::vector buffer(size); - if (!file.read(reinterpret_cast(buffer.data()), size)) { - throw std::runtime_error("Failed to read file: " + filePath.string()); - } + uint8_t* buffer = new uint8_t[size]; + file.read(reinterpret_cast(buffer), size); + file.close(); - LoadImageResources(buffer.data(), buffer.size()); + LoadImageResources(buffer, size); } -Texture2D::Texture2D(std::filesystem::path path) : Texture2D() -{ +Texture2D::Texture2D(const std::filesystem::path& path) : Texture2D() { if (!std::filesystem::exists(path)) { throw std::runtime_error(path.string() + " not found!"); } - std::fstream fs(path, std::ios::binary | std::ios::in); - if (!fs.is_open()) { - throw std::runtime_error(path.string() + " cannot opened!"); + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + throw std::runtime_error(path.string() + " cannot be opened!"); } - fs.seekg(0, std::ios::end); - size_t size = fs.tellg(); - fs.seekg(0, std::ios::beg); + size_t size = file.tellg(); + file.seekg(0, std::ios::beg); - uint8_t *buffer = new uint8_t[size]; - fs.read((char *)buffer, size); - fs.close(); - - Rotation = 0; - Transparency = 0.0f; - m_actualSize = { 0, 0, 0, 0 }; - m_bDisposeTexture = true; - TintColor = { 1.0f, 1.0f, 1.0f }; + uint8_t* buffer = new uint8_t[size]; + file.read(reinterpret_cast(buffer), size); + file.close(); LoadImageResources(buffer, size); } -// Do base constructor called before derived constructor? -// https://stackoverflow.com/questions/120547/what-are-the-rules-for-calling-the-superclass-constructor - -Texture2D::Texture2D(uint8_t *fileData, size_t size) : Texture2D() -{ - uint8_t *buffer = new uint8_t[size]; - memcpy(buffer, fileData, size); - - Rotation = 0; - Transparency = 0.0f; - m_actualSize = { 0, 0, 0, 0 }; - m_bDisposeTexture = true; - TintColor = { 1.0f, 1.0f, 1.0f }; - - m_sdl_tex = nullptr; - m_vk_tex = nullptr; - +Texture2D::Texture2D(const uint8_t* fileData, size_t size) : Texture2D() { + uint8_t* buffer = new uint8_t[size]; + std::memcpy(buffer, fileData, size); LoadImageResources(buffer, size); } @@ -411,21 +390,26 @@ void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) m_vk_tex = tex_data; m_bDisposeTexture = true; m_ready = true; - } else { + } + else { + // Load compressed image data for SDL using ASTC compression + SDL_Surface* decompressed_surface = nullptr; SDL_RWops* rw = SDL_RWFromMem(buffer, static_cast(size)); - m_sdl_surface = (buffer[0] == 0x42 && buffer[1] == 0x4D) ? - SDL_LoadBMP_RW(rw, 1) : IMG_Load_RW(rw, 1); + decompressed_surface = IMG_LoadTyped_RW(rw, 1, "ASTC"); - if (!m_sdl_surface) throw SDLException(); + if (!decompressed_surface) throw SDLException(); - m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), m_sdl_surface); - if (!m_sdl_tex) throw SDLException(); + m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), decompressed_surface); int w, h; SDL_QueryTexture(m_sdl_tex, nullptr, nullptr, &w, &h); - m_bDisposeTexture = true; + m_actualSize = { 0, 0, w, h }; + + m_bDisposeTexture = true; m_ready = true; + + SDL_FreeSurface(decompressed_surface); } delete[] buffer; } From 0f10ed23540604d2b6c041679bd4eaeef47eb1e5 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sun, 14 Apr 2024 02:23:39 +0700 Subject: [PATCH 07/83] feat: move background option to settings --- Engine/include/Game.h | 2 +- Engine/src/Game.cpp | 9 ++-- Game/src/EnvironmentSetup.cpp | 2 +- Game/src/Scenes/GameplayScene.cpp | 4 +- Game/src/Scenes/Overlays/Settings.cpp | 70 +++++++++++++++++++++++++-- Game/src/Scenes/Overlays/Settings.h | 1 + Game/src/Scenes/SongSelectScene.cpp | 56 ++++++--------------- 7 files changed, 89 insertions(+), 55 deletions(-) diff --git a/Engine/include/Game.h b/Engine/include/Game.h index 4e764017..d31eb36c 100644 --- a/Engine/include/Game.h +++ b/Engine/include/Game.h @@ -89,5 +89,5 @@ class Game GameThread mLocalThread; std::mutex m_mutex; - std::condition_variable m_conditionVariable; + std::condition_variable m_cv; }; diff --git a/Engine/src/Game.cpp b/Engine/src/Game.cpp index eff016fe..9587bcbf 100644 --- a/Engine/src/Game.cpp +++ b/Engine/src/Game.cpp @@ -83,7 +83,7 @@ Game::~Game() if (m_notify) { std::unique_lock lock(m_mutex); - m_conditionVariable.wait(lock, [this] { return !m_notify; }); + m_cv.wait(lock, [this] { return !m_notify; }); } } @@ -369,13 +369,12 @@ void Game::CheckFont() void Game::Stop() { if (m_running) { - m_running = false; - { - std::lock_guard lock(m_mutex); + std::unique_lock lock(m_mutex); + m_running = false; m_notify = true; } - m_conditionVariable.notify_one(); + m_cv.notify_one(); } } diff --git a/Game/src/EnvironmentSetup.cpp b/Game/src/EnvironmentSetup.cpp index 421ac62b..9be0e8af 100644 --- a/Game/src/EnvironmentSetup.cpp +++ b/Game/src/EnvironmentSetup.cpp @@ -3,7 +3,7 @@ namespace { std::unordered_map m_stores; - std::unordered_map m_storesPtr; + std::unordered_map m_storesPtr; std::unordered_map m_paths; std::unordered_map m_ints; } // namespace diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 47acab7a..14245b37 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -137,8 +137,8 @@ void GameplayScene::Render(double delta) int arena = EnvironmentSetup::GetInt("Arena"); - bool useSongBG = EnvironmentSetup::GetInt("Song BG") == 1; - bool blackBG = EnvironmentSetup::GetInt("Black BG") == 1; + bool useSongBG = EnvironmentSetup::GetInt("Song Background") == 1; + bool blackBG = EnvironmentSetup::GetInt("Black Background") == 1; if (useSongBG) { auto songBG = (Texture2D*)EnvironmentSetup::GetObj("SongBackground"); diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index cc501e8f..78d69f8e 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -45,6 +45,7 @@ static std::map Graphics = { static std::array LongNote = { "None", "Short", "Normal", "Long" }; static std::array m_fps = { "30", "60", "75", "120", "144", "165", "180", "240", "360", "480", "600", "800", "1000", "Unlimited" }; +static std::array SelectedBackground = { "Arena", "Song", "Black" }; static std::vector m_resolutions = {}; @@ -285,10 +286,10 @@ void SettingsOverlay::Render(double delta) ImGui::Text("Guide Line Length"); for (int i = (int)LongNote.size() - 1; i >= 0; i--) { - bool is_combo_selected = currentGuideLineIndex == i; + bool selected = currentGuideLineIndex == i; ImGui::PushItemWidth(50); - if (ImGui::Checkbox(("###ComboCheck" + std::to_string(i)).c_str(), &is_combo_selected)) { + if (ImGui::Checkbox(("###ComboCheck" + std::to_string(i)).c_str(), &selected)) { currentGuideLineIndex = i; } @@ -317,12 +318,53 @@ void SettingsOverlay::Render(double delta) ImGui::SetTooltip("When Long note on hold, make the head position at hit position else keep going to bottom"); } + ImGui::NewLine(); + + ImGui::Text("Background"); + for (int i = 0; i < SelectedBackground.size(); ++i) { + bool selected = (BackgroundIndex == i); + + std::string tooltipText; + if (i == 0) { + tooltipText = "Using arena image background inside Skin folder"; + } + else if (i == 1) { + tooltipText = "Using song image background inside O2Jam file / BMS folder / osu!mania beatmap folder"; + } + else if (i == 2) { + tooltipText = "Not using any background"; + } + + if (ImGui::Checkbox(SelectedBackground[i].c_str(), &selected)) { + BackgroundIndex = i; + } + + if (!tooltipText.empty() && ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", tooltipText.c_str()); + } + + ImGui::SameLine(); + } + + if (BackgroundIndex == 0) { + EnvironmentSetup::SetInt("Song Background", 0); + EnvironmentSetup::SetInt("Black Background", 0); + } + else if (BackgroundIndex == 1) { + EnvironmentSetup::SetInt("Song Background", 1); + EnvironmentSetup::SetInt("Black Background", 0); + } + else if (BackgroundIndex == 2) { + EnvironmentSetup::SetInt("Song Background", 0); + EnvironmentSetup::SetInt("Black Background", 1); + } + ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Skins")) { ImGui::Text("Current selected skin: "); - if (ImGui::BeginCombo("#SkinsComboBox", currentSkin.c_str())) { + if (ImGui::BeginCombo("##SkinsComboBox", currentSkin.c_str())) { for (int i = 0; i < skins.size(); i++) { bool isSelected = (currentSkin == skins[i]); @@ -451,9 +493,28 @@ void SettingsOverlay::LoadConfiguration() currentGuideLineIndex = 2; } + try { + BackgroundIndex = std::stoi(Configuration::Load("Game", "Background").c_str()); + } catch (const std::invalid_argument&) { + BackgroundIndex = 0; + } + + if (BackgroundIndex == 0) { // HACK: Solution for issue background not applied even configuration already loaded + EnvironmentSetup::SetInt("Song Background", 0); + EnvironmentSetup::SetInt("Black Background", 0); + } + else if (BackgroundIndex == 1) { + EnvironmentSetup::SetInt("Song Background", 1); + EnvironmentSetup::SetInt("Black Background", 0); + } + else if (BackgroundIndex == 2) { + EnvironmentSetup::SetInt("Song Background", 0); + EnvironmentSetup::SetInt("Black Background", 1); + } + auto fps = m_fps[currentFPSIndex]; if (fps == *(m_fps.end() - 1)) { - fps = "-1";// Unlimited + fps = "9999" ; } SceneManager::GetInstance()->SetFrameLimit(std::atof(fps.c_str())); @@ -468,6 +529,7 @@ void SettingsOverlay::SaveConfiguration() Configuration::Set("Game", "AutoSound", std::to_string(convertAutoSound ? 1 : 0)); Configuration::Set("Game", "FrameLimit", m_fps[currentFPSIndex]); Configuration::Set("Game", "GuideLine", std::to_string(currentGuideLineIndex)); + Configuration::Set("Game", "Background", std::to_string(BackgroundIndex)); auto frame = m_fps[currentFPSIndex]; if (frame == m_fps[13]) { diff --git a/Game/src/Scenes/Overlays/Settings.h b/Game/src/Scenes/Overlays/Settings.h index 16798421..a999f70b 100644 --- a/Game/src/Scenes/Overlays/Settings.h +++ b/Game/src/Scenes/Overlays/Settings.h @@ -26,6 +26,7 @@ class SettingsOverlay : public Overlay int currentGuideLineIndex = 0; bool LongNoteLighting = false; bool LongNoteOnHitPos = false; + int BackgroundIndex = 0; bool convertAutoSound = false; std::string currentSkin = ""; diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index 68e8776a..aaaa1a1e 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -47,7 +47,7 @@ static std::wstring OpenFilePrompt() { } } -static std::array Mods = { "Mirror", "Random", "Panic", "Rearrange", "Autoplay", "Hidden", "Flashlight", "Sudden", "Song BG", "Black BG"}; +static std::array Mods = { "Mirror", "Random", "Panic", "Rearrange", "Autoplay", "Hidden", "Flashlight", "Sudden"}; static std::array Arena = { "Random", "Arena 1", "Arena 2", "Arena 3", "Arena 4", "Arena 5", "Arena 6", "Arena 7", "Arena 8", "Arena 9", "Arena 10", "Arena 11", "Arena 12" }; @@ -119,7 +119,7 @@ void SongSelectScene::Render(double delta) bOpenFile = true; }*/ // FIXME: Plz Fix This - if (ImGui::Button("Options", MathUtil::ScaleVec2(ImVec2(50, 0)))) { + if (ImGui::Button("Settings", MathUtil::ScaleVec2(ImVec2(50, 0)))) { bOptionPopup = true; } @@ -434,6 +434,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) // create child window if (ImGui::BeginChild("#Container1", MathUtil::ScaleVec2(ImVec2(200, 500)))) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 3)); if (ImGui::BeginChild("#SongSelectChild2", MathUtil::ScaleVec2(ImVec2(200, 200)), true)) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); @@ -454,13 +455,13 @@ void SongSelectScene::OnGameSelectMusic(double delta) ImGui::Text("Title\r"); imgui_extends::TextBackground(color, MathUtil::ScaleVec2(340, 0), "%s", (const char *)item.Title); - ImGui::Text("Artist\r"); + ImGui::Text("Artist / Composer\r"); imgui_extends::TextBackground(color, MathUtil::ScaleVec2(340, 0), "%s", (const char *)item.Artist); ImGui::Text("Notecharter\r"); imgui_extends::TextBackground(color, MathUtil::ScaleVec2(340, 0), "%s", (const char *)item.Noter); - ImGui::Text("Note count\r"); + ImGui::Text("Total Notes\r"); int difficulty = EnvironmentSetup::GetInt("Difficulty"); int count = item.Id == -1 ? 0 : item.MaxNotes[difficulty]; @@ -477,6 +478,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) } if (ImGui::BeginChild("#test2", MathUtil::ScaleVec2(ImVec2(200, 290)), true)) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 2)); std::vector difficulty = { "EZ", "NM", "HD" }; ImGui::Text("Note difficulty"); @@ -519,16 +521,16 @@ void SongSelectScene::OnGameSelectMusic(double delta) ImGui::PopItemWidth(); + ImGui::Text("Modifier"); for (int i = 0; i < Mods.size(); i++) { - auto &mod = Mods[i]; + auto& mod = Mods[i]; int value = EnvironmentSetup::GetInt(mod); if (value == 1) { ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.9f); ImVec4 color = ImGui::GetStyleColorVec4(ImGuiCol_Button); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(color.x * 1.2f, color.y * 1.2f, color.z * 1.2f, 1.0f)); } @@ -541,40 +543,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) EnvironmentSetup::SetInt(Mods[2], 0); // Panic EnvironmentSetup::SetInt(Mods[3], 0); // Rearrange break; - case 1: // Random - EnvironmentSetup::SetInt(Mods[0], 0); // Mirror - EnvironmentSetup::SetInt(Mods[2], 0); // Panic - EnvironmentSetup::SetInt(Mods[3], 0); // Rearrange - break; - case 2: // Panic - EnvironmentSetup::SetInt(Mods[0], 0); // Mirror - EnvironmentSetup::SetInt(Mods[1], 0); // Random - EnvironmentSetup::SetInt(Mods[3], 0); // Rearrange - break; - case 3: // Rearrange - EnvironmentSetup::SetInt(Mods[0], 0); // Mirror - EnvironmentSetup::SetInt(Mods[1], 0); // Random - EnvironmentSetup::SetInt(Mods[2], 0); // Panic - bOpenRearrange = true; // Open Rearrange Window - break; - case 5: // Hidden - EnvironmentSetup::SetInt(Mods[6], 0); // Flashlight - EnvironmentSetup::SetInt(Mods[7], 0); // Sudden - break; - case 6: // Flashlight - EnvironmentSetup::SetInt(Mods[5], 0); // Hidden - EnvironmentSetup::SetInt(Mods[7], 0); // Sudden - break; - case 7: // Sudden - EnvironmentSetup::SetInt(Mods[5], 0); // Hidden - EnvironmentSetup::SetInt(Mods[6], 0); // Flashlight - break; - case 8: // Song Background - EnvironmentSetup::SetInt(Mods[9], 0); // Black Background - break; - case 9: // Black Background - EnvironmentSetup::SetInt(Mods[8], 0); // Song Background - break; + // Cases omitted for brevity } } @@ -589,8 +558,6 @@ void SongSelectScene::OnGameSelectMusic(double delta) } } - ImGui::NewLine(); - ImGui::PushItemWidth(ImGui::GetCurrentWindow()->Size.x - 15); ImGui::Text("Arena"); @@ -606,11 +573,16 @@ void SongSelectScene::OnGameSelectMusic(double delta) ImGui::EndCombo(); } + + ImGui::PopStyleVar(); + ImGui::PopItemWidth(); ImGui::EndChild(); } + ImGui::PopStyleVar(); + ImGui::EndChild(); } From b10e6a16d5e5083d3a9e8adc6745e5ff92b79b62 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sun, 14 Apr 2024 02:28:19 +0700 Subject: [PATCH 08/83] fix(songselectscene): fix switch case modifier --- Game/src/Scenes/SongSelectScene.cpp | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index aaaa1a1e..368f7c19 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -543,7 +543,34 @@ void SongSelectScene::OnGameSelectMusic(double delta) EnvironmentSetup::SetInt(Mods[2], 0); // Panic EnvironmentSetup::SetInt(Mods[3], 0); // Rearrange break; - // Cases omitted for brevity + case 1: // Random + EnvironmentSetup::SetInt(Mods[0], 0); // Mirror + EnvironmentSetup::SetInt(Mods[2], 0); // Panic + EnvironmentSetup::SetInt(Mods[3], 0); // Rearrange + break; + case 2: // Panic + EnvironmentSetup::SetInt(Mods[0], 0); // Mirror + EnvironmentSetup::SetInt(Mods[1], 0); // Random + EnvironmentSetup::SetInt(Mods[3], 0); // Rearrange + break; + case 3: // Rearrange + EnvironmentSetup::SetInt(Mods[0], 0); // Mirror + EnvironmentSetup::SetInt(Mods[1], 0); // Random + EnvironmentSetup::SetInt(Mods[2], 0); // Panic + bOpenRearrange = true; // Open Rearrange Window + break; + case 5: // Hidden + EnvironmentSetup::SetInt(Mods[6], 0); // Flashlight + EnvironmentSetup::SetInt(Mods[7], 0); // Sudden + break; + case 6: // Flashlight + EnvironmentSetup::SetInt(Mods[5], 0); // Hidden + EnvironmentSetup::SetInt(Mods[7], 0); // Sudden + break; + case 7: // Sudden + EnvironmentSetup::SetInt(Mods[5], 0); // Hidden + EnvironmentSetup::SetInt(Mods[6], 0); // Flashlight + break; } } From 684b2739155a3b009a5457e8fd7be490930c54b7 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sun, 14 Apr 2024 13:40:21 +0700 Subject: [PATCH 09/83] feat: open file feature inside game need to fix selected mods not applied if using open file --- Game/src/Scenes/ResultScene.cpp | 10 +++------- Game/src/Scenes/SongSelectScene.cpp | 31 ++++++++++++++++++----------- Game/src/Scenes/SongSelectScene.h | 1 + Game/src/main.cpp | 4 ++++ 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/Game/src/Scenes/ResultScene.cpp b/Game/src/Scenes/ResultScene.cpp index 83146054..00cbcac9 100644 --- a/Game/src/Scenes/ResultScene.cpp +++ b/Game/src/Scenes/ResultScene.cpp @@ -132,13 +132,9 @@ void ResultScene::Render(double delta) } if (m_backButton) { - if (EnvironmentSetup::GetPath("FILE").empty()) { - SceneManager::DisplayFade(100, [] { - SceneManager::ChangeScene(GameScene::SONGSELECT); - }); - } else { - SceneManager::GetInstance()->StopGame(); - } + SceneManager::DisplayFade(100, [] { + SceneManager::ChangeScene(GameScene::SONGSELECT); + }); } if (m_retryButton) { diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index 368f7c19..1d08a1df 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -115,9 +115,9 @@ void SongSelectScene::Render(double delta) bQuit = true; } - /*if (ImGui::Button("Open File", MathUtil::ScaleVec2(ImVec2(50, 0)))) { + if (ImGui::Button("Open File", MathUtil::ScaleVec2(ImVec2(50, 0)))) { bOpenFile = true; - }*/ // FIXME: Plz Fix This + } if (ImGui::Button("Settings", MathUtil::ScaleVec2(ImVec2(50, 0)))) { bOptionPopup = true; @@ -352,20 +352,14 @@ void SongSelectScene::Render(double delta) } if (bOpenFile) { - std::wstring songfile = OpenFilePrompt(); + std::wstring songfile = OpenFilePrompt(); //FIXME: Selected mods not applied or saved if using open file if (!songfile.empty()) { - EnvironmentSetup::SetPath("FILE", songfile); is_departing = true; SaveConfiguration(); + EnvironmentSetup::SetPath("FILE", songfile); - if (m_songBackground) { - EnvironmentSetup::SetObj("SongBackground", m_songBackground.get()); - } - - nextAlpha = 0; - SceneManager::ExecuteAfter(600, [this]() { - SceneManager::ChangeScene(GameScene::LOADING); - }); + // Restart the game + RestartGame(); } else { MsgBox::Show("MustSelectFile", "Error", "You must select a file!", MsgBoxType::OK); @@ -911,6 +905,19 @@ bool SongSelectScene::Attach() return true; } +void SongSelectScene::RestartGame() { // HACK: This is the only way to use Open File function by restart the game to use the file opened without path issues + wchar_t moduleFileName[MAX_PATH]; + GetModuleFileNameW(NULL, moduleFileName, MAX_PATH); + + std::wstring commandLine = std::wstring(moduleFileName) + L" \"" + std::wstring(EnvironmentSetup::GetPath("FILE")) + L"\""; + + STARTUPINFOW si = { sizeof(si) }; + PROCESS_INFORMATION pi; + CreateProcessW(NULL, const_cast(commandLine.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + + ExitProcess(0); +} + bool SongSelectScene::Detach() { if (m_bgm) { diff --git a/Game/src/Scenes/SongSelectScene.h b/Game/src/Scenes/SongSelectScene.h index e3c95560..cfd3355f 100644 --- a/Game/src/Scenes/SongSelectScene.h +++ b/Game/src/Scenes/SongSelectScene.h @@ -24,6 +24,7 @@ class SongSelectScene : public Scene void OnMouseDown(const MouseState &state) override; bool Attach() override; + void RestartGame(); bool Detach() override; protected: diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 6d501ab9..559439d2 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -76,6 +76,10 @@ int Run(int argc, wchar_t **argv) } } + if (argc > 1) { // Run game with opened file + EnvironmentSetup::SetPath("FILE", argv[1]); + } + MyGame game; if (game.Init()) { game.Run(); From 46c5b05a620486251e1122a8597f4fba8b4a8667 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sun, 14 Apr 2024 14:22:28 +0700 Subject: [PATCH 10/83] --- Game/src/main.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 559439d2..6d501ab9 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -76,10 +76,6 @@ int Run(int argc, wchar_t **argv) } } - if (argc > 1) { // Run game with opened file - EnvironmentSetup::SetPath("FILE", argv[1]); - } - MyGame game; if (game.Init()) { game.Run(); From 0b2c6e25226a934ae4032654cfb9dc193a94240a Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Mon, 15 Apr 2024 20:40:05 +0700 Subject: [PATCH 11/83] feat: open file now can load selected mod --- Game/src/Resources/DefaultConfiguration.h | 4 +++- Game/src/Scenes/LoadingScene.cpp | 19 ++++++++++++++++++- Game/src/Scenes/LoadingScene.h | 1 + Game/src/Scenes/SongSelectScene.cpp | 20 +++++++++++++++++++- Game/src/Scenes/SongSelectScene.h | 1 + Game/src/main.cpp | 2 +- 6 files changed, 43 insertions(+), 4 deletions(-) diff --git a/Game/src/Resources/DefaultConfiguration.h b/Game/src/Resources/DefaultConfiguration.h index 0fbd3b2c..265a8323 100644 --- a/Game/src/Resources/DefaultConfiguration.h +++ b/Game/src/Resources/DefaultConfiguration.h @@ -42,4 +42,6 @@ std::string defaultConfiguration = "[game]\n" "folder =\n" "[gameplay]\n" - "notespeed = 225\n"; \ No newline at end of file + "notespeed = 250\n" + "modifiers =\n" + "arena =\n"; \ No newline at end of file diff --git a/Game/src/Scenes/LoadingScene.cpp b/Game/src/Scenes/LoadingScene.cpp index 217fc103..680f2b6f 100644 --- a/Game/src/Scenes/LoadingScene.cpp +++ b/Game/src/Scenes/LoadingScene.cpp @@ -18,7 +18,6 @@ #include "../GameScenes.h" #include "../Resources/GameDatabase.h" -// I don't know if this new changes causing memleak or not because i can't tell due my hardware limit LoadingScene::LoadingScene() { m_background = nullptr; @@ -58,6 +57,10 @@ void LoadingScene::Update(double delta) EnvironmentSetup::Set("SongRate", rate); EnvironmentSetup::SetInt("Song BG", 1); EnvironmentSetup::SetInt("Difficulty", 2); // Hard difficulty it's fun (fucked) + + if (EnvironmentSetup::GetInt("FileOpen") == 1) { + LoadModifiers(); + } } const char *bmsfile[] = { ".bms", ".bme", ".bml", ".bmsc" }; @@ -173,6 +176,20 @@ void LoadingScene::Update(double delta) } } +void LoadingScene::LoadModifiers() // For File Opened +{ + std::string selectedMods = Configuration::Load("Gameplay", "Modifiers"); + std::istringstream iss(selectedMods); + std::string mod; + while (std::getline(iss, mod, ',')) { + EnvironmentSetup::SetInt(mod, 1); + } + + // Load selected arena + std::string arenaValue = Configuration::Load("Gameplay", "Arena"); + EnvironmentSetup::SetInt("Arena", std::stoi(arenaValue)); +} + void LoadingScene::Render(double delta) { if (m_background && is_ready) { diff --git a/Game/src/Scenes/LoadingScene.h b/Game/src/Scenes/LoadingScene.h index c3ad174c..4fd27efd 100644 --- a/Game/src/Scenes/LoadingScene.h +++ b/Game/src/Scenes/LoadingScene.h @@ -10,6 +10,7 @@ class LoadingScene : public Scene ~LoadingScene(); void Update(double delta) override; + void LoadModifiers(); void Render(double delta) override; bool Attach() override; diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index 1d08a1df..797ed74f 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -352,10 +352,11 @@ void SongSelectScene::Render(double delta) } if (bOpenFile) { + SaveModifiers(); + SaveConfiguration(); std::wstring songfile = OpenFilePrompt(); //FIXME: Selected mods not applied or saved if using open file if (!songfile.empty()) { is_departing = true; - SaveConfiguration(); EnvironmentSetup::SetPath("FILE", songfile); // Restart the game @@ -942,6 +943,23 @@ void SongSelectScene::SaveConfiguration() Configuration::Set("Gameplay", "Notespeed", std::to_string(static_cast(::round(currentSpeed * 100.0)))); } +void SongSelectScene::SaveModifiers() +{ + std::string selectedMods; + for (int i = 0; i < Mods.size(); i++) { + std::string mod = Mods[i]; + int value = EnvironmentSetup::GetInt(mod); + if (value == 1) { + if (!selectedMods.empty()) selectedMods += ","; + selectedMods += mod; + } + } + Configuration::Set("Gameplay", "Modifiers", selectedMods); + + int arenaValue = EnvironmentSetup::GetInt("Arena"); + Configuration::Set("Gameplay", "Arena", std::to_string(arenaValue)); +} + void SongSelectScene::LoadChartImage() { std::lock_guard lock(m_imageLock); diff --git a/Game/src/Scenes/SongSelectScene.h b/Game/src/Scenes/SongSelectScene.h index cfd3355f..72e2d206 100644 --- a/Game/src/Scenes/SongSelectScene.h +++ b/Game/src/Scenes/SongSelectScene.h @@ -33,6 +33,7 @@ class SongSelectScene : public Scene private: void SaveConfiguration(); + void SaveModifiers(); void LoadChartImage(); int scene_index = 0; diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 6d501ab9..dcaaae7c 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -71,7 +71,7 @@ int Run(int argc, wchar_t **argv) if (std::filesystem::exists(argv[i]) && EnvironmentSetup::GetPath("FILE").empty()) { std::filesystem::path path = argv[i]; - + EnvironmentSetup::SetInt("FileOpen", 1); EnvironmentSetup::SetPath("FILE", path); } } From cfa99844f0b377b121aa3bd1a424b7e33e4e590f Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Mon, 15 Apr 2024 22:04:12 +0700 Subject: [PATCH 12/83] refactor(songselectscene): added difficulty to saved selected mod after open file --- Game/src/Resources/DefaultConfiguration.h | 1 + Game/src/Scenes/LoadingScene.cpp | 20 +++++++++++++++++--- Game/src/Scenes/SongSelectScene.cpp | 6 ++++-- Game/src/Scenes/SongSelectScene.h | 3 +++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/Game/src/Resources/DefaultConfiguration.h b/Game/src/Resources/DefaultConfiguration.h index 265a8323..4a895d31 100644 --- a/Game/src/Resources/DefaultConfiguration.h +++ b/Game/src/Resources/DefaultConfiguration.h @@ -43,5 +43,6 @@ std::string defaultConfiguration = "[game]\n" "[gameplay]\n" "notespeed = 250\n" + "difficulty = \n" "modifiers =\n" "arena =\n"; \ No newline at end of file diff --git a/Game/src/Scenes/LoadingScene.cpp b/Game/src/Scenes/LoadingScene.cpp index 680f2b6f..65d5bf93 100644 --- a/Game/src/Scenes/LoadingScene.cpp +++ b/Game/src/Scenes/LoadingScene.cpp @@ -55,12 +55,13 @@ void LoadingScene::Update(double delta) EnvironmentSetup::SetInt("Autoplay", autoplay); EnvironmentSetup::Set("SongRate", rate); - EnvironmentSetup::SetInt("Song BG", 1); - EnvironmentSetup::SetInt("Difficulty", 2); // Hard difficulty it's fun (fucked) if (EnvironmentSetup::GetInt("FileOpen") == 1) { LoadModifiers(); } + else { + EnvironmentSetup::SetInt("Song BG", 1); + } } const char *bmsfile[] = { ".bms", ".bme", ".bml", ".bmsc" }; @@ -178,6 +179,20 @@ void LoadingScene::Update(double delta) void LoadingScene::LoadModifiers() // For File Opened { + std::string difficultyValue = Configuration::Load("Gameplay", "Difficulty"); + int setDifficulty = std::stoi(difficultyValue); + switch (setDifficulty) { + case 0: // EZ + EnvironmentSetup::SetInt("Difficulty", 0); + break; + case 1: // NM + EnvironmentSetup::SetInt("Difficulty", 1); + break; + case 2: // HD + EnvironmentSetup::SetInt("Difficulty", 2); + break; + } + std::string selectedMods = Configuration::Load("Gameplay", "Modifiers"); std::istringstream iss(selectedMods); std::string mod; @@ -185,7 +200,6 @@ void LoadingScene::LoadModifiers() // For File Opened EnvironmentSetup::SetInt(mod, 1); } - // Load selected arena std::string arenaValue = Configuration::Load("Gameplay", "Arena"); EnvironmentSetup::SetInt("Arena", std::stoi(arenaValue)); } diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index 797ed74f..d9b1770c 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -425,7 +425,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) auto music = GameDatabase::GetInstance(); auto window = GameWindow::GetInstance(); auto windowNextSz = ImVec2((float)window->GetBufferWidth(), (float)window->GetBufferHeight()); - int currentDifficulty = EnvironmentSetup::GetInt("Difficulty"); + currentDifficulty = EnvironmentSetup::GetInt("Difficulty"); // create child window if (ImGui::BeginChild("#Container1", MathUtil::ScaleVec2(ImVec2(200, 500)))) { @@ -458,7 +458,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) ImGui::Text("Total Notes\r"); - int difficulty = EnvironmentSetup::GetInt("Difficulty"); + difficulty = EnvironmentSetup::GetInt("Difficulty"); int count = item.Id == -1 ? 0 : item.MaxNotes[difficulty]; imgui_extends::TextBackground(color, MathUtil::ScaleVec2(340, 0), "%d", count); @@ -945,6 +945,8 @@ void SongSelectScene::SaveConfiguration() void SongSelectScene::SaveModifiers() { + Configuration::Set("Gameplay", "Difficulty", std::to_string(currentDifficulty)); + std::string selectedMods; for (int i = 0; i < Mods.size(); i++) { std::string mod = Mods[i]; diff --git a/Game/src/Scenes/SongSelectScene.h b/Game/src/Scenes/SongSelectScene.h index 72e2d206..ab5d4ce4 100644 --- a/Game/src/Scenes/SongSelectScene.h +++ b/Game/src/Scenes/SongSelectScene.h @@ -44,6 +44,9 @@ class SongSelectScene : public Scene bool isScrolled = false; float waitTime = 0; + int currentDifficulty; + int difficulty; + float currentSpeed = 2.25; float currentRate = 1.0; From 9df2a24658c9798405981224acd64b85e19387e1 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Mon, 15 Apr 2024 22:27:50 +0700 Subject: [PATCH 13/83] --- Game/src/Scenes/Overlays/Settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index 78d69f8e..2ae8974b 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -45,7 +45,7 @@ static std::map Graphics = { static std::array LongNote = { "None", "Short", "Normal", "Long" }; static std::array m_fps = { "30", "60", "75", "120", "144", "165", "180", "240", "360", "480", "600", "800", "1000", "Unlimited" }; -static std::array SelectedBackground = { "Arena", "Song", "Black" }; +static std::array SelectedBackground = { "Arena", "Song", "Disable" }; static std::vector m_resolutions = {}; From 5747db7d0546ab95acf97c5aa8bfa9771cef9129 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sat, 20 Apr 2024 00:08:03 +0700 Subject: [PATCH 14/83] feat: added new settings and fix --- Game/src/Engine/Note.cpp | 4 +- Game/src/Engine/RhythmEngine.cpp | 6 ++- Game/src/Scenes/GameplayScene.cpp | 1 + Game/src/Scenes/Overlays/Settings.cpp | 56 +++++++++++++++++++++++++++ Game/src/Scenes/Overlays/Settings.h | 2 + 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index f5382c59..d0c660f7 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -248,7 +248,9 @@ void Note::Render(double delta) m_body->SetIndexAt(m_engine->GetNoteImageIndex()); m_body->Draw(delta, &playRect); - if (isTailVisible) { + bool NoteTail = EnvironmentSetup::GetInt("NoteTail") == 1; + + if (isTailVisible && NoteTail) { m_tail->Position = UDim2::fromOffset(m_laneOffset, tailPosY); m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); m_tail->Draw(delta, &playRect); diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 778baa62..7b6e5715 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -418,7 +418,11 @@ void RhythmEngine::Render(double delta) if (m_state == GameState::NotGame || m_state == GameState::PosGame) return; - m_timingLineManager->Render(delta); + bool MeasureLine = EnvironmentSetup::GetInt("MeasureLine") == 1; + + if (MeasureLine) { + m_timingLineManager->Render(delta); + } for (auto &it : m_tracks) { it->Render(delta); diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 14245b37..ed033c92 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -84,6 +84,7 @@ void GameplayScene::Update(double delta) if (m_counter > 10.0) { m_ended = true; + m_counter = 0.0; // Reset SceneManager::DisplayFade(100, [] { SceneManager::ChangeScene(GameScene::RESULT); }); diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index 2ae8974b..a57a8c06 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -308,16 +308,40 @@ void SettingsOverlay::Render(double delta) ImGui::NewLine(); ImGui::Text("Gameplay-Related Configuration"); + ImGui::Checkbox("Long Note Lighting###SetCheckbox1", &LongNoteLighting); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("When Long note on hold, change the lighting brightness to 100%% else 90%% brightness"); } + ImGui::SameLine(); + + ImGui::Checkbox("Disable Note Tail###SetCheckbox3", &NoteTail); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Why this called No Percy? Lol"); + } + if (NoteTail) { + EnvironmentSetup::SetInt("NoteTail", 0); + } + else { + EnvironmentSetup::SetInt("NoteTail", 1); + } + ImGui::Checkbox("Long Note Head Position at HitPos###SetCheckbox2", &LongNoteOnHitPos); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("When Long note on hold, make the head position at hit position else keep going to bottom"); } + ImGui::SameLine(); + + ImGui::Checkbox("Disable Measure Line###SetCheckbox4", &MeasureLine); + if (MeasureLine) { + EnvironmentSetup::SetInt("MeasureLine", 0); + } + else { + EnvironmentSetup::SetInt("MeasureLine", 1); + } + ImGui::NewLine(); ImGui::Text("Background"); @@ -512,6 +536,36 @@ void SettingsOverlay::LoadConfiguration() EnvironmentSetup::SetInt("Black Background", 1); } + try { + int noteTailValue = std::stoi(Configuration::Load("Game", "NoteTail")); + NoteTail = (noteTailValue == 1); + } + catch (const std::invalid_argument&) { + NoteTail = true; + } + + if (NoteTail) { // HACK: Same workaround like Background :troll: + EnvironmentSetup::SetInt("NoteTail", 0); + } + else { + EnvironmentSetup::SetInt("NoteTail", 1); + } + + try { + int measureLineValue = std::stoi(Configuration::Load("Game", "MeasureLine")); + MeasureLine = (measureLineValue == 1); + } + catch (const std::invalid_argument&) { + MeasureLine = true; + } + + if (MeasureLine) { // HACK: Same workaround like Background :troll: + EnvironmentSetup::SetInt("MeasureLine", 0); + } + else { + EnvironmentSetup::SetInt("MeasureLine", 1); + } + auto fps = m_fps[currentFPSIndex]; if (fps == *(m_fps.end() - 1)) { fps = "9999" ; @@ -530,6 +584,8 @@ void SettingsOverlay::SaveConfiguration() Configuration::Set("Game", "FrameLimit", m_fps[currentFPSIndex]); Configuration::Set("Game", "GuideLine", std::to_string(currentGuideLineIndex)); Configuration::Set("Game", "Background", std::to_string(BackgroundIndex)); + Configuration::Set("Game", "MeasureLine", std::to_string(MeasureLine ? 1 : 0)); + Configuration::Set("Game", "NoteTail", std::to_string(NoteTail ? 1 : 0)); auto frame = m_fps[currentFPSIndex]; if (frame == m_fps[13]) { diff --git a/Game/src/Scenes/Overlays/Settings.h b/Game/src/Scenes/Overlays/Settings.h index a999f70b..44f9f442 100644 --- a/Game/src/Scenes/Overlays/Settings.h +++ b/Game/src/Scenes/Overlays/Settings.h @@ -26,6 +26,8 @@ class SettingsOverlay : public Overlay int currentGuideLineIndex = 0; bool LongNoteLighting = false; bool LongNoteOnHitPos = false; + bool MeasureLine = false; + bool NoteTail = false; int BackgroundIndex = 0; bool convertAutoSound = false; From 044e9ee88575ebfd84d5fdb63e1cb68e342385f7 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sat, 20 Apr 2024 21:38:14 +0700 Subject: [PATCH 15/83] refactor(gameplayscene): The true O2Jam Combo animation --- Game/src/Scenes/GameplayScene.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index ed033c92..5ec75429 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -274,13 +274,22 @@ void GameplayScene::Render(double delta) } } - if (m_drawCombo && std::get<7>(scores) > 0) { // This should be O2Jam Replication + if (m_drawCombo && std::get<7>(scores) > 0) { // O2Jam Combo Animation 1:1 const double positionStart = 30.0; + const double increment = 6.0; const double decrement = 6.0; - double animationSpeed = 60.0; + double animationSpeed = 72.0; - double targetposition = positionStart - decrement * m_comboTimer * animationSpeed; - double currentposition = (targetposition > 0.0) ? targetposition : 0.0; + double targetPosition = positionStart - decrement * m_comboTimer * animationSpeed; + double currentposition = (targetPosition > 0.0) ? targetPosition : 0.0; + + // If moving down, limit the wiggle to between 30px and 36px + if (currentposition > positionStart) { + double wiggleAmount = currentposition - positionStart; + if (wiggleAmount > increment) { + currentposition = positionStart + increment; + } + } m_comboLogo->Position2 = UDim2::fromOffset(0, currentposition / 3.0); m_comboNum->Position2 = UDim2::fromOffset(0, currentposition); From 664e09549a033d6af10bbd60d7d98e029d53c84c Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sun, 21 Apr 2024 19:31:46 +0700 Subject: [PATCH 16/83] fix: antivirus false detection --- Game/src/Scenes/SongSelectScene.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index d9b1770c..81c17d55 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -910,13 +910,17 @@ void SongSelectScene::RestartGame() { // HACK: This is the only way to use Open wchar_t moduleFileName[MAX_PATH]; GetModuleFileNameW(NULL, moduleFileName, MAX_PATH); - std::wstring commandLine = std::wstring(moduleFileName) + L" \"" + std::wstring(EnvironmentSetup::GetPath("FILE")) + L"\""; + std::wstring filePath = EnvironmentSetup::GetPath("FILE"); + std::wstring commandLine = std::wstring(moduleFileName) + L" \"" + filePath + L"\""; STARTUPINFOW si = { sizeof(si) }; PROCESS_INFORMATION pi; - CreateProcessW(NULL, const_cast(commandLine.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); - ExitProcess(0); + if (CreateProcessW(NULL, const_cast(commandLine.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { // Fix antivirus false detection + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + ExitProcess(0); + } } bool SongSelectScene::Detach() From 8848758b1e02f4282ffb940bfa28d31cefd9dd14 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Tue, 14 May 2024 13:28:44 +0700 Subject: [PATCH 17/83] refactor: fix Lv. 0 on Title and stuff --- Engine/include/Rendering/Window.h | 2 +- Engine/src/Rendering/GameWindow.cpp | 2 +- Engine/src/Texture/Texture2D.cpp | 16 +++--- Game/src/Data/Chart.cpp | 5 +- Game/src/Data/Chart.hpp | 1 + Game/src/Engine/FrameTimer.cpp | 77 ++++++++++++++--------------- Game/src/Engine/RhythmEngine.cpp | 17 +++++-- Game/src/Scenes/GameplayScene.cpp | 4 +- Game/src/Scenes/LoadingScene.cpp | 5 +- Game/src/Scenes/SongSelectScene.cpp | 2 +- 10 files changed, 72 insertions(+), 59 deletions(-) diff --git a/Engine/include/Rendering/Window.h b/Engine/include/Rendering/Window.h index 6ce2e40d..4f3b575e 100644 --- a/Engine/include/Rendering/Window.h +++ b/Engine/include/Rendering/Window.h @@ -26,7 +26,7 @@ class GameWindow float GetHeightScale(); void SetScaleOutput(bool value); - bool IsScaleOutput(); + bool IsScaleOutput() const; void SetWindowTitle(std::string &title); void SetWindowSubTitle(std::string &subTitle); diff --git a/Engine/src/Rendering/GameWindow.cpp b/Engine/src/Rendering/GameWindow.cpp index 9d2cf067..60bdbb19 100644 --- a/Engine/src/Rendering/GameWindow.cpp +++ b/Engine/src/Rendering/GameWindow.cpp @@ -193,7 +193,7 @@ void GameWindow::SetScaleOutput(bool value) m_scaleOutput = value; } -bool GameWindow::IsScaleOutput() +bool GameWindow::IsScaleOutput() const { return m_scaleOutput; } diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 369ade58..b5d184da 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -157,10 +157,10 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) scissor.extent.height = window->GetHeight(); if (clipRect) { - scissor.offset.x = clipRect->left; - scissor.offset.y = clipRect->top; - scissor.extent.width = clipRect->right - clipRect->left; - scissor.extent.height = clipRect->bottom - clipRect->top; + scissor.offset.x = static_cast(clipRect->left * window->GetWidthScale()); + scissor.offset.y = static_cast(clipRect->top * window->GetHeightScale()); + scissor.extent.width = static_cast((clipRect->right - clipRect->left) * window->GetWidthScale()); + scissor.extent.height = static_cast((clipRect->bottom - clipRect->top) * window->GetHeightScale()); } VkDescriptorSet imageId = m_vk_tex->DS; @@ -240,10 +240,10 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) } else { SDL_FRect destRect = { m_calculatedSizeF.left, m_calculatedSizeF.top, m_calculatedSizeF.right, m_calculatedSizeF.bottom }; if (scaleOutput) { - destRect.x = destRect.x * window->GetWidthScale(); - destRect.y = destRect.y * window->GetHeightScale(); - destRect.w = destRect.w * window->GetWidthScale(); - destRect.h = destRect.h * window->GetHeightScale(); + destRect.x = std::round(destRect.x * window->GetWidthScale()); + destRect.y = std::round(destRect.y * window->GetHeightScale()); + destRect.w = std::round(destRect.w * window->GetWidthScale()); + destRect.h = std::round(destRect.h * window->GetHeightScale()); } SDL_Rect originClip = {}; diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index b7c24283..0165141a 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -51,6 +51,7 @@ Chart::Chart(Osu::Beatmap &beatmap) m_title = std::u8string(beatmap.Title.begin(), beatmap.Title.end()); m_keyCount = (int)beatmap.CircleSize; m_artist = std::u8string(beatmap.Artist.begin(), beatmap.Artist.end()); + m_difname = std::u8string(beatmap.Version.begin(), beatmap.Version.end()); m_beatmapDirectory = beatmap.CurrentDir; for (auto &event : beatmap.Events) { @@ -379,7 +380,7 @@ Chart::Chart(O2::OJN &file, int diffIndex) -void Chart::CalculateBeat() +void Chart::CalculateBeat() { m_bpms[0].Beat = 0; for (size_t i = 1; i < m_bpms.size(); i++) { @@ -387,7 +388,7 @@ void Chart::CalculateBeat() } } -void Chart::SortTimings() +void Chart::SortTimings() { std::sort(m_autoSamples.begin(), m_autoSamples.end(), [](const AutoSample& a, const AutoSample& b) { return a.StartTime < b.StartTime; diff --git a/Game/src/Data/Chart.hpp b/Game/src/Data/Chart.hpp index 3515ce63..c11dc1af 100644 --- a/Game/src/Data/Chart.hpp +++ b/Game/src/Data/Chart.hpp @@ -105,6 +105,7 @@ class Chart std::vector m_backgroundBuffer; std::u8string m_title; std::u8string m_artist; + std::u8string m_difname; std::string m_audio; std::filesystem::path m_beatmapDirectory; diff --git a/Game/src/Engine/FrameTimer.cpp b/Game/src/Engine/FrameTimer.cpp index 1f5e7d24..77dee001 100644 --- a/Game/src/Engine/FrameTimer.cpp +++ b/Game/src/Engine/FrameTimer.cpp @@ -2,50 +2,46 @@ #include "Rendering/Renderer.h" #include "Texture/Texture2D.h" -FrameTimer::FrameTimer() +FrameTimer::FrameTimer() : + Repeat(false), + m_currentFrame(0), + m_frameTime(1.0 / 60.0), + m_currentTime(0), + AlphaBlend(false), + Size(UDim2::fromScale(1, 1)), + TintColor({1.0f, 1.0f, 1.0f}) { - Repeat = false; - m_currentFrame = 0; - m_frameTime = 1.0 / 60.0; - m_currentTime = 0; - AlphaBlend = false; - Size = UDim2::fromScale(1, 1); - TintColor = { 1.0f, 1.0f, 1.0f }; } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = frames; + m_frames = std::move(frames); } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = std::vector(); - for (auto frame : frames) { + for (const auto &frame : frames) { m_frames.emplace_back(new Texture2D(frame)); } } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = std::vector(); - for (auto frame : frames) { + for (const auto &frame : frames) { m_frames.emplace_back(new Texture2D(frame)); } } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = std::vector(); - for (auto frame : frames) { + for (const auto &frame : frames) { m_frames.emplace_back(new Texture2D(frame)); } } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = std::vector(); - for (auto frame : frames) { + for (const auto &frame : frames) { m_frames.emplace_back(new Texture2D(frame)); } } @@ -68,26 +64,26 @@ void FrameTimer::Draw(double delta, Rect *clip) if (m_currentTime >= m_frameTime) { m_currentTime -= m_frameTime; - m_currentFrame++; } - if (Repeat && m_currentFrame >= m_frames.size()) { - m_currentFrame = 0; - } + if (Repeat && m_currentFrame >= m_frames.size()) { + m_currentFrame = 0; + } if (m_currentFrame < m_frames.size()) { CalculateSize(); - m_frames[m_currentFrame]->AlphaBlend = AlphaBlend; - m_frames[m_currentFrame]->TintColor = TintColor; + auto currentFrame = m_frames[m_currentFrame]; + currentFrame->AlphaBlend = AlphaBlend; + currentFrame->TintColor = TintColor; if (m_currentFrame != 0) { - m_frames[m_currentFrame]->Position = UDim2::fromOffset(AbsolutePosition.X, AbsolutePosition.Y); - m_frames[m_currentFrame]->Size = UDim2::fromOffset(AbsoluteSize.X, AbsoluteSize.Y); - m_frames[m_currentFrame]->AnchorPoint = { 0, 0 }; + currentFrame->Position = UDim2::fromOffset(AbsolutePosition.X, AbsolutePosition.Y); + currentFrame->Size = UDim2::fromOffset(AbsoluteSize.X, AbsoluteSize.Y); + currentFrame->AnchorPoint = {0, 0}; } - m_frames[m_currentFrame]->Draw(clip); + currentFrame->Draw(clip); } } @@ -103,7 +99,7 @@ void FrameTimer::ResetIndex() void FrameTimer::LastIndex() { - m_currentFrame = (int)m_frames.size() - 1; + m_currentFrame = static_cast(m_frames.size()) - 1; } void FrameTimer::SetIndexAt(int idx) @@ -113,11 +109,12 @@ void FrameTimer::SetIndexAt(int idx) void FrameTimer::CalculateSize() { - m_frames[0]->AnchorPoint = AnchorPoint; - m_frames[0]->Size = Size; - m_frames[0]->Position = Position; - m_frames[0]->CalculateSize(); - - AbsoluteSize = m_frames[0]->AbsoluteSize; - AbsolutePosition = m_frames[0]->AbsolutePosition; + auto &firstFrame = *m_frames[0]; + firstFrame.AnchorPoint = AnchorPoint; + firstFrame.Size = Size; + firstFrame.Position = Position; + firstFrame.CalculateSize(); + + AbsoluteSize = firstFrame.AbsoluteSize; + AbsolutePosition = firstFrame.AbsolutePosition; } diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 7b6e5715..b5c4dcc2 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -1,4 +1,4 @@ -#include "RhythmEngine.hpp" +#include "RhythmEngine.hpp" #include #include #include @@ -221,9 +221,20 @@ bool RhythmEngine::Load(Chart *chart) m_rate = std::clamp(m_rate, 0.5, 2.0); } - m_title = chart->m_title; char buffer[MAX_BUFFER_TXT_SIZE]; - sprintf(buffer, "Lv.%d %s", chart->m_level, (const char *)chart->m_title.c_str()); + + if (EnvironmentSetup::GetInt("SongType") == 1) { + m_title = chart->m_title; + sprintf(buffer, "Lv.%d %s", chart->m_level, (const char*)chart->m_title.c_str()); + } + else if (EnvironmentSetup::GetInt("SongType") == 2) { + m_title = chart->m_title; + sprintf(buffer, "[%s] %s", chart->m_difname, (const char*)chart->m_title.c_str()); + } + else { + m_title = chart->m_title; + //sprintf(buffer, "%d %s", chart->m_level, (const char*)chart->m_title.c_str()); + } m_title = std::u8string(buffer, buffer + strlen(buffer)); if (m_rate != 1.0) { diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 5ec75429..9d63aed7 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -98,12 +98,12 @@ void GameplayScene::Update(double delta) if (health <= 0) { m_game->Stop(); EnvironmentSetup::SetInt("Failed", 1); - } + } } if (m_doExit && !m_ended) { m_ended = true; - + auto scores = m_game->GetScoreManager()->GetScore(); if (std::get<1>(scores) != 0 || std::get<2>(scores) != 0 || std::get<3>(scores) != 0 || std::get<4>(scores) != 0) { diff --git a/Game/src/Scenes/LoadingScene.cpp b/Game/src/Scenes/LoadingScene.cpp index 65d5bf93..96cfda81 100644 --- a/Game/src/Scenes/LoadingScene.cpp +++ b/Game/src/Scenes/LoadingScene.cpp @@ -78,6 +78,7 @@ void LoadingScene::Update(double delta) } chart = new Chart(beatmap); + EnvironmentSetup::SetInt("SongType", 0); } else if (file.extension() == ojnfile) { O2::OJN o2jamFile; o2jamFile.Load(file); @@ -91,8 +92,9 @@ void LoadingScene::Update(double delta) } chart = new Chart(o2jamFile, diffIndex); - + EnvironmentSetup::SetInt("SongType", 1); IsO2Jam = true; + } else { Osu::Beatmap beatmap(file); @@ -103,6 +105,7 @@ void LoadingScene::Update(double delta) } chart = new Chart(beatmap); + EnvironmentSetup::SetInt("SongType", 2); } EnvironmentSetup::SetObj("SONG", chart); diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index 81c17d55..987ca7c9 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -354,7 +354,7 @@ void SongSelectScene::Render(double delta) if (bOpenFile) { SaveModifiers(); SaveConfiguration(); - std::wstring songfile = OpenFilePrompt(); //FIXME: Selected mods not applied or saved if using open file + std::wstring songfile = OpenFilePrompt(); if (!songfile.empty()) { is_departing = true; EnvironmentSetup::SetPath("FILE", songfile); From 349a76ee22c7428e8cb5cf43354eaf6459c881f6 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Thu, 16 May 2024 15:54:54 +0700 Subject: [PATCH 18/83] refactor: improve framelimit and scenemanager --- Engine/src/Game.cpp | 26 ++++++++++++++++---------- Engine/src/Scenes/SceneManager.cpp | 19 +++++++++++++++++-- Game/src/main.cpp | 5 +++-- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/Engine/src/Game.cpp b/Engine/src/Game.cpp index 9587bcbf..522f5d42 100644 --- a/Engine/src/Game.cpp +++ b/Engine/src/Game.cpp @@ -35,24 +35,30 @@ namespace { IMG_Quit(); } - thread_local double curTick = 0.0; - thread_local double lastTick = 0.0; + thread_local Uint64 curTick = SDL_GetPerformanceCounter(); + thread_local Uint64 lastTick = 0; double FrameLimit(double MaxFrameRate) { - const double targetFrameTime = 1000.0 / MaxFrameRate; + const double targetFrameTime = 1.0 / MaxFrameRate; + const Uint64 targetFrameTicks = static_cast(targetFrameTime * SDL_GetPerformanceFrequency()); - double newTick = SDL_GetTicks(); - double frameTime = newTick - curTick; + Uint64 newTick = SDL_GetPerformanceCounter(); + Uint64 frameTicks = newTick - curTick; - if (frameTime < targetFrameTime) + if (frameTicks < targetFrameTicks) { - double delayTime = targetFrameTime - frameTime; - SDL_Delay(static_cast(delayTime)); - newTick += delayTime; + Uint64 delayTicks = targetFrameTicks - frameTicks; + if (delayTicks > 0) + { + Uint64 delayTime = delayTicks * 1000 / SDL_GetPerformanceFrequency(); + SDL_Delay(static_cast(delayTime)); + newTick = SDL_GetPerformanceCounter(); + frameTicks = newTick - curTick; + } } - double delta = (newTick - curTick) / 1000.0; + double delta = static_cast(frameTicks) / SDL_GetPerformanceFrequency(); lastTick = curTick; curTick = newTick; diff --git a/Engine/src/Scenes/SceneManager.cpp b/Engine/src/Scenes/SceneManager.cpp index c0121a8b..c6c4f7ee 100644 --- a/Engine/src/Scenes/SceneManager.cpp +++ b/Engine/src/Scenes/SceneManager.cpp @@ -40,6 +40,11 @@ SceneManager *SceneManager::s_instance = nullptr; void SceneManager::Update(double delta) { + if (m_ready_change_state) { + std::unique_lock lock(m_mutex); // Lock the mutex + m_cv.wait(lock); // Wait until notified by the scene transition + } + if (m_nextScene != nullptr) { // std::lock_guard lock(m_mutex); if (m_onSceneChange) { @@ -111,6 +116,11 @@ void SceneManager::Update(double delta) void SceneManager::Render(double delta) { + if (m_ready_change_state) { + std::unique_lock lock(m_mutex); // Lock the mutex + m_cv.wait(lock); // Wait until notified by the scene transition + } + if (m_currentScene) m_currentScene->Render(delta); @@ -175,6 +185,11 @@ void SceneManager::Render(double delta) void SceneManager::Input(double delta) { + if (m_ready_change_state) { + std::unique_lock lock(m_mutex); // Lock the mutex + m_cv.wait(lock); // Wait until notified by the scene transition + } + m_inputId = std::this_thread::get_id(); if (m_currentScene) @@ -293,8 +308,8 @@ void SceneManager::IChangeScene(int idx) m_currentSceneId = idx; m_nextScene = m_scenes[idx].get(); - m_ready_change_state = true; - m_cv.notify_one(); + m_ready_change_state = false; + m_cv.notify_all(); } void SceneManager::SetParent(Game *parent) diff --git a/Game/src/main.cpp b/Game/src/main.cpp index dcaaae7c..4d85d939 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -22,8 +22,9 @@ #if _WIN32 extern "C" { -__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; -__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; + __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; + __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; + __declspec(dllexport) int IntelGpuPowerPreference = 1; // for Intel GPUs } #endif From 139af503fedb7528797265c07e105b6c1724ff5d Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Fri, 17 May 2024 15:59:13 +0700 Subject: [PATCH 19/83] fix(texture2d): fixed half white line --- Engine/src/Texture/Texture2D.cpp | 13 ++++++++++--- Game/src/Engine/Note.cpp | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index b5d184da..33adbd77 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -382,7 +382,7 @@ Texture2D *Texture2D::FromPNG(std::string fileName) return nullptr; } -void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) +void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) { if (Renderer::GetInstance()->IsVulkan()) { auto tex_data = vkTexture::TexLoadImage(buffer, size); @@ -399,7 +399,13 @@ void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) if (!decompressed_surface) throw SDLException(); - m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), decompressed_surface); + // Fix Half White Line + SDL_Rect bounds; + SDL_GetClipRect(decompressed_surface, &bounds); + SDL_Surface* extended_surface = SDL_CreateRGBSurfaceWithFormat(0, bounds.w + 1, bounds.h + 1, decompressed_surface->format->BitsPerPixel, decompressed_surface->format->format); + SDL_BlitSurface(decompressed_surface, &bounds, extended_surface, nullptr); + + m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), extended_surface); int w, h; SDL_QueryTexture(m_sdl_tex, nullptr, nullptr, &w, &h); @@ -409,7 +415,8 @@ void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) m_bDisposeTexture = true; m_ready = true; + SDL_FreeSurface(extended_surface); SDL_FreeSurface(decompressed_surface); } delete[] buffer; -} +} \ No newline at end of file diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index d0c660f7..df7b0225 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -211,7 +211,7 @@ void Note::Update(double delta) } } -void Note::Render(double delta) +void Note::Render(double delta) // Code more cleared than before { if (IsRemoveable() || !m_drawAble) return; @@ -238,7 +238,7 @@ void Note::Render(double delta) double bodyPosY = (headPosY + tailPosY) / 2.0; double bodyHeight = std::abs(headPosY - tailPosY); m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY); - m_body->Size = { 1, 0, 0, bodyHeight }; + m_body->Size = { 1, 0, 0, bodyHeight + 1 }; // IDK this cause 1px gap between body and tail, so i had to add more height float transparency = 0.9f; if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { From 339a9c54a9dc2f517f955ed60a8805d9dcd192dd Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Fri, 17 May 2024 18:39:50 +0700 Subject: [PATCH 20/83] --- Engine/src/Texture/Texture2D.cpp | 2 +- Game/src/Engine/Note.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 33adbd77..20d0fbbf 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -402,7 +402,7 @@ void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) // Fix Half White Line SDL_Rect bounds; SDL_GetClipRect(decompressed_surface, &bounds); - SDL_Surface* extended_surface = SDL_CreateRGBSurfaceWithFormat(0, bounds.w + 1, bounds.h + 1, decompressed_surface->format->BitsPerPixel, decompressed_surface->format->format); + SDL_Surface* extended_surface = SDL_CreateRGBSurfaceWithFormat(0, bounds.w , bounds.h, decompressed_surface->format->BitsPerPixel, decompressed_surface->format->format); SDL_BlitSurface(decompressed_surface, &bounds, extended_surface, nullptr); m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), extended_surface); diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index df7b0225..56c28201 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -238,7 +238,7 @@ void Note::Render(double delta) // Code more cleared than before double bodyPosY = (headPosY + tailPosY) / 2.0; double bodyHeight = std::abs(headPosY - tailPosY); m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY); - m_body->Size = { 1, 0, 0, bodyHeight + 1 }; // IDK this cause 1px gap between body and tail, so i had to add more height + m_body->Size = { 1, 0, 0, bodyHeight + 2 }; // IDK this cause 1px gap between body and tail, so i had to add more height float transparency = 0.9f; if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { From 1b6c3642fabba62cbca58b7c1b732ec321291ae0 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sun, 19 May 2024 11:38:35 +0700 Subject: [PATCH 21/83] --- Engine/src/Texture/Texture2D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 20d0fbbf..5a0ecc8d 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -399,7 +399,7 @@ void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) if (!decompressed_surface) throw SDLException(); - // Fix Half White Line + // Fix Half White Line, Slighly Black Pixel on outside but seems not problem SDL_Rect bounds; SDL_GetClipRect(decompressed_surface, &bounds); SDL_Surface* extended_surface = SDL_CreateRGBSurfaceWithFormat(0, bounds.w , bounds.h, decompressed_surface->format->BitsPerPixel, decompressed_surface->format->format); From c034d80555979118eeb6651c4ea167097bd1c6f8 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Sun, 19 May 2024 11:50:32 +0700 Subject: [PATCH 22/83] Revert "" This reverts commit 928fce70f16d23eacdf0f3011b0ab95b1b48b15b. --- Engine/src/Texture/Texture2D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 5a0ecc8d..20d0fbbf 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -399,7 +399,7 @@ void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) if (!decompressed_surface) throw SDLException(); - // Fix Half White Line, Slighly Black Pixel on outside but seems not problem + // Fix Half White Line SDL_Rect bounds; SDL_GetClipRect(decompressed_surface, &bounds); SDL_Surface* extended_surface = SDL_CreateRGBSurfaceWithFormat(0, bounds.w , bounds.h, decompressed_surface->format->BitsPerPixel, decompressed_surface->format->format); From 56058580554b24750967ad4d733df74037b5eac8 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Tue, 21 May 2024 10:08:26 +0700 Subject: [PATCH 23/83] refactor: better approach for white line issues, added game version inside gameplayscene --- Engine/src/Texture/Texture2D.cpp | 32 +++++++++++++++++++++++-------- Game/src/Engine/Note.cpp | 18 +++++++++-------- Game/src/Scenes/GameplayScene.cpp | 11 +++++++++-- Game/src/Scenes/GameplayScene.h | 5 +++++ 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 20d0fbbf..2b4e76b0 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -15,6 +15,28 @@ #include #include +namespace { + SDL_Surface* PremultiplyAlpha(SDL_Surface* surface) { // Fix half white line + if (surface->format->BytesPerPixel != 4) return surface; + + Uint32* pixels = (Uint32*)surface->pixels; + for (int y = 0; y < surface->h; ++y) { + for (int x = 0; x < surface->w; ++x) { + Uint32 pixel = pixels[y * surface->w + x]; + Uint8 r, g, b, a; + SDL_GetRGBA(pixel, surface->format, &r, &g, &b, &a); + + r = r * a / 255; + g = g * a / 255; + b = b * a / 255; + + pixels[y * surface->w + x] = SDL_MapRGBA(surface->format, r, g, b, a); + } + } + return surface; + } +} + Texture2D::Texture2D() { TintColor = { 1.0f, 1.0f, 1.0f }; @@ -392,20 +414,15 @@ void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) m_ready = true; } else { - // Load compressed image data for SDL using ASTC compression SDL_Surface* decompressed_surface = nullptr; SDL_RWops* rw = SDL_RWFromMem(buffer, static_cast(size)); decompressed_surface = IMG_LoadTyped_RW(rw, 1, "ASTC"); if (!decompressed_surface) throw SDLException(); - // Fix Half White Line - SDL_Rect bounds; - SDL_GetClipRect(decompressed_surface, &bounds); - SDL_Surface* extended_surface = SDL_CreateRGBSurfaceWithFormat(0, bounds.w , bounds.h, decompressed_surface->format->BitsPerPixel, decompressed_surface->format->format); - SDL_BlitSurface(decompressed_surface, &bounds, extended_surface, nullptr); + decompressed_surface = PremultiplyAlpha(decompressed_surface); - m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), extended_surface); + m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), decompressed_surface); int w, h; SDL_QueryTexture(m_sdl_tex, nullptr, nullptr, &w, &h); @@ -415,7 +432,6 @@ void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) m_bDisposeTexture = true; m_ready = true; - SDL_FreeSurface(extended_surface); SDL_FreeSurface(decompressed_surface); } delete[] buffer; diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 56c28201..62a838e1 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -206,9 +206,6 @@ void Note::Update(double delta) } } } - if (IsPassed()) { - m_state = NoteState::DO_REMOVE; - } } void Note::Render(double delta) // Code more cleared than before @@ -244,6 +241,11 @@ void Note::Render(double delta) // Code more cleared than before if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { transparency = 1.0f; } + + else if (m_state == NoteState::HOLD_MISSED_ACTIVE) { + transparency = 0.7f; + } + m_body->TintColor = { transparency, transparency, transparency }; m_body->SetIndexAt(m_engine->GetNoteImageIndex()); m_body->Draw(delta, &playRect); @@ -451,7 +453,7 @@ void Note::OnRelease(NoteResult result) if (result == NoteResult::MISS) { //GameAudioSampleCache::Stop(m_keysoundIndex); - m_state = NoteState::DO_REMOVE; + m_state = NoteState::HOLD_MISSED_ACTIVE; m_track->HandleHoldScore(HoldResult::HoldBreak); m_track->HandleScore({ result, @@ -495,14 +497,14 @@ bool Note::IsDrawable() return m_drawAble; } -bool Note::IsRemoveable() +bool Note::IsPassed() { - return m_state == NoteState::DO_REMOVE; + return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED || m_state == NoteState::DO_REMOVE; } -bool Note::IsPassed() +bool Note::IsRemoveable() { - return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED || IsRemoveable(); + return m_state == NoteState::DO_REMOVE; } bool Note::IsHeadHit() diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 9d63aed7..b040920d 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -27,6 +27,7 @@ #include "../GameScenes.h" #define AUTOPLAY_TEXT u8"Game currently on autoplay!" +#define GAMEINFO_TEXT u8"O2Clone Build Date: " __DATE__ " " __TIME__ struct MissInfo { @@ -395,6 +396,9 @@ void GameplayScene::Render(double delta) m_title->Draw(m_game->GetTitle()); + m_gameInfo->Position = m_gameInfoPos; + m_gameInfo->Draw(GAMEINFO_TEXT); + if (m_autoPlay) { m_autoText->Position = m_autoTextPos; m_autoText->Draw(AUTOPLAY_TEXT); @@ -507,11 +511,14 @@ bool GameplayScene::Attach() m_title->AnchorPoint = { TitlePos[0].AnchorPointX, TitlePos[0].AnchorPointY }; m_title->Clip = { RectPos[0].X, RectPos[0].Y, RectPos[0].Width, RectPos[0].Height }; - m_autoText = std::make_unique(13); + m_autoText = std::make_unique(12); m_autoTextSize = m_autoText->CalculateSize(AUTOPLAY_TEXT); - m_autoTextPos = UDim2::fromOffset(GameWindow::GetInstance()->GetBufferWidth(), 50); + m_gameInfo = std::make_unique(8); + m_gameInfoSize = m_gameInfo->CalculateSize(GAMEINFO_TEXT); + m_gameInfoPos = UDim2::fromOffset(/*GameWindow::GetInstance()->GetBufferWidth()*/ 0, GameWindow::GetInstance()->GetBufferHeight() - 10); + m_PlayBG = std::make_unique(arenaPath / ("PlayingBG.png")); auto PlayBGPos = manager->Arena_GetPosition("PlayingBG"); // arena_conf.GetPosition("PlayingBG"); m_PlayBG->Position = UDim2::fromOffset(PlayBGPos[0].X, PlayBGPos[0].Y); diff --git a/Game/src/Scenes/GameplayScene.h b/Game/src/Scenes/GameplayScene.h index d4d20bb3..077de1af 100644 --- a/Game/src/Scenes/GameplayScene.h +++ b/Game/src/Scenes/GameplayScene.h @@ -72,6 +72,7 @@ class GameplayScene : public Scene std::unique_ptr m_title; std::unique_ptr m_autoText; + std::unique_ptr m_gameInfo; std::unique_ptr m_laneHideImage; @@ -114,4 +115,8 @@ class GameplayScene : public Scene bool m_autoPlay; int m_autoTextSize; UDim2 m_autoTextPos; + + /* game info */ + int m_gameInfoSize; + UDim2 m_gameInfoPos; }; \ No newline at end of file From 3b135fd9896011e95e79f624a0ca000411a45ed4 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Tue, 21 May 2024 10:14:30 +0700 Subject: [PATCH 24/83] --- Engine/src/Game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/src/Game.cpp b/Engine/src/Game.cpp index 522f5d42..0916ce3b 100644 --- a/Engine/src/Game.cpp +++ b/Engine/src/Game.cpp @@ -16,7 +16,7 @@ constexpr auto kInputDefaultRate = 1000.0; constexpr auto kMenuDefaultRate = 60.0; -constexpr auto kAudioDefaultRate = 24.0; +constexpr auto kAudioDefaultRate = 60.0; namespace { From 57941c60e821bd737d2555f3c6ac14f673acbe26 Mon Sep 17 00:00:00 2001 From: Albert Frengki Date: Tue, 21 May 2024 10:56:29 +0700 Subject: [PATCH 25/83] --- Game/src/Engine/Note.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 62a838e1..e9b4da61 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -206,6 +206,9 @@ void Note::Update(double delta) } } } + if (IsPassed()) { + m_state = NoteState::DO_REMOVE; + } } void Note::Render(double delta) // Code more cleared than before @@ -242,7 +245,7 @@ void Note::Render(double delta) // Code more cleared than before transparency = 1.0f; } - else if (m_state == NoteState::HOLD_MISSED_ACTIVE) { + else if (m_hitResult >= NoteResult::MISS && m_state == NoteState::HOLD_MISSED_ACTIVE) { transparency = 0.7f; } From 2e6f25a693b072a6c0ac8515311577762a33ec84 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Tue, 21 May 2024 11:05:17 +0700 Subject: [PATCH 26/83] --- Game/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 4d85d939..2afe1b14 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -178,4 +178,4 @@ int main(int argc, char *argv[]) // auto val = lua.GetSprite(SkinGroup::Playing, "JamLogo"); // return 0; -// } \ No newline at end of file +// } From f86a4cfe1eb5983832461f1b4451096545a5a083 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Tue, 21 May 2024 15:21:28 +0700 Subject: [PATCH 27/83] refactor(ojm): add handler for unencoded audio data --- Game/src/Data/OJM.cpp | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/Game/src/Data/OJM.cpp b/Game/src/Data/OJM.cpp index c6a38ced..5b8b9ead 100644 --- a/Game/src/Data/OJM.cpp +++ b/Game/src/Data/OJM.cpp @@ -182,7 +182,7 @@ void OJM::LoadM30Data(std::fstream &fs) fs.read((char *)&Header, sizeof(M30Header)); - for (int i = 0; i < Header.sampleSize; i++) { + for (int i = 0; i < Header.sampleCount; i++) { struct M30SampleHeader { char sampleName[32]; @@ -203,31 +203,37 @@ void OJM::LoadM30Data(std::fstream &fs) uint8_t *buffer = new uint8_t[SampleHeader.sampleSize]; fs.read((char *)buffer, SampleHeader.sampleSize); - switch (Header.encryptionFlag) { - case 0: - break; - case 16: - { - M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_NAMI); - break; - } - case 32: - { - M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_0412); - break; - } + // Handle unencoded audio data + if (Header.encryptionFlag == 0) { + O2Sample sample = {}; + sample.RefValue = SampleHeader.ValueRef; + sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); + Samples.push_back(sample); } + // Handle encoded audio data + else { + switch (Header.encryptionFlag) { + case 16: + M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_NAMI); + break; + case 32: + M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_0412); + break; + default: + break; + } // OGG Sample if (SampleHeader.codecCode == 0) { SampleHeader.ValueRef += 1000; } - O2Sample sample = {}; - sample.RefValue = SampleHeader.ValueRef; - sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); + O2Sample sample = {}; + sample.RefValue = SampleHeader.ValueRef; + sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); + Samples.push_back(sample); + } - Samples.push_back(sample); delete[] buffer; } } From f689accc79e64540f4bb0a4c0ad8476edb6c4d3f Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 22 May 2024 12:58:35 +0700 Subject: [PATCH 28/83] refactor: better solution for half white line issue (2) --- .../src/Rendering/Vulkan/Texture2DVulkan.cpp | 8 + Engine/src/Texture/Texture2D.cpp | 225 ++++++------------ Game/src/Data/OJM.cpp | 2 +- 3 files changed, 86 insertions(+), 149 deletions(-) diff --git a/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp b/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp index 85fb06d7..030fc78f 100644 --- a/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp +++ b/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp @@ -79,6 +79,14 @@ void InternalLoad( size_t image_size = static_cast(tex_data->Width) * static_cast(tex_data->Height) * tex_data->Channels; + // Premultiply alpha + for (size_t i = 0; i < image_size; i += tex_data->Channels) { // Fix white line issue + float alpha = image_data[i + 3] / 255.0f; + image_data[i] *= alpha; + image_data[i + 1] *= alpha; + image_data[i + 2] *= alpha; + } + VkResult err; { VkImageCreateInfo info = {}; diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 2b4e76b0..62c9c692 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #include "../Data/Imgui/imgui_impl_vulkan.h" #include "../Rendering/Vulkan/Texture2DVulkan_Internal.h" @@ -16,7 +19,8 @@ #include namespace { - SDL_Surface* PremultiplyAlpha(SDL_Surface* surface) { // Fix half white line + // Premultiply alpha + SDL_Surface* PremultiplyAlpha(SDL_Surface* surface) { if (surface->format->BytesPerPixel != 4) return surface; Uint32* pixels = (Uint32*)surface->pixels; @@ -26,9 +30,9 @@ namespace { Uint8 r, g, b, a; SDL_GetRGBA(pixel, surface->format, &r, &g, &b, &a); - r = r * a / 255; - g = g * a / 255; - b = b * a / 255; + r = (r * a + 127) / 255; + g = (g * a + 127) / 255; + b = (b * a + 127) / 255; pixels[y * surface->w + x] = SDL_MapRGBA(surface->format, r, g, b, a); } @@ -57,7 +61,8 @@ Texture2D::Texture2D() Size = UDim2::fromScale(1, 1); } -Texture2D::Texture2D(const std::string& fileName) : Texture2D() { +Texture2D::Texture2D(const std::string& fileName) : Texture2D() +{ std::string filePath = fileName; if (!std::filesystem::exists(filePath)) { filePath = std::filesystem::current_path().string() + fileName; @@ -75,11 +80,11 @@ Texture2D::Texture2D(const std::string& fileName) : Texture2D() { size_t size = file.tellg(); file.seekg(0, std::ios::beg); - uint8_t* buffer = new uint8_t[size]; - file.read(reinterpret_cast(buffer), size); + std::vector buffer(size); + file.read(reinterpret_cast(buffer.data()), size); file.close(); - LoadImageResources(buffer, size); + LoadImageResources(buffer.data(), size); } Texture2D::Texture2D(const std::filesystem::path& path) : Texture2D() { @@ -95,24 +100,23 @@ Texture2D::Texture2D(const std::filesystem::path& path) : Texture2D() { size_t size = file.tellg(); file.seekg(0, std::ios::beg); - uint8_t* buffer = new uint8_t[size]; - file.read(reinterpret_cast(buffer), size); + std::vector buffer(size); + file.read(reinterpret_cast(buffer.data()), size); file.close(); - LoadImageResources(buffer, size); + LoadImageResources(buffer.data(), size); } -Texture2D::Texture2D(const uint8_t* fileData, size_t size) : Texture2D() { - uint8_t* buffer = new uint8_t[size]; - std::memcpy(buffer, fileData, size); - LoadImageResources(buffer, size); +Texture2D::Texture2D(const uint8_t* fileData, size_t size) : Texture2D() +{ + std::vector buffer(fileData, fileData + size); + LoadImageResources(buffer.data(), size); } Texture2D::Texture2D(SDL_Texture *texture) : Texture2D() { m_bDisposeTexture = false; m_sdl_tex = texture; - m_ready = true; } @@ -124,7 +128,7 @@ Texture2D::Texture2D(Texture2D_Vulkan *texture) : Texture2D() m_ready = true; } -Texture2D::~Texture2D() +Texture2D::~Texture2D() { if (m_bDisposeTexture) { if (Renderer::GetInstance()->IsVulkan() && m_vk_tex) { @@ -158,11 +162,11 @@ void Texture2D::Draw(Rect *clipRect) Draw(clipRect, true); } -void Texture2D::Draw(Rect *clipRect, bool manualDraw) +void Texture2D::Draw(Rect* clipRect, bool manualDraw) { - Renderer *renderer = Renderer::GetInstance(); - auto window = GameWindow::GetInstance(); - bool scaleOutput = window->IsScaleOutput(); + Renderer* renderer = Renderer::GetInstance(); + auto window = GameWindow::GetInstance(); + bool scaleOutput = window->IsScaleOutput(); CalculateSize(); if (!m_ready) @@ -179,10 +183,10 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) scissor.extent.height = window->GetHeight(); if (clipRect) { - scissor.offset.x = static_cast(clipRect->left * window->GetWidthScale()); - scissor.offset.y = static_cast(clipRect->top * window->GetHeightScale()); - scissor.extent.width = static_cast((clipRect->right - clipRect->left) * window->GetWidthScale()); - scissor.extent.height = static_cast((clipRect->bottom - clipRect->top) * window->GetHeightScale()); + scissor.offset.x = clipRect->left; + scissor.offset.y = clipRect->top; + scissor.extent.width = clipRect->right - clipRect->left; + scissor.extent.height = clipRect->bottom - clipRect->top; } VkDescriptorSet imageId = m_vk_tex->DS; @@ -215,66 +219,41 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) ImVec2 uv3(1.0f, 1.0f); // Bottom-right UV coordinate ImVec2 uv4(0.0f, 1.0f); // Bottom-left UV coordinate - ImU32 color = IM_COL32((uint8_t)(TintColor.R * 255), (uint8_t)(TintColor.G * 255), (uint8_t)(TintColor.B * 255), 255); // Probably fix for Color3 - - std::array vertexData; - - for (int i = 0; i < 6; i++) { - ImDrawVert &vertex = vertexData[i]; - switch (i) { - case 0: - vertex.pos = ImVec2(x1, y1); - vertex.uv = uv1; - break; - case 1: - vertex.pos = ImVec2(x2, y1); - vertex.uv = uv2; - break; - case 2: - vertex.pos = ImVec2(x2, y2); - vertex.uv = uv3; - break; - case 3: - vertex.pos = ImVec2(x1, y1); - vertex.uv = uv1; - break; - case 4: - vertex.pos = ImVec2(x2, y2); - vertex.uv = uv3; - break; - case 5: - vertex.pos = ImVec2(x1, y2); - vertex.uv = uv4; - break; - } - vertex.col = color; - } + ImU32 color = IM_COL32((uint8_t)(TintColor.R * 255), (uint8_t)(TintColor.G * 255), (uint8_t)(TintColor.B * 255), 255); + + std::array vertexData = {{ + {ImVec2(x1, y1), uv1, color}, + {ImVec2(x2, y1), uv2, color}, + {ImVec2(x2, y2), uv3, color}, + {ImVec2(x1, y1), uv1, color}, + {ImVec2(x2, y2), uv3, color}, + {ImVec2(x1, y2), uv4, color} + }}; SubmitQueueInfo info = {}; info.AlphaBlend = AlphaBlend; info.descriptor = imageId; - info.vertices = std::vector(vertexData.begin(), vertexData.end()); - info.indices = { 0, 1, 2, 3, 4, 5 }; + info.vertices = {vertexData.begin(), vertexData.end()}; + info.indices = {0, 1, 2, 3, 4, 5}; info.scissor = scissor; - // submit to queue vulkan_driver->queue_submit(info); } else { - SDL_FRect destRect = { m_calculatedSizeF.left, m_calculatedSizeF.top, m_calculatedSizeF.right, m_calculatedSizeF.bottom }; + SDL_FRect destRect = {m_calculatedSizeF.left, m_calculatedSizeF.top, m_calculatedSizeF.right, m_calculatedSizeF.bottom}; if (scaleOutput) { - destRect.x = std::round(destRect.x * window->GetWidthScale()); - destRect.y = std::round(destRect.y * window->GetHeightScale()); - destRect.w = std::round(destRect.w * window->GetWidthScale()); - destRect.h = std::round(destRect.h * window->GetHeightScale()); + destRect.x *= window->GetWidthScale(); + destRect.y *= window->GetHeightScale(); + destRect.w *= window->GetWidthScale(); + destRect.h *= window->GetHeightScale(); } - SDL_Rect originClip = {}; + SDL_Rect originClip = {}; SDL_BlendMode oldBlendMode = SDL_BLENDMODE_NONE; if (clipRect) { SDL_RenderGetClipRect(renderer->GetSDLRenderer(), &originClip); - SDL_Rect testClip = { clipRect->left, clipRect->top, clipRect->right - clipRect->left, clipRect->bottom - clipRect->top }; + SDL_Rect testClip = {clipRect->left, clipRect->top, clipRect->right - clipRect->left, clipRect->bottom - clipRect->top}; if (scaleOutput) { testClip.x = static_cast(testClip.x * window->GetWidthScale()); testClip.y = static_cast(testClip.y * window->GetHeightScale()); @@ -290,23 +269,15 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) SDL_SetTextureBlendMode(m_sdl_tex, renderer->GetSDLBlendMode()); } - SDL_Color color = { (uint8_t)(TintColor.R * 255.0f), (uint8_t)(TintColor.G * 255.0f), (uint8_t)(TintColor.B * 255.0f), (uint8_t)255 }; + SDL_Color color = {(uint8_t)(TintColor.R * 255.0f), (uint8_t)(TintColor.G * 255.0f), (uint8_t)(TintColor.B * 255.0f), 255}; if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { - color.r = (uint8_t)(TintColor.B * 255.0f); - color.b = (uint8_t)(TintColor.R * 255.0f); + std::swap(color.r, color.b); } SDL_SetTextureColorMod(m_sdl_tex, color.r, color.g, color.b); SDL_SetTextureAlphaMod(m_sdl_tex, static_cast(255 - (Transparency / 100.0) * 255)); - int error = SDL_RenderCopyExF( - renderer->GetSDLRenderer(), - m_sdl_tex, - nullptr, - &destRect, - Rotation, - nullptr, - (SDL_RendererFlip)0); + int error = SDL_RenderCopyExF(renderer->GetSDLRenderer(), m_sdl_tex, nullptr, &destRect, Rotation, nullptr, SDL_FLIP_NONE); if (error != 0) { throw SDLException(); @@ -317,20 +288,16 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) } if (clipRect) { - if (originClip.w == 0 || originClip.h == 0) { - SDL_RenderSetClipRect(renderer->GetSDLRenderer(), nullptr); - } else { - SDL_RenderSetClipRect(renderer->GetSDLRenderer(), &originClip); - } + SDL_RenderSetClipRect(renderer->GetSDLRenderer(), originClip.w == 0 || originClip.h == 0 ? nullptr : &originClip); } } } void Texture2D::CalculateSize() { - GameWindow *window = GameWindow::GetInstance(); - int wWidth = window->GetBufferWidth(); - int wHeight = window->GetBufferHeight(); + GameWindow* window = GameWindow::GetInstance(); + int wWidth = window->GetBufferWidth(); + int wHeight = window->GetBufferHeight(); float xPos = static_cast((wWidth * Position.X.Scale) + Position.X.Offset); float yPos = static_cast((wHeight * Position.Y.Scale) + Position.Y.Offset); @@ -338,8 +305,8 @@ void Texture2D::CalculateSize() float width = static_cast((m_actualSize.right * Size.X.Scale) + Size.X.Offset); float height = static_cast((m_actualSize.bottom * Size.Y.Scale) + Size.Y.Offset); - m_preAnchoredSize = { (LONG)xPos, (LONG)yPos, (LONG)width, (LONG)height }; - m_preAnchoredSizeF = { xPos, yPos, width, height }; + m_preAnchoredSize = {(LONG)xPos, (LONG)yPos, (LONG)width, (LONG)height}; + m_preAnchoredSizeF = {xPos, yPos, width, height}; float xAnchor = width * std::clamp((float)AnchorPoint.X, 0.0f, 1.0f); float yAnchor = height * std::clamp((float)AnchorPoint.Y, 0.0f, 1.0f); @@ -347,11 +314,11 @@ void Texture2D::CalculateSize() xPos -= xAnchor; yPos -= yAnchor; - m_calculatedSize = { (LONG)xPos, (LONG)yPos, (LONG)width, (LONG)height }; - m_calculatedSizeF = { xPos, yPos, width, height }; + m_calculatedSize = {(LONG)xPos, (LONG)yPos, (LONG)width, (LONG)height}; + m_calculatedSizeF = {xPos, yPos, width, height}; - AbsolutePosition = { xPos, yPos }; - AbsoluteSize = { width, height }; + AbsolutePosition = {xPos, yPos}; + AbsoluteSize = {width, height}; } Rect Texture2D::GetOriginalRECT() @@ -364,75 +331,37 @@ void Texture2D::SetOriginalRECT(Rect size) m_actualSize = size; } -//Texture2D *Texture2D::FromTexture2D(Texture2D *tex) -//{ -// auto copy = new Texture2D(tex->m_sdl_tex); -// copy->m_actualSize = tex->m_actualSize; -// copy->Position = tex->Position; -// copy->Size = tex->Size; -// -// return copy; -//} - -Texture2D *Texture2D::FromBMP(uint8_t *fileData, size_t size) -{ - return nullptr; -} - -Texture2D *Texture2D::FromBMP(std::string fileName) -{ - return nullptr; -} - -Texture2D *Texture2D::FromJPEG(uint8_t *fileData, size_t size) -{ - return nullptr; -} - -Texture2D *Texture2D::FromJPEG(std::string fileName) -{ - return nullptr; -} - -Texture2D *Texture2D::FromPNG(uint8_t *fileData, size_t size) -{ - return nullptr; -} - -Texture2D *Texture2D::FromPNG(std::string fileName) -{ - return nullptr; -} - void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) { if (Renderer::GetInstance()->IsVulkan()) { auto tex_data = vkTexture::TexLoadImage(buffer, size); - m_actualSize = { 0, 0, tex_data->Width, tex_data->Height }; + m_actualSize = {0, 0, tex_data->Width, tex_data->Height}; m_vk_tex = tex_data; m_bDisposeTexture = true; m_ready = true; - } - else { - SDL_Surface* decompressed_surface = nullptr; + } else { SDL_RWops* rw = SDL_RWFromMem(buffer, static_cast(size)); - decompressed_surface = IMG_LoadTyped_RW(rw, 1, "ASTC"); + std::unique_ptr decompressed_surface(IMG_LoadTyped_RW(rw, 1, "PNG"), SDL_FreeSurface); - if (!decompressed_surface) throw SDLException(); + if (!decompressed_surface) { + throw SDLException(); + } - decompressed_surface = PremultiplyAlpha(decompressed_surface); + std::unique_ptr formatted_surface(SDL_ConvertSurfaceFormat(decompressed_surface.get(), SDL_PIXELFORMAT_ABGR8888, 0), SDL_FreeSurface); - m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), decompressed_surface); + if (!formatted_surface) { + throw SDLException(); + } - int w, h; - SDL_QueryTexture(m_sdl_tex, nullptr, nullptr, &w, &h); + m_sdl_surface = PremultiplyAlpha(formatted_surface.release()); // Fix white line issue + m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), m_sdl_surface); - m_actualSize = { 0, 0, w, h }; + if (!m_sdl_tex) { + throw SDLException(); + } + m_actualSize = {0, 0, m_sdl_surface->w, m_sdl_surface->h}; m_bDisposeTexture = true; m_ready = true; - - SDL_FreeSurface(decompressed_surface); } - delete[] buffer; } \ No newline at end of file diff --git a/Game/src/Data/OJM.cpp b/Game/src/Data/OJM.cpp index 5b8b9ead..1fa5563c 100644 --- a/Game/src/Data/OJM.cpp +++ b/Game/src/Data/OJM.cpp @@ -182,7 +182,7 @@ void OJM::LoadM30Data(std::fstream &fs) fs.read((char *)&Header, sizeof(M30Header)); - for (int i = 0; i < Header.sampleCount; i++) { + for (int i = 0; i < Header.sampleSize; i++) { struct M30SampleHeader { char sampleName[32]; From 5acf404f1e3e6989a1feaf8773e6c0d13be28e9f Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 22 May 2024 12:44:06 +0700 Subject: [PATCH 29/83] refactor: better solution for half white line issue --- Game/src/Engine/FrameTimer.cpp | 32 ++++++++++++++++---------------- Game/src/Engine/FrameTimer.hpp | 16 ++++++++-------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/Game/src/Engine/FrameTimer.cpp b/Game/src/Engine/FrameTimer.cpp index 77dee001..77e1f41a 100644 --- a/Game/src/Engine/FrameTimer.cpp +++ b/Game/src/Engine/FrameTimer.cpp @@ -13,7 +13,7 @@ FrameTimer::FrameTimer() : { } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer() +FrameTimer::FrameTimer(std::vector> frames) : FrameTimer() { m_frames = std::move(frames); } @@ -21,36 +21,34 @@ FrameTimer::FrameTimer(std::vector frames) : FrameTimer() FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { for (const auto &frame : frames) { - m_frames.emplace_back(new Texture2D(frame)); + m_frames.emplace_back(std::make_shared(frame)); } } FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { for (const auto &frame : frames) { - m_frames.emplace_back(new Texture2D(frame)); + m_frames.emplace_back(std::make_shared(frame)); } } FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { for (const auto &frame : frames) { - m_frames.emplace_back(new Texture2D(frame)); + m_frames.emplace_back(std::make_shared(frame)); } } FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { for (const auto &frame : frames) { - m_frames.emplace_back(new Texture2D(frame)); + m_frames.emplace_back(std::make_shared(frame)); } } FrameTimer::~FrameTimer() { - for (auto &f : m_frames) { - delete f; - } + // The destructor is empty because using shared_ptr } void FrameTimer::Draw(double delta) @@ -109,12 +107,14 @@ void FrameTimer::SetIndexAt(int idx) void FrameTimer::CalculateSize() { - auto &firstFrame = *m_frames[0]; - firstFrame.AnchorPoint = AnchorPoint; - firstFrame.Size = Size; - firstFrame.Position = Position; - firstFrame.CalculateSize(); - - AbsoluteSize = firstFrame.AbsoluteSize; - AbsolutePosition = firstFrame.AbsolutePosition; + if (!m_frames.empty()) { + auto &firstFrame = *m_frames[0]; + firstFrame.AnchorPoint = AnchorPoint; + firstFrame.Size = Size; + firstFrame.Position = Position; + firstFrame.CalculateSize(); + + AbsoluteSize = firstFrame.AbsoluteSize; + AbsolutePosition = firstFrame.AbsolutePosition; + } } diff --git a/Game/src/Engine/FrameTimer.hpp b/Game/src/Engine/FrameTimer.hpp index cd6b4f61..731cad33 100644 --- a/Game/src/Engine/FrameTimer.hpp +++ b/Game/src/Engine/FrameTimer.hpp @@ -16,12 +16,12 @@ class FrameTimer { public: FrameTimer(); - FrameTimer(std::vector frames); + FrameTimer(std::vector> frames); FrameTimer(std::vector frames); FrameTimer(std::vector frames); FrameTimer(std::vector frames); FrameTimer(std::vector frames); - ~FrameTimer(); + virtual ~FrameTimer(); bool Repeat; bool AlphaBlend; @@ -35,7 +35,7 @@ class FrameTimer Vector2 AbsoluteSize; void Draw(double delta); - void Draw(double delta, Rect *clip); + void Draw(double delta, Rect* clip); void SetFPS(double fps); void ResetIndex(); void LastIndex(); @@ -43,10 +43,10 @@ class FrameTimer void CalculateSize(); - std::vector m_frames; + std::vector> m_frames; protected: - int m_currentFrame; - double m_frameTime; - double m_currentTime; -}; \ No newline at end of file + size_t m_currentFrame; + double m_frameTime; + double m_currentTime; +}; From 3c77949d2954bb420c517a26bca439409dce7289 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 22 May 2024 14:38:27 +0700 Subject: [PATCH 30/83] --- Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp | 6 +++--- Game/src/Engine/Note.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp b/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp index 030fc78f..414790f8 100644 --- a/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp +++ b/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp @@ -82,9 +82,9 @@ void InternalLoad( // Premultiply alpha for (size_t i = 0; i < image_size; i += tex_data->Channels) { // Fix white line issue float alpha = image_data[i + 3] / 255.0f; - image_data[i] *= alpha; - image_data[i + 1] *= alpha; - image_data[i + 2] *= alpha; + image_data[i] = static_cast(image_data[i] * alpha); + image_data[i + 1] = static_cast(image_data[i + 1] * alpha); + image_data[i + 2] = static_cast(image_data[i + 2] * alpha); } VkResult err; diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index e9b4da61..0c4949a8 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -238,7 +238,7 @@ void Note::Render(double delta) // Code more cleared than before double bodyPosY = (headPosY + tailPosY) / 2.0; double bodyHeight = std::abs(headPosY - tailPosY); m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY); - m_body->Size = { 1, 0, 0, bodyHeight + 2 }; // IDK this cause 1px gap between body and tail, so i had to add more height + m_body->Size = { 1, 0, 0, bodyHeight }; float transparency = 0.9f; if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { From bb787ac279363f335e369a2e5824156c519745e1 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 22 May 2024 15:24:58 +0700 Subject: [PATCH 31/83] refactor(ojm): fix no sound in few OJM --- Game/src/Data/OJM.cpp | 38 ++++++++++++++------------------------ 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/Game/src/Data/OJM.cpp b/Game/src/Data/OJM.cpp index 1fa5563c..9978f40e 100644 --- a/Game/src/Data/OJM.cpp +++ b/Game/src/Data/OJM.cpp @@ -182,7 +182,7 @@ void OJM::LoadM30Data(std::fstream &fs) fs.read((char *)&Header, sizeof(M30Header)); - for (int i = 0; i < Header.sampleSize; i++) { + for (int i = 0; i < Header.sampleCount; i++) { // This fix no sound in few OJM struct M30SampleHeader { char sampleName[32]; @@ -203,37 +203,27 @@ void OJM::LoadM30Data(std::fstream &fs) uint8_t *buffer = new uint8_t[SampleHeader.sampleSize]; fs.read((char *)buffer, SampleHeader.sampleSize); - // Handle unencoded audio data - if (Header.encryptionFlag == 0) { - O2Sample sample = {}; - sample.RefValue = SampleHeader.ValueRef; - sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); - Samples.push_back(sample); + switch (Header.encryptionFlag) { + case 0: + break; + case 16: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_NAMI); + break; + case 32: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_0412); + break; } - // Handle encoded audio data - else { - switch (Header.encryptionFlag) { - case 16: - M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_NAMI); - break; - case 32: - M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_0412); - break; - default: - break; - } // OGG Sample if (SampleHeader.codecCode == 0) { SampleHeader.ValueRef += 1000; } - O2Sample sample = {}; - sample.RefValue = SampleHeader.ValueRef; - sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); - Samples.push_back(sample); - } + O2Sample sample = {}; + sample.RefValue = SampleHeader.ValueRef; + sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); + Samples.push_back(sample); delete[] buffer; } } From 93fa47924ef0bf20c8752b30f05cf7389059c3f7 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 22 May 2024 15:13:29 +0700 Subject: [PATCH 32/83] added comment --- Game/src/Data/OJM.cpp | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/Game/src/Data/OJM.cpp b/Game/src/Data/OJM.cpp index 9978f40e..a86d6a2a 100644 --- a/Game/src/Data/OJM.cpp +++ b/Game/src/Data/OJM.cpp @@ -182,7 +182,7 @@ void OJM::LoadM30Data(std::fstream &fs) fs.read((char *)&Header, sizeof(M30Header)); - for (int i = 0; i < Header.sampleCount; i++) { // This fix no sound in few OJM + for (int i = 0; i < Header.sampleSize; i++) { struct M30SampleHeader { char sampleName[32]; @@ -203,27 +203,37 @@ void OJM::LoadM30Data(std::fstream &fs) uint8_t *buffer = new uint8_t[SampleHeader.sampleSize]; fs.read((char *)buffer, SampleHeader.sampleSize); - switch (Header.encryptionFlag) { - case 0: - break; - case 16: - M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_NAMI); - break; - case 32: - M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_0412); - break; + // Handle unencoded audio data + if (Header.encryptionFlag == 0) { // Skip if not encrypted just processing straight + O2Sample sample = {}; + sample.RefValue = SampleHeader.ValueRef; + sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); + Samples.push_back(sample); } + // Handle encoded audio data + else { + switch (Header.encryptionFlag) { + case 16: + M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_NAMI); + break; + case 32: + M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_0412); + break; + default: + break; + } // OGG Sample if (SampleHeader.codecCode == 0) { SampleHeader.ValueRef += 1000; } - O2Sample sample = {}; - sample.RefValue = SampleHeader.ValueRef; - sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); + O2Sample sample = {}; // Process data that decrypted + sample.RefValue = SampleHeader.ValueRef; + sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); + Samples.push_back(sample); + } - Samples.push_back(sample); delete[] buffer; } } From cab75a70dc24534537431347b2baca00fb0a649c Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 22 May 2024 15:36:03 +0700 Subject: [PATCH 33/83] --- Engine/src/Texture/Texture2D.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index 62c9c692..90570193 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -30,9 +30,9 @@ namespace { Uint8 r, g, b, a; SDL_GetRGBA(pixel, surface->format, &r, &g, &b, &a); - r = (r * a + 127) / 255; - g = (g * a + 127) / 255; - b = (b * a + 127) / 255; + r = (r * a) / 255; + g = (g * a) / 255; + b = (b * a) / 255; pixels[y * surface->w + x] = SDL_MapRGBA(surface->format, r, g, b, a); } From 7e566b763a6739b62331aa3029afbbb61320e14f Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Thu, 23 May 2024 14:44:46 +0700 Subject: [PATCH 34/83] refactor(ojm): game now can read the other mask ojm files --- Game/src/Data/OJM.cpp | 62 +++++++++++++++++-------------- Game/src/Engine/Note.cpp | 8 +--- Game/src/Scenes/GameplayScene.cpp | 4 ++ Game/src/main.cpp | 6 +-- 4 files changed, 42 insertions(+), 38 deletions(-) diff --git a/Game/src/Data/OJM.cpp b/Game/src/Data/OJM.cpp index a86d6a2a..1d8b654a 100644 --- a/Game/src/Data/OJM.cpp +++ b/Game/src/Data/OJM.cpp @@ -9,16 +9,20 @@ constexpr int kM30Signature = 0x0030334D; constexpr int kOMCSignature = 0x00434D4F; constexpr int kOJMSignature = 0x004D4A4F; +const char MASK_SCRAMBLE1[] = { 0x73, 0x63, 0x72, 0x61, 0x6D, 0x62, 0x6C, 0x65, 0x31 }; +const char MASK_SCRAMBLE2[] = { 0x73, 0x63, 0x72, 0x61, 0x6D, 0x62, 0x6C, 0x65, 0x32 }; +const char MASK_DECODE[] = { 0x64, 0x65, 0x63, 0x6F, 0x64, 0x65 }; +const char MASK_DECRYPT[] = { 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74 }; const char MASK_NAMI[] = { 0x6E, 0x61, 0x6D, 0x69 }; const char MASK_0412[] = { 0x30, 0x34, 0x31, 0x32 }; void M30Xor(char *data, size_t sz, const char *xorKey) { for (int i = 0; i + 3 < sz; i += 4) { - data[i] ^= xorKey[0]; - data[i + 1] ^= xorKey[1]; - data[i + 2] ^= xorKey[2]; - data[i + 3] ^= xorKey[3]; + data[i] ^= xorKey[i % 4]; + data[i + 1] ^= xorKey[(i + 1) % 4]; + data[i + 2] ^= xorKey[(i + 2) % 4]; + data[i + 3] ^= xorKey[(i + 3) % 4]; } } @@ -182,7 +186,7 @@ void OJM::LoadM30Data(std::fstream &fs) fs.read((char *)&Header, sizeof(M30Header)); - for (int i = 0; i < Header.sampleSize; i++) { + for (int i = 0; i < Header.sampleCount; i++) { // This fix no sound in few OJM struct M30SampleHeader { char sampleName[32]; @@ -203,37 +207,39 @@ void OJM::LoadM30Data(std::fstream &fs) uint8_t *buffer = new uint8_t[SampleHeader.sampleSize]; fs.read((char *)buffer, SampleHeader.sampleSize); - // Handle unencoded audio data - if (Header.encryptionFlag == 0) { // Skip if not encrypted just processing straight - O2Sample sample = {}; - sample.RefValue = SampleHeader.ValueRef; - sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); - Samples.push_back(sample); + switch (Header.encryptionFlag) { + case 0: + break; + case 1: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_SCRAMBLE1); + break; + case 2: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_SCRAMBLE2); + break; + case 4: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_DECODE); + break; + case 8: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_DECRYPT); + break; + case 16: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_NAMI); + break; + case 32: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_0412); + break; } - // Handle encoded audio data - else { - switch (Header.encryptionFlag) { - case 16: - M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_NAMI); - break; - case 32: - M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_0412); - break; - default: - break; - } // OGG Sample if (SampleHeader.codecCode == 0) { SampleHeader.ValueRef += 1000; } - O2Sample sample = {}; // Process data that decrypted - sample.RefValue = SampleHeader.ValueRef; - sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); - Samples.push_back(sample); - } + O2Sample sample = {}; + sample.RefValue = SampleHeader.ValueRef; + sample.AudioData.insert(sample.AudioData.end(), buffer, buffer + SampleHeader.sampleSize); + Samples.push_back(sample); delete[] buffer; } } diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 0c4949a8..41dfdf41 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -169,7 +169,6 @@ void Note::Update(double delta) m_hitPos = m_startTime + m_hitTime; OnHit(NoteResult::MISS); } - m_state = NoteState::DO_REMOVE; } } else { @@ -201,14 +200,9 @@ void Note::Update(double delta) OnRelease(NoteResult::MISS); } } - - m_state = NoteState::DO_REMOVE; } } } - if (IsPassed()) { - m_state = NoteState::DO_REMOVE; - } } void Note::Render(double delta) // Code more cleared than before @@ -502,7 +496,7 @@ bool Note::IsDrawable() bool Note::IsPassed() { - return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED || m_state == NoteState::DO_REMOVE; + return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED; } bool Note::IsRemoveable() diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index b040920d..3c2178ca 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -80,6 +80,8 @@ void GameplayScene::Update(double delta) if (m_game->GetState() == GameState::PosGame && !m_ended) { m_counter += delta; + m_drawExitButton = false; + m_doExit = false; m_minuteNum->DrawNumber(0); m_secondNum->DrawNumber(0); @@ -97,6 +99,8 @@ void GameplayScene::Update(double delta) float health = m_game->GetScoreManager()->GetLife(); if (health <= 0) { + m_drawExitButton = false; + m_doExit = false; m_game->Stop(); EnvironmentSetup::SetInt("Failed", 1); } diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 2afe1b14..595b4916 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -22,9 +22,9 @@ #if _WIN32 extern "C" { - __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; - __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; - __declspec(dllexport) int IntelGpuPowerPreference = 1; // for Intel GPUs + __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; + __declspec(dllexport) DWORD IntelGpuPowerPreference = 0x00000003; } #endif From 88c4cb125df34b7d78566814df741aa6630a319d Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 24 May 2024 11:26:39 +0700 Subject: [PATCH 35/83] refactor: fix everything --- Engine/include/Texture/Sprite2D.h | 2 + Engine/src/Game.cpp | 29 +++++------ Engine/src/Texture/Sprite2D.cpp | 84 +++++++------------------------ Game/src/Engine/FrameTimer.cpp | 50 +++++++++--------- Game/src/Engine/FrameTimer.hpp | 18 +++---- Game/src/Engine/Note.cpp | 17 +++++-- 6 files changed, 80 insertions(+), 120 deletions(-) diff --git a/Engine/include/Texture/Sprite2D.h b/Engine/include/Texture/Sprite2D.h index 2c3ae760..55025cdf 100644 --- a/Engine/include/Texture/Sprite2D.h +++ b/Engine/include/Texture/Sprite2D.h @@ -49,4 +49,6 @@ class Sprite2D bool m_drawOnce = false; std::vector m_textures; + + void DrawInternal(double delta, bool playOnce, Rect* rect, bool manual); }; diff --git a/Engine/src/Game.cpp b/Engine/src/Game.cpp index 0916ce3b..87ac8aa3 100644 --- a/Engine/src/Game.cpp +++ b/Engine/src/Game.cpp @@ -35,30 +35,27 @@ namespace { IMG_Quit(); } - thread_local Uint64 curTick = SDL_GetPerformanceCounter(); - thread_local Uint64 lastTick = 0; + using namespace std::chrono; + + thread_local high_resolution_clock::time_point curTick = high_resolution_clock::now(); + thread_local high_resolution_clock::time_point lastTick = high_resolution_clock::now(); double FrameLimit(double MaxFrameRate) { - const double targetFrameTime = 1.0 / MaxFrameRate; - const Uint64 targetFrameTicks = static_cast(targetFrameTime * SDL_GetPerformanceFrequency()); + const double targetFrameTime = 1000.0 / MaxFrameRate; + - Uint64 newTick = SDL_GetPerformanceCounter(); - Uint64 frameTicks = newTick - curTick; + auto newTick = high_resolution_clock::now(); + auto frameTime = duration_cast(newTick - curTick).count() / 1000.0; - if (frameTicks < targetFrameTicks) + if (frameTime < targetFrameTime) { - Uint64 delayTicks = targetFrameTicks - frameTicks; - if (delayTicks > 0) - { - Uint64 delayTime = delayTicks * 1000 / SDL_GetPerformanceFrequency(); - SDL_Delay(static_cast(delayTime)); - newTick = SDL_GetPerformanceCounter(); - frameTicks = newTick - curTick; - } + auto delayTime = duration(targetFrameTime - frameTime); + std::this_thread::sleep_for(delayTime); + newTick += duration_cast(delayTime); } - double delta = static_cast(frameTicks) / SDL_GetPerformanceFrequency(); + double delta = duration_cast(newTick - curTick).count() / 1000000.0; lastTick = curTick; curTick = newTick; diff --git a/Engine/src/Texture/Sprite2D.cpp b/Engine/src/Texture/Sprite2D.cpp index e9d29c33..0c861321 100644 --- a/Engine/src/Texture/Sprite2D.cpp +++ b/Engine/src/Texture/Sprite2D.cpp @@ -64,38 +64,13 @@ void Sprite2D::Draw(double delta, bool manual) Draw(delta, nullptr, manual); } -void Sprite2D::Draw(double delta, Rect *rect, bool manual) // Original code, play image sprite loop +void Sprite2D::DrawInternal(double delta, bool playOnce, Rect* rect, bool manual) { - auto tex = m_textures[m_currentIndex]; - GameWindow *window = GameWindow::GetInstance(); - - double xPos = (window->GetBufferWidth() * Position.X.Scale) + (Position.X.Offset); - double yPos = (window->GetBufferHeight() * Position.Y.Scale) + (Position.Y.Offset); - - double xMPos = (window->GetBufferWidth() * Position2.X.Scale) + (Position2.X.Offset); - double yMPos = (window->GetBufferHeight() * Position2.Y.Scale) + (Position2.Y.Offset); - - xPos += xMPos; - yPos += yMPos; - - tex->Position = UDim2::fromOffset(xPos, yPos); - tex->AlphaBlend = AlphaBlend; - tex->Size = Size; - tex->AnchorPoint = AnchorPoint; - tex->Draw(rect, manual ? false : true); - - if (m_spritespeed > 0.0) { - m_currentTime += static_cast(delta); - if (m_currentTime >= m_spritespeed) { - m_currentTime = 0.0; - m_currentIndex = (m_currentIndex + 1) % m_textures.size(); - } - } -} - -void Sprite2D::DrawOnce(double delta, bool manual) { // Play whole image sprite once if (m_currentIndex >= m_textures.size()) { - return; + if (playOnce) { + return; // Stop if playing once and reached end + } + m_currentIndex = 0; // Reset index if looping } auto tex = m_textures[m_currentIndex]; @@ -114,7 +89,7 @@ void Sprite2D::DrawOnce(double delta, bool manual) { // Play whole image sprite tex->AlphaBlend = AlphaBlend; tex->Size = Size; tex->AnchorPoint = AnchorPoint; - tex->Draw(); + tex->Draw(rect, manual ? false : true); if (m_spritespeed > 0.0) { m_currentTime += static_cast(delta); @@ -122,47 +97,26 @@ void Sprite2D::DrawOnce(double delta, bool manual) { // Play whole image sprite m_currentTime = 0.0; m_currentIndex++; - if (m_currentIndex == m_textures.size() && m_drawOnce) { - return; + if (playOnce && m_currentIndex == m_textures.size()) { + return; // Stop if playing once and reached end } } } } -void Sprite2D::DrawStop(double delta, bool manual) { // Play image sprite once and stop on last frame - if (m_currentIndex >= m_textures.size()) { - m_currentIndex = static_cast(m_textures.size()) - 1; - } - - auto tex = m_textures[m_currentIndex]; - GameWindow* window = GameWindow::GetInstance(); - - double xPos = (window->GetBufferWidth() * Position.X.Scale) + (Position.X.Offset); - double yPos = (window->GetBufferHeight() * Position.Y.Scale) + (Position.Y.Offset); - - double xMPos = (window->GetBufferWidth() * Position2.X.Scale) + (Position2.X.Offset); - double yMPos = (window->GetBufferHeight() * Position2.Y.Scale) + (Position2.Y.Offset); - - xPos += xMPos; - yPos += yMPos; - - tex->Position = UDim2::fromOffset(xPos, yPos); - tex->AlphaBlend = AlphaBlend; - tex->Size = Size; - tex->AnchorPoint = AnchorPoint; - tex->Draw(); +void Sprite2D::Draw(double delta, Rect* rect, bool manual) +{ + DrawInternal(delta, false, rect, manual); // Play loop +} - if (m_spritespeed > 0.0) { - m_currentTime += static_cast(delta); - if (m_currentTime >= m_spritespeed) { - m_currentTime = 0.0; - m_currentIndex++; +void Sprite2D::DrawOnce(double delta, bool manual) +{ + DrawInternal(delta, true, nullptr, manual); // Play once +} - if (m_currentIndex == m_textures.size() && m_drawOnce) { - return; - } - } - } +void Sprite2D::DrawStop(double delta, bool manual) +{ + DrawInternal(delta, true, nullptr, manual); // Play once } diff --git a/Game/src/Engine/FrameTimer.cpp b/Game/src/Engine/FrameTimer.cpp index 77e1f41a..1d938bc3 100644 --- a/Game/src/Engine/FrameTimer.cpp +++ b/Game/src/Engine/FrameTimer.cpp @@ -9,46 +9,48 @@ FrameTimer::FrameTimer() : m_currentTime(0), AlphaBlend(false), Size(UDim2::fromScale(1, 1)), - TintColor({1.0f, 1.0f, 1.0f}) + TintColor({ 1.0f, 1.0f, 1.0f }) { } -FrameTimer::FrameTimer(std::vector> frames) : FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { m_frames = std::move(frames); } FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - for (const auto &frame : frames) { - m_frames.emplace_back(std::make_shared(frame)); + for (const auto& frame : frames) { + m_frames.emplace_back(new Texture2D(frame)); } } FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - for (const auto &frame : frames) { - m_frames.emplace_back(std::make_shared(frame)); + for (const auto& frame : frames) { + m_frames.emplace_back(new Texture2D(frame)); } } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - for (const auto &frame : frames) { - m_frames.emplace_back(std::make_shared(frame)); + for (const auto& frame : frames) { + m_frames.emplace_back(new Texture2D(frame)); } } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - for (const auto &frame : frames) { - m_frames.emplace_back(std::make_shared(frame)); + for (const auto& frame : frames) { + m_frames.emplace_back(new Texture2D(frame)); } } FrameTimer::~FrameTimer() { - // The destructor is empty because using shared_ptr + for (auto& f : m_frames) { + delete f; + } } void FrameTimer::Draw(double delta) @@ -56,7 +58,7 @@ void FrameTimer::Draw(double delta) Draw(delta, nullptr); } -void FrameTimer::Draw(double delta, Rect *clip) +void FrameTimer::Draw(double delta, Rect* clip) { m_currentTime += delta; @@ -78,7 +80,7 @@ void FrameTimer::Draw(double delta, Rect *clip) if (m_currentFrame != 0) { currentFrame->Position = UDim2::fromOffset(AbsolutePosition.X, AbsolutePosition.Y); currentFrame->Size = UDim2::fromOffset(AbsoluteSize.X, AbsoluteSize.Y); - currentFrame->AnchorPoint = {0, 0}; + currentFrame->AnchorPoint = { 0, 0 }; } currentFrame->Draw(clip); @@ -107,14 +109,12 @@ void FrameTimer::SetIndexAt(int idx) void FrameTimer::CalculateSize() { - if (!m_frames.empty()) { - auto &firstFrame = *m_frames[0]; - firstFrame.AnchorPoint = AnchorPoint; - firstFrame.Size = Size; - firstFrame.Position = Position; - firstFrame.CalculateSize(); - - AbsoluteSize = firstFrame.AbsoluteSize; - AbsolutePosition = firstFrame.AbsolutePosition; - } + auto& firstFrame = *m_frames[0]; + firstFrame.AnchorPoint = AnchorPoint; + firstFrame.Size = Size; + firstFrame.Position = Position; + firstFrame.CalculateSize(); + + AbsoluteSize = firstFrame.AbsoluteSize; + AbsolutePosition = firstFrame.AbsolutePosition; } diff --git a/Game/src/Engine/FrameTimer.hpp b/Game/src/Engine/FrameTimer.hpp index 731cad33..b8846be7 100644 --- a/Game/src/Engine/FrameTimer.hpp +++ b/Game/src/Engine/FrameTimer.hpp @@ -16,12 +16,12 @@ class FrameTimer { public: FrameTimer(); - FrameTimer(std::vector> frames); + FrameTimer(std::vector frames); FrameTimer(std::vector frames); FrameTimer(std::vector frames); - FrameTimer(std::vector frames); - FrameTimer(std::vector frames); - virtual ~FrameTimer(); + FrameTimer(std::vector frames); + FrameTimer(std::vector frames); + ~FrameTimer(); bool Repeat; bool AlphaBlend; @@ -43,10 +43,10 @@ class FrameTimer void CalculateSize(); - std::vector> m_frames; + std::vector m_frames; protected: - size_t m_currentFrame; - double m_frameTime; - double m_currentTime; -}; + int m_currentFrame; + double m_frameTime; + double m_currentTime; +}; \ No newline at end of file diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 41dfdf41..b88c73ea 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -169,6 +169,7 @@ void Note::Update(double delta) m_hitPos = m_startTime + m_hitTime; OnHit(NoteResult::MISS); } + m_state = NoteState::DO_REMOVE; } } else { @@ -200,6 +201,8 @@ void Note::Update(double delta) OnRelease(NoteResult::MISS); } } + + m_state = NoteState::DO_REMOVE; } } } @@ -207,8 +210,12 @@ void Note::Update(double delta) void Note::Render(double delta) // Code more cleared than before { - if (IsRemoveable() || !m_drawAble) + if (IsRemoveable()) { + return; + } + if (!m_drawAble) { return; + } auto resolution = m_engine->GetResolution(); auto hitPos = m_engine->GetHitPosition(); @@ -494,14 +501,14 @@ bool Note::IsDrawable() return m_drawAble; } -bool Note::IsPassed() +bool Note::IsRemoveable() { - return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED; + return m_state == NoteState::DO_REMOVE; } -bool Note::IsRemoveable() +bool Note::IsPassed() { - return m_state == NoteState::DO_REMOVE; + return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED || IsRemoveable(); } bool Note::IsHeadHit() From a5f61da9baea602e4599300f5b8fb7c594292596 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 24 May 2024 15:05:36 +0700 Subject: [PATCH 36/83] refactor: fix everything (2) --- Game/src/Engine/Note.cpp | 34 ++++++++++++++++++++++++------- Game/src/Engine/RhythmEngine.cpp | 10 +++++---- Game/src/Engine/ScoreManager.cpp | 10 +++++++++ Game/src/EnvironmentSetup.cpp | 13 +++++++++++- Game/src/Scenes/GameplayScene.cpp | 10 +++++---- 5 files changed, 61 insertions(+), 16 deletions(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index b88c73ea..3c7c42b5 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -356,27 +356,39 @@ std::tuple Note::CheckHit() if (m_type == NoteType::NORMAL) { double time_to_end = m_engine->GetGameAudioPosition() - m_startTime; - auto result = judge->CalculateResult(this); + auto result = judge->CalculateResult(this); if (std::get(result)) { m_ignore = false; } + else if (time_to_end) { + m_ignore = true; + } return result; - } else { + m_state = NoteState::DO_REMOVE; + } + else { if (m_state == NoteState::HOLD_PRE) { double time_to_end = m_engine->GetGameAudioPosition() - m_startTime; - auto result = judge->CalculateResult(this); + auto result = judge->CalculateResult(this); if (std::get(result)) { m_ignore = false; } + else if (time_to_end) { + m_ignore = true; + } return result; - } else if (m_state == NoteState::HOLD_MISSED_ACTIVE) { + } + else if (m_state == NoteState::HOLD_MISSED_ACTIVE) { double time_to_end = m_engine->GetGameAudioPosition() - m_endTime; - auto result = judge->CalculateResult(this); + auto result = judge->CalculateResult(this); if (std::get(result)) { m_ignore = false; } + else if (time_to_end) { + m_ignore = true; + } return result; } @@ -388,7 +400,7 @@ std::tuple Note::CheckHit() std::tuple Note::CheckRelease() { if (m_type == NoteType::HOLD) { - double time_to_end = m_engine->GetGameAudioPosition() - m_endTime; + double time_to_end = m_engine->GetGameAudioPosition() - m_endTime; JudgeBase *judge = m_engine->GetJudge(); if (m_state == NoteState::HOLD_ON_HOLDING || m_state == NoteState::HOLD_MISSED_ACTIVE) { @@ -396,6 +408,7 @@ std::tuple Note::CheckRelease() if (std::get(result)) { if (m_state == NoteState::HOLD_MISSED_ACTIVE) { + m_ignore = false; return { true, NoteResult::BAD }; } @@ -403,8 +416,15 @@ std::tuple Note::CheckRelease() } if (m_state == NoteState::HOLD_ON_HOLDING) { + if (time_to_end) { + m_ignore = true; + } return { true, NoteResult::MISS }; - } else { + } + else { + if (time_to_end) { + m_ignore = true; + } return { false, NoteResult::MISS }; } } diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index b5c4dcc2..00b20081 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -326,6 +326,7 @@ void RhythmEngine::SetKeys(Keys *keys) bool RhythmEngine::Start() { // no, use update event instead + EnvironmentSetup::SetInt("NowPlaying", 1); m_currentAudioPosition -= 5000; m_state = GameState::Playing; //m_startClock = std::chrono::system_clock::now(); @@ -334,10 +335,11 @@ bool RhythmEngine::Start() bool RhythmEngine::Stop() { + EnvironmentSetup::SetInt("NowPlaying", 0); m_state = GameState::PosGame; GameAudioSampleCache::StopAll(); - return true; m_PlayTime = 0.0; + return true; } bool RhythmEngine::Ready() @@ -442,13 +444,13 @@ void RhythmEngine::Render(double delta) void RhythmEngine::Input(double delta) { - if (m_state == GameState::NotGame || m_state == GameState::PosGame) + if (m_state == GameState::NotGame) return; } void RhythmEngine::OnKeyDown(const KeyState &state) { - if (m_state == GameState::NotGame || m_state == GameState::PosGame) + if (m_state == GameState::NotGame) return; if (state.key == Keys::F3) { @@ -472,7 +474,7 @@ void RhythmEngine::OnKeyDown(const KeyState &state) void RhythmEngine::OnKeyUp(const KeyState &state) { - if (m_state == GameState::NotGame || m_state == GameState::PosGame) + if (m_state == GameState::NotGame) return; if (!m_is_autoplay) { diff --git a/Game/src/Engine/ScoreManager.cpp b/Game/src/Engine/ScoreManager.cpp index f63cac49..e34b2350 100644 --- a/Game/src/Engine/ScoreManager.cpp +++ b/Game/src/Engine/ScoreManager.cpp @@ -34,6 +34,11 @@ ScoreManager::~ScoreManager() void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 and divided that by 10 { + bool IsPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; + if (!IsPlaying) { + return; + } + int difficulty = EnvironmentSetup::GetInt("Difficulty"); switch (difficulty) { case 0: // Easy @@ -208,6 +213,11 @@ void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 a void ScoreManager::OnLongNoteHold(HoldResult result) { + bool IsPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; + if (!IsPlaying) { + return; + } + switch (result) { case HoldResult::HoldBreak: { diff --git a/Game/src/EnvironmentSetup.cpp b/Game/src/EnvironmentSetup.cpp index 9be0e8af..7aa320d5 100644 --- a/Game/src/EnvironmentSetup.cpp +++ b/Game/src/EnvironmentSetup.cpp @@ -1,15 +1,18 @@ #include "EnvironmentSetup.hpp" #include +#include namespace { std::unordered_map m_stores; std::unordered_map m_storesPtr; std::unordered_map m_paths; std::unordered_map m_ints; + std::mutex m_mutex; } // namespace void EnvironmentSetup::OnExitCheck() { + std::lock_guard lock(m_mutex); m_stores.clear(); m_paths.clear(); m_ints.clear(); @@ -17,11 +20,13 @@ void EnvironmentSetup::OnExitCheck() void EnvironmentSetup::Set(std::string key, std::string value) { + std::lock_guard lock(m_mutex); m_stores[key] = std::move(value); } std::string EnvironmentSetup::Get(std::string key) { + std::lock_guard lock(m_mutex); auto it = m_stores.find(key); if (it != m_stores.end()) { return it->second; @@ -31,11 +36,13 @@ std::string EnvironmentSetup::Get(std::string key) void EnvironmentSetup::SetObj(std::string key, void* ptr) { + std::lock_guard lock(m_mutex); m_storesPtr[key] = ptr; } void* EnvironmentSetup::GetObj(std::string key) { + std::lock_guard lock(m_mutex); auto it = m_storesPtr.find(key); if (it != m_storesPtr.end()) { return it->second; @@ -45,11 +52,13 @@ void* EnvironmentSetup::GetObj(std::string key) void EnvironmentSetup::SetPath(std::string key, std::filesystem::path path) { + std::lock_guard lock(m_mutex); m_paths[key] = std::move(path); } std::filesystem::path EnvironmentSetup::GetPath(std::string key) { + std::lock_guard lock(m_mutex); auto it = m_paths.find(key); if (it != m_paths.end()) { return it->second; @@ -59,14 +68,16 @@ std::filesystem::path EnvironmentSetup::GetPath(std::string key) void EnvironmentSetup::SetInt(std::string key, int value) { + std::lock_guard lock(m_mutex); m_ints[key] = value; } int EnvironmentSetup::GetInt(std::string key) { + std::lock_guard lock(m_mutex); auto it = m_ints.find(key); if (it != m_ints.end()) { return it->second; } return 0; -} \ No newline at end of file +} diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 3c2178ca..a7aa2111 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -386,11 +386,13 @@ void GameplayScene::Render(double delta) m_minuteNum->DrawNumber(currentMinutes); m_secondNum->DrawNumber(currentSeconds); - for (int i = 0; i < 7; i++) { - m_hitEffect[i]->Draw(delta); + if (EnvironmentSetup::GetInt("NowPlaying") == 1) { + for (int i = 0; i < 7; i++) { + m_hitEffect[i]->Draw(delta); - if (m_drawHold[i]) { - m_holdEffect[i]->Draw(delta); + if (m_drawHold[i]) { + m_holdEffect[i]->Draw(delta); + } } } From bf00f6b374ce065d01d9d66c40135a1f8e5edaeb Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 24 May 2024 15:23:57 +0700 Subject: [PATCH 37/83] --- Game/src/Engine/Note.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 3c7c42b5..2c796d22 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -365,7 +365,6 @@ std::tuple Note::CheckHit() } return result; - m_state = NoteState::DO_REMOVE; } else { if (m_state == NoteState::HOLD_PRE) { From 23cddeb24ef03e55d5e4b7779eb97e87fed43d29 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 24 May 2024 21:42:22 +0700 Subject: [PATCH 38/83] refactor(sprite2d): fix for drawstop --- Engine/src/Texture/Sprite2D.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Engine/src/Texture/Sprite2D.cpp b/Engine/src/Texture/Sprite2D.cpp index 0c861321..5681383a 100644 --- a/Engine/src/Texture/Sprite2D.cpp +++ b/Engine/src/Texture/Sprite2D.cpp @@ -116,7 +116,11 @@ void Sprite2D::DrawOnce(double delta, bool manual) void Sprite2D::DrawStop(double delta, bool manual) { - DrawInternal(delta, true, nullptr, manual); // Play once + DrawInternal(delta, true, nullptr, manual); + + if (m_currentIndex == m_textures.size()) { // Play the stop on last frame + m_currentIndex = m_textures.size() - 1; + } } From 50e2e702e66fd157975f80a0ce121f694bfd41c0 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 24 May 2024 22:01:42 +0700 Subject: [PATCH 39/83] refactor: hide directx11 due weird framedrop (instead use vulkan lmao) --- Engine/src/Rendering/Renderer.cpp | 4 ++-- Game/src/Scenes/Overlays/Settings.cpp | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Engine/src/Rendering/Renderer.cpp b/Engine/src/Rendering/Renderer.cpp index 13c56937..62e49a39 100644 --- a/Engine/src/Rendering/Renderer.cpp +++ b/Engine/src/Rendering/Renderer.cpp @@ -52,11 +52,11 @@ bool Renderer::Create(RendererMode mode, GameWindow *window, bool failed) break; } - case RendererMode::DIRECTX11: + /*case RendererMode::DIRECTX11: { rendererName = "direct3d11"; break; - } + }*/ case RendererMode::DIRECTX12: { diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index a57a8c06..f7e63fc4 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -35,14 +35,23 @@ static std::map Graphics = { { 1, "Vulkan" }, #if _WIN32 { 2, "DirectX-9" }, - { 3, "DirectX-11" }, - { 4, "DirectX-12" }, + { 3, "DirectX-12" }, #endif #if __APPLE__ - { 5, "Metal" }, + { 4, "Metal" }, #endif }; +//#if _WIN32 +//{ 2, "DirectX-9" }, +//{ 3, "DirectX-11" }, +//{ 4, "DirectX-12" }, +//#endif +//#if __APPLE__ +//{ 5, "Metal" }, +//#endif +//}; + static std::array LongNote = { "None", "Short", "Normal", "Long" }; static std::array m_fps = { "30", "60", "75", "120", "144", "165", "180", "240", "360", "480", "600", "800", "1000", "Unlimited" }; static std::array SelectedBackground = { "Arena", "Song", "Disable" }; From 45720a3bfb9d318ab34ab7c55bd7c4b0cd81e86c Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sat, 25 May 2024 11:51:36 +0700 Subject: [PATCH 40/83] refactor(game): changed some code --- Engine/src/Game.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/Engine/src/Game.cpp b/Engine/src/Game.cpp index 87ac8aa3..fa122f16 100644 --- a/Engine/src/Game.cpp +++ b/Engine/src/Game.cpp @@ -35,27 +35,25 @@ namespace { IMG_Quit(); } - using namespace std::chrono; - - thread_local high_resolution_clock::time_point curTick = high_resolution_clock::now(); - thread_local high_resolution_clock::time_point lastTick = high_resolution_clock::now(); + thread_local double curTick = 0.0; + thread_local double lastTick = 0.0; double FrameLimit(double MaxFrameRate) { const double targetFrameTime = 1000.0 / MaxFrameRate; - - auto newTick = high_resolution_clock::now(); - auto frameTime = duration_cast(newTick - curTick).count() / 1000.0; + double newTick = static_cast(std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count()); + double frameTime = newTick - curTick; if (frameTime < targetFrameTime) { - auto delayTime = duration(targetFrameTime - frameTime); - std::this_thread::sleep_for(delayTime); - newTick += duration_cast(delayTime); + std::this_thread::yield(); + double delayTime = targetFrameTime - frameTime; + std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(delayTime))); + newTick += delayTime; } - double delta = duration_cast(newTick - curTick).count() / 1000000.0; + double delta = (newTick - curTick) / 1000.0; lastTick = curTick; curTick = newTick; From 87b20fabe2fcc3d20cce481a924e12d79c8915fb Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sun, 26 May 2024 22:31:51 +0700 Subject: [PATCH 41/83] refactor(setting): now game grab refresh rate and make values by multiply it --- Game/src/Scenes/Overlays/Settings.cpp | 89 +++++++++++++++++++-------- 1 file changed, 63 insertions(+), 26 deletions(-) diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index f7e63fc4..26ab471a 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -53,11 +53,36 @@ static std::map Graphics = { //}; static std::array LongNote = { "None", "Short", "Normal", "Long" }; -static std::array m_fps = { "30", "60", "75", "120", "144", "165", "180", "240", "360", "480", "600", "800", "1000", "Unlimited" }; +//static std::array m_fps = { "30", "60", "75", "120", "144", "165", "180", "240", "360", "480", "600", "800", "1000", "Unlimited" }; static std::array SelectedBackground = { "Arena", "Song", "Disable" }; static std::vector m_resolutions = {}; +int currentFPSIndex = 0; +int customFPS = 0; + +namespace { + int GetScreenRefreshRate() { + SDL_DisplayMode displayMode; + if (SDL_GetCurrentDisplayMode(0, &displayMode) != 0) { + return 60; // Default to 60 if SDL can't catch refresh rate (pc issues) + } + return displayMode.refresh_rate; + } + + std::vector GetFpsOptions() { + int refreshRate = GetScreenRefreshRate(); + std::vector multipliers = { 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 20 }; + std::vector fpsOptions; + + for (int multiplier : multipliers) { + fpsOptions.push_back(std::to_string(refreshRate * multiplier)); + } + fpsOptions.push_back("Unlimited"); + return fpsOptions; + } +} + void SettingsOverlay::Render(double delta) { auto &io = ImGui::GetIO(); @@ -197,7 +222,8 @@ void SettingsOverlay::Render(double delta) int nextGraphicsIndex = -1; try { GraphicsIndex = std::stoi(Configuration::Load("Game", "Renderer").c_str()); - } catch (const std::invalid_argument &) { + } + catch (const std::invalid_argument&) { } ImGui::Text("Graphics"); @@ -253,25 +279,34 @@ void SettingsOverlay::Render(double delta) ImGui::NewLine(); + std::vector fpsOptions = GetFpsOptions(); ImGui::Text("FPS"); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Warning: setting unlimited FPS can cause PC to unstable!"); - if (ImGui::BeginCombo("###ComboBox2", m_fps[currentFPSIndex].c_str())) { - for (int i = 0; i < m_fps.size(); i++) { + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Warning: setting unlimited FPS can cause PC to become unstable!"); + if (ImGui::BeginCombo("###ComboBox2", fpsOptions[currentFPSIndex].c_str())) { + for (int i = 0; i < fpsOptions.size(); i++) { bool isSelected = (currentFPSIndex == i); - if (ImGui::Selectable(m_fps[i].c_str(), &isSelected)) { + if (ImGui::Selectable(fpsOptions[i].c_str(), &isSelected)) { currentFPSIndex = i; + if (fpsOptions[i] == "Unlimited") { + customFPS = 9999; + Configuration::Set("Game", "FrameLimit", std::to_string(customFPS)); + } + else { + customFPS = 0; + Configuration::Set("Game", "FrameLimit", fpsOptions[i]); + } } if (isSelected) { ImGui::SetItemDefaultFocus(); } } - ImGui::EndCombo(); } ImGui::EndTabItem(); + } if (ImGui::BeginTabItem("Audio")) { @@ -509,17 +544,24 @@ void SettingsOverlay::LoadConfiguration() } try { - auto value = Configuration::Load("Game", "FrameLimit"); - auto it = std::find(m_fps.begin(), m_fps.end(), value); - if (it == m_fps.end()) { - currentFPSIndex = 4; - } else { - currentFPSIndex = (int)(it - m_fps.begin()); + std::string frameLimit = Configuration::Load("Game", "FrameLimit"); + auto fpsOptions = GetFpsOptions(); + auto it = std::find(fpsOptions.begin(), fpsOptions.end(), frameLimit); + if (it != fpsOptions.end()) { + currentFPSIndex = std::distance(fpsOptions.begin(), it); + customFPS = 0; } - } catch (const std::invalid_argument &) { - currentFPSIndex = 4; + else { + currentFPSIndex = fpsOptions.size() - 1; + customFPS = 9999; + } + } + catch (const std::invalid_argument&) { + customFPS = 9999; } + SceneManager::GetInstance()->SetFrameLimit(std::atof(Configuration::Load("Game", "FrameLimit").c_str())); + try { currentGuideLineIndex = std::stoi(Configuration::Load("Game", "GuideLine").c_str()); } catch (const std::invalid_argument &) { @@ -575,12 +617,6 @@ void SettingsOverlay::LoadConfiguration() EnvironmentSetup::SetInt("MeasureLine", 1); } - auto fps = m_fps[currentFPSIndex]; - if (fps == *(m_fps.end() - 1)) { - fps = "9999" ; - } - - SceneManager::GetInstance()->SetFrameLimit(std::atof(fps.c_str())); currentSkin = Configuration::Load("Game", "Skin"); PreloadSkin(); } @@ -590,18 +626,19 @@ void SettingsOverlay::SaveConfiguration() Configuration::Set("Game", "AudioOffset", std::to_string(currentOffset)); Configuration::Set("Game", "AudioVolume", std::to_string(currentVolume)); Configuration::Set("Game", "AutoSound", std::to_string(convertAutoSound ? 1 : 0)); - Configuration::Set("Game", "FrameLimit", m_fps[currentFPSIndex]); Configuration::Set("Game", "GuideLine", std::to_string(currentGuideLineIndex)); Configuration::Set("Game", "Background", std::to_string(BackgroundIndex)); Configuration::Set("Game", "MeasureLine", std::to_string(MeasureLine ? 1 : 0)); Configuration::Set("Game", "NoteTail", std::to_string(NoteTail ? 1 : 0)); - auto frame = m_fps[currentFPSIndex]; - if (frame == m_fps[13]) { - frame = "9999"; + if (currentFPSIndex == GetFpsOptions().size() - 1 && customFPS > 0) { + Configuration::Set("Game", "FrameLimit", std::to_string(customFPS)); + } + else { + Configuration::Set("Game", "FrameLimit", GetFpsOptions()[currentFPSIndex]); } - SceneManager::GetInstance()->SetFrameLimit(std::atof(frame.c_str())); + SceneManager::GetInstance()->SetFrameLimit(std::atof(Configuration::Load("Game", "FrameLimit").c_str())); if (currentSkin.empty()) { throw std::runtime_error("SKIN_NAME Undefined!"); From 3f6f057e7755f72cfa75810294b67e0010c6e20b Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Mon, 27 May 2024 14:00:05 +0700 Subject: [PATCH 42/83] --- Engine/src/Game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine/src/Game.cpp b/Engine/src/Game.cpp index fa122f16..b79c5c5b 100644 --- a/Engine/src/Game.cpp +++ b/Engine/src/Game.cpp @@ -47,9 +47,9 @@ namespace { if (frameTime < targetFrameTime) { - std::this_thread::yield(); double delayTime = targetFrameTime - frameTime; std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(delayTime))); + std::this_thread::yield(); newTick += delayTime; } From 8df764c06a07ce54bec6e582d8d9c5d9362a42cf Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 29 May 2024 10:49:43 +0700 Subject: [PATCH 43/83] refactor(note): forget to add trail on tail Long Note, fix crash in rare cases --- Engine/src/Texture/Sprite2D.cpp | 18 ++-- Game/src/Engine/Note.cpp | 147 ++++++-------------------------- 2 files changed, 38 insertions(+), 127 deletions(-) diff --git a/Engine/src/Texture/Sprite2D.cpp b/Engine/src/Texture/Sprite2D.cpp index 5681383a..1c793328 100644 --- a/Engine/src/Texture/Sprite2D.cpp +++ b/Engine/src/Texture/Sprite2D.cpp @@ -66,6 +66,8 @@ void Sprite2D::Draw(double delta, bool manual) void Sprite2D::DrawInternal(double delta, bool playOnce, Rect* rect, bool manual) { + if (m_textures.empty()) return; // Safety check to ensure m_textures is not empty + if (m_currentIndex >= m_textures.size()) { if (playOnce) { return; // Stop if playing once and reached end @@ -97,8 +99,13 @@ void Sprite2D::DrawInternal(double delta, bool playOnce, Rect* rect, bool manual m_currentTime = 0.0; m_currentIndex++; - if (playOnce && m_currentIndex == m_textures.size()) { - return; // Stop if playing once and reached end + if (m_currentIndex >= m_textures.size()) { + if (playOnce) { + m_currentIndex = m_textures.size() - 1; // Stop at the last frame if playing once + return; + } else { + m_currentIndex = 0; // Loop back to the first frame + } } } } @@ -118,12 +125,11 @@ void Sprite2D::DrawStop(double delta, bool manual) { DrawInternal(delta, true, nullptr, manual); - if (m_currentIndex == m_textures.size()) { // Play the stop on last frame + if (m_currentIndex >= m_textures.size()) { // Play the stop on last frame m_currentIndex = m_textures.size() - 1; } } - void Sprite2D::Reset() { m_currentIndex = 0; @@ -132,6 +138,8 @@ void Sprite2D::Reset() Texture2D *Sprite2D::GetTexture() { + if (m_textures.empty()) return nullptr; // Safety check to ensure m_textures is not empty + auto tex = m_textures[m_currentIndex]; tex->Position = Position; tex->Size = Size; @@ -143,4 +151,4 @@ Texture2D *Sprite2D::GetTexture() void Sprite2D::SetFPS(double fps) { m_spritespeed = 1.0f / fps; -} \ No newline at end of file +} diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 2c796d22..23f19099 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -260,6 +260,30 @@ void Note::Render(double delta) // Code more cleared than before m_tail->Position = UDim2::fromOffset(m_laneOffset, tailPosY); m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); m_tail->Draw(delta, &playRect); + + if (guideLineLength > 0) { + m_trail_down->Position = m_tail->Position; + m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_down->AnchorPoint = { 0, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_down->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, 0); + m_trail_down->AnchorPoint = { 1, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_up->Position = m_tail->Position + UDim2::fromOffset(0, -m_tail->AbsoluteSize.Y); + m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_up->AnchorPoint = { 0, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + + m_trail_up->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, -m_tail->AbsoluteSize.Y); + m_trail_up->AnchorPoint = { 1, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + } } } @@ -566,125 +590,4 @@ void Note::Release() cacheManager->Repool(m_head, m_imageType); m_head = nullptr; } -} - -// Old code -//void Note::Render(double delta) -//{ -// if (IsRemoveable()) -// return; -// if (!m_drawAble) -// return; -// -// auto resolution = m_engine->GetResolution(); -// auto hitPos = m_engine->GetHitPosition(); -// double trackPosition = m_engine->GetTrackPosition(); -// -// int min = -100, max = hitPos + 25; -// auto playRect = m_engine->GetPlayRectangle(); -// -// int guideLineIndex = m_engine->GetGuideLineIndex(); -// -// int guideLineLength = 24 * length_multiplier[guideLineIndex]; -// -// if (m_type == NoteType::HOLD) { -// double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; -// double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; -// -// m_head->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y1)); -// m_tail->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y2)); -// -// float Transparency = 0.9f; -// -// if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { -// // m_head->Position.Y.Offset = hitPos; -// Transparency = 1.0f; -// } -// -// m_head->CalculateSize(); -// m_tail->CalculateSize(); -// -// double headPos = m_head->AbsolutePosition.Y + (m_head->AbsoluteSize.Y / 2.0); -// double tailPos = m_tail->AbsolutePosition.Y + (m_tail->AbsoluteSize.Y / 2.0); -// -// double height = headPos - tailPos; -// double position = (height / 2.0) + tailPos; -// -// m_body->Position = UDim2::fromOffset(m_laneOffset, position); -// m_body->Size = { 1, 0, 0, height }; -// -// m_body->TintColor = { Transparency, Transparency, Transparency }; -// -// bool b1 = isWithinRange(m_head->Position.Y.Offset, min, max); -// bool b2 = isWithinRange(m_tail->Position.Y.Offset, min, max); -// -// if (isCollision(m_tail->Position.Y.Offset, m_head->Position.Y.Offset, min, max)) { -// m_body->SetIndexAt(m_engine->GetNoteImageIndex()); -// m_body->Draw(delta, &playRect); -// } -// -// if (b1) { -// if (guideLineLength > 0) { -// m_trail_down->Position = m_head->Position; -// m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); -// m_trail_down->AnchorPoint = { 0, 0 }; -// m_trail_down->Draw(delta, &playRect); -// -// m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); -// m_trail_down->AnchorPoint = { 1, 0 }; -// m_trail_down->Draw(delta, &playRect); -// } -// -// m_head->SetIndexAt(m_engine->GetNoteImageIndex()); -// m_head->Draw(delta, &playRect); -// } -// -// if (b2) { -// if (guideLineLength > 0) { -// m_trail_up->Position = m_tail->Position + UDim2::fromOffset(0, -m_tail->AbsoluteSize.Y); -// m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); -// m_trail_up->AnchorPoint = { 0, 1 }; -// m_trail_up->Draw(delta, &playRect); -// -// m_trail_up->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, -m_tail->AbsoluteSize.Y); -// m_trail_up->AnchorPoint = { 1, 1 }; -// m_trail_up->Draw(delta, &playRect); -// } -// -// m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); -// m_tail->Draw(delta, &playRect); -// } -// } -// else { -// double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; -// m_head->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y1)); -// m_head->CalculateSize(); -// -// bool b1 = isWithinRange(m_head->Position.Y.Offset, min, max); -// -// if (b1) { -// if (guideLineLength > 0) { -// m_trail_down->Position = m_head->Position; -// m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); -// m_trail_down->AnchorPoint = { 0, 0 }; -// m_trail_down->Draw(delta, &playRect); -// -// m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); -// m_trail_down->AnchorPoint = { 1, 0 }; -// m_trail_down->Draw(delta, &playRect); -// -// m_trail_up->Position = m_head->Position + UDim2::fromOffset(0, -m_head->AbsoluteSize.Y); -// m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); -// m_trail_up->AnchorPoint = { 0, 1 }; -// m_trail_up->Draw(delta, &playRect); -// -// m_trail_up->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, -m_head->AbsoluteSize.Y); -// m_trail_up->AnchorPoint = { 1, 1 }; -// m_trail_up->Draw(delta, &playRect); -// } -// -// m_head->SetIndexAt(m_engine->GetNoteImageIndex()); -// m_head->Draw(delta, &playRect); -// } -// } -//} \ No newline at end of file +} \ No newline at end of file From 5a04bbbd2529354e08609426ba93e373d5c7c947 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Thu, 30 May 2024 09:32:29 +0700 Subject: [PATCH 44/83] refactor(scoremanager): make code easiest to read --- Game/src/Engine/ScoreManager.cpp | 215 ++++++++++++------------------ Game/src/Engine/ScoreManager.hpp | 8 ++ Game/src/Engine/TimingLine.cpp | 1 + Game/src/Scenes/GameplayScene.cpp | 24 +++- 4 files changed, 112 insertions(+), 136 deletions(-) diff --git a/Game/src/Engine/ScoreManager.cpp b/Game/src/Engine/ScoreManager.cpp index e34b2350..2f7a181b 100644 --- a/Game/src/Engine/ScoreManager.cpp +++ b/Game/src/Engine/ScoreManager.cpp @@ -3,6 +3,11 @@ #include #include "../EnvironmentSetup.hpp" +// Cool, Good, Bad, Miss (Divide by 10 from O2Jam) +const HealthDifficulty easy = {0.3f, 0.2f, -1.0f, -5.0f}; +const HealthDifficulty normal = {0.2f, 0.1f, -0.7f, -4.0f}; +const HealthDifficulty hard = {0.1f, 0.0f, -0.5f, -3.0f}; + ScoreManager::ScoreManager() { m_cool = 0; @@ -32,116 +37,92 @@ ScoreManager::~ScoreManager() { } -void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 and divided that by 10 +void ScoreManager::OnHit(NoteHitInfo info) { - bool IsPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; - if (!IsPlaying) { + bool isPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; + bool isFail = EnvironmentSetup::GetInt("Failed") == 1; + + if (!isPlaying) { return; } + HealthDifficulty health; int difficulty = EnvironmentSetup::GetInt("Difficulty"); switch (difficulty) { - case 0: // Easy - switch (info.Result) { - case NoteResult::COOL: - AddLife(0.3f); - m_jamGauge += 4.0f; - m_score += 200 + (10 * m_jamCombo); - m_cool++; - break; - case NoteResult::GOOD: - AddLife(0.2f); - m_jamGauge += 2.0f; - m_score += 100 + (5 * m_jamCombo); - m_good++; + case 0: + health = easy; break; - case NoteResult::BAD: // IDK if this correct or not (from old code) - if (m_numOfPills > 0) { - m_numOfPills = std::clamp(m_numOfPills - 1, 0, 5); - m_score += 200 + (10 * m_jamCombo); - m_cool++; - info.Result = NoteResult::COOL; - } - else { - AddLife(-1.0f); - m_jamGauge = 0.0f; - m_coolCombo = 0; - m_score += 4; - m_combo = 0; - m_bad++; - } + case 1: + health = normal; break; - default: - AddLife(-5.0f); - m_combo = 0; - m_jamCombo = 0; - m_jamGauge = 0.0f; - if (m_life > 0) { - m_score -= 10; - } - m_miss++; + case 2: + health = hard; break; - } - break; + } - case 1: // Normal - switch (info.Result) { - case NoteResult::COOL: - AddLife(0.2f); - m_jamGauge += 4.0f; - m_score += 200 + (10 * m_jamCombo); - m_cool++; - break; - case NoteResult::GOOD: - AddLife(0.1f); - m_jamGauge += 2.0f; - m_score += 100 + (5 * m_jamCombo); - m_good++; - break; - case NoteResult::BAD: // IDK if this correct or not (from old code) - if (m_numOfPills > 0) { - m_numOfPills = std::clamp(m_numOfPills - 1, 0, 5); - m_score += 200 + (10 * m_jamCombo); - m_cool++; - info.Result = NoteResult::COOL; - } - else { - AddLife(-0.7f); - m_jamGauge = 0.0f; + HandleHit(info, health); + + m_combo = std::clamp(m_combo, 0, INT_MAX); + if (!isFail) { + m_jamCombo = std::clamp(m_jamCombo, 0, INT_MAX); + m_jamGauge = std::clamp(m_jamGauge, 0.0f, 100.0f); + } + m_score = std::clamp(m_score, 0, INT_MAX); + + if (info.Result == NoteResult::COOL) { + m_coolCombo += 1; + if (!isFail) { + if (m_coolCombo > 15) { m_coolCombo = 0; - m_score += 4; - m_combo = 0; - m_bad++; + m_numOfPills = std::clamp(m_numOfPills + 1, 0, 5); } - break; - default: - AddLife(-4.0f); - m_combo = 0; - m_jamCombo = 0; - m_jamGauge = 0.0f; - if (m_life > 0) { - m_score -= 10; + } + } else { + m_coolCombo = 0; + } + + if (info.Result != NoteResult::BAD && info.Result != NoteResult::MISS) { + m_combo += 1; + m_maxCombo = std::max(m_maxCombo, m_combo); + } + + if (!isFail) { + if (m_jamGauge >= kMaxJamGauge) { + m_jamGauge = 0; + m_jamCombo += 1; + m_maxJamCombo = std::max(m_maxJamCombo, m_jamCombo); + + if (m_jamCallback) { + m_jamCallback(m_jamCombo); } - m_miss++; - break; } - break; + } + + if (m_callback) { + if (info.Result == NoteResult::MISS && m_life == 0) { + return; + } - case 2: // Hard - switch (info.Result) { + m_callback(info); + } +} + +void ScoreManager::HandleHit(NoteHitInfo& info, const HealthDifficulty& health) +{ + switch (info.Result) { case NoteResult::COOL: - AddLife(0.1f); + AddLife(health.cool); m_jamGauge += 4.0f; m_score += 200 + (10 * m_jamCombo); m_cool++; break; case NoteResult::GOOD: - AddLife(0.0f); + AddLife(health.good); m_jamGauge += 2.0f; m_score += 100 + (5 * m_jamCombo); m_good++; break; - case NoteResult::BAD: // IDK if this correct or not (from old code) + case NoteResult::BAD: if (m_numOfPills > 0) { m_numOfPills = std::clamp(m_numOfPills - 1, 0, 5); m_score += 200 + (10 * m_jamCombo); @@ -149,7 +130,7 @@ void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 a info.Result = NoteResult::COOL; } else { - AddLife(-0.5f); + AddLife(health.bad); m_jamGauge = 0.0f; m_coolCombo = 0; m_score += 4; @@ -158,7 +139,7 @@ void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 a } break; default: - AddLife(-3.0f); + AddLife(health.miss); m_combo = 0; m_jamCombo = 0; m_jamGauge = 0.0f; @@ -167,54 +148,19 @@ void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 a } m_miss++; break; - } - break; - } - - m_combo = std::clamp(m_combo, 0, INT_MAX); - m_jamCombo = std::clamp(m_jamCombo, 0, INT_MAX); - m_jamGauge = std::clamp(m_jamGauge, 0.0f, 100.0f); - m_score = std::clamp(m_score, 0, INT_MAX); - - if (info.Result == NoteResult::COOL) { - m_coolCombo += 1; - - if (m_coolCombo > 15) { - m_coolCombo = 0; - m_numOfPills = std::clamp(m_numOfPills + 1, 0, 5); - } - } else { - m_coolCombo = 0; - } - - if (info.Result != NoteResult::BAD && info.Result != NoteResult::MISS) { - m_combo += 1; - m_maxCombo = std::max(m_maxCombo, m_combo); - } - - if (m_jamGauge >= kMaxJamGauge) { - m_jamGauge = 0; - m_jamCombo += 1; - m_maxJamCombo = std::max(m_maxJamCombo, m_jamCombo); - - if (m_jamCallback) { - m_jamCallback(m_jamCombo); - } - } - - if (m_callback) { - if (info.Result == NoteResult::MISS && m_life == 0) { - return; - } - - m_callback(info); } } void ScoreManager::OnLongNoteHold(HoldResult result) { - bool IsPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; - if (!IsPlaying) { + bool isPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; + bool isFail = EnvironmentSetup::GetInt("Failed") == 1; + + if (!isPlaying) { + return; + } + + if (isFail) { return; } @@ -276,8 +222,11 @@ std::tuple ScoreManager:: void ScoreManager::AddLife(float sz) { - if (m_life > 0) { - m_life += sz; - m_life = std::clamp(m_life, 0.0f, 100.0f); + bool isFail = EnvironmentSetup::GetInt("Failed") == 1; + if (!isFail) { + if (m_life > 0) { + m_life += sz; + m_life = std::clamp(m_life, 0.0f, 100.0f); + } } } diff --git a/Game/src/Engine/ScoreManager.hpp b/Game/src/Engine/ScoreManager.hpp index d15c37d4..9c29e053 100644 --- a/Game/src/Engine/ScoreManager.hpp +++ b/Game/src/Engine/ScoreManager.hpp @@ -5,6 +5,13 @@ constexpr float kMaxJamGauge = 100; constexpr float kMaxLife = 100; +struct HealthDifficulty { + float cool; + float good; + float bad; + float miss; +}; + struct NoteHitInfo { NoteResult Result; @@ -21,6 +28,7 @@ class ScoreManager ~ScoreManager(); void OnHit(NoteHitInfo info); + void HandleHit(NoteHitInfo& info, const HealthDifficulty& health); void OnLongNoteHold(HoldResult result); void ListenHit(std::function); void ListenJam(std::function); diff --git a/Game/src/Engine/TimingLine.cpp b/Game/src/Engine/TimingLine.cpp index 1a8894ba..f9724811 100644 --- a/Game/src/Engine/TimingLine.cpp +++ b/Game/src/Engine/TimingLine.cpp @@ -66,6 +66,7 @@ void TimingLine::Render(double delta) m_line->Position = UDim2::fromOffset(m_imagePos, pos_y); //+ start.Lerp(end, alpha); if (m_line->Position.Y.Offset >= 0 && m_line->Position.Y.Offset < hitPos + 10) { + m_line->TintColor = { 0.7f, 0.7f, 0.7f }; m_line->Draw(&playRect); } } diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index a7aa2111..3ebc777b 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -85,7 +85,7 @@ void GameplayScene::Update(double delta) m_minuteNum->DrawNumber(0); m_secondNum->DrawNumber(0); - if (m_counter > 10.0) { + if (m_counter > 5.0) { m_ended = true; m_counter = 0.0; // Reset SceneManager::DisplayFade(100, [] { @@ -94,14 +94,32 @@ void GameplayScene::Update(double delta) } } + if (m_game->GetState() == GameState::PosGame && !m_ended) { + m_drawExitButton = false; + m_doExit = false; + m_minuteNum->DrawNumber(0); + m_secondNum->DrawNumber(0); + + m_ended = true; + m_counter = 0.0; // Reset + SceneManager::DisplayFade(100, [] { + SceneManager::ChangeScene(GameScene::RESULT); + }); + } + int difficulty = EnvironmentSetup::GetInt("Difficulty"); + float health = m_game->GetScoreManager()->GetLife(); if (difficulty >= 1 && m_starting) { - float health = m_game->GetScoreManager()->GetLife(); - if (health <= 0) { m_drawExitButton = false; m_doExit = false; m_game->Stop(); + EnvironmentSetup::SetInt("NowPlaying", 0); + EnvironmentSetup::SetInt("Failed", 1); + } + } + else { + if (health <= 0) { EnvironmentSetup::SetInt("Failed", 1); } } From 19babe40c529a20870df7480d7bdfed86931763e Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Thu, 30 May 2024 10:01:29 +0700 Subject: [PATCH 45/83] --- Game/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 595b4916..c6c1e982 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -24,7 +24,7 @@ extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; - __declspec(dllexport) DWORD IntelGpuPowerPreference = 0x00000003; + __declspec(dllexport) DWORD IntelGpuPowerPreference = 0x00000002; } #endif From bcb6c639e72924712fb7dcb77644227213807e51 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 31 May 2024 09:45:45 +0700 Subject: [PATCH 46/83] refactor(chart): fix game not read event and audio sample properly on osu files at some cases --- Game/src/Data/Chart.cpp | 151 ++++++++++++++++++++-------------------- 1 file changed, 75 insertions(+), 76 deletions(-) diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index 0165141a..2f286590 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -18,6 +18,19 @@ float float_floor(float value) #endif } +namespace { + std::string getFileExtension(const std::string& filename) { + size_t dotPos = filename.find_last_of('.'); + if (dotPos != std::string::npos) { + std::string ext = filename.substr(dotPos + 1); + // Convert extension to lowercase + std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) { return std::tolower(c); }); + return ext; + } + return ""; // No extension found + } +} + double TimingInfo::CalculateBeat(double offset) { if (Type == TimingType::SV) { @@ -33,7 +46,7 @@ Chart::Chart() m_keyCount = 7; } -Chart::Chart(Osu::Beatmap &beatmap) +Chart::Chart(Osu::Beatmap& beatmap) { if (!beatmap.IsValid()) { throw std::invalid_argument("Invalid osu beatmap!"); @@ -47,67 +60,72 @@ Chart::Chart(Osu::Beatmap &beatmap) throw std::invalid_argument("osu beatmap's Mania key must be 7"); } - // m_audio = beatmap.AudioFilename; m_title = std::u8string(beatmap.Title.begin(), beatmap.Title.end()); m_keyCount = (int)beatmap.CircleSize; m_artist = std::u8string(beatmap.Artist.begin(), beatmap.Artist.end()); m_difname = std::u8string(beatmap.Version.begin(), beatmap.Version.end()); m_beatmapDirectory = beatmap.CurrentDir; - for (auto &event : beatmap.Events) { - switch (event.Type) { - case Osu::OsuEventType::Background: - { - std::string fileName = event.params[0]; - fileName.erase(std::remove(fileName.begin(), fileName.end(), '\"'), fileName.end()); + for (auto& event : beatmap.Events) { // Fix some background not load properly + if (event.Type == Osu::OsuEventType::Background) { + std::string fileName = event.params[0]; + fileName.erase(std::remove(fileName.begin(), fileName.end(), '\"'), fileName.end()); + m_backgroundFile = fileName; + break; + } + } - m_backgroundFile = fileName; - break; + for (auto& event : beatmap.Events) { + if (event.Type == Osu::OsuEventType::Sample) { + std::string fileName = event.params[1]; + if (fileName.front() == '\"' && fileName.back() == '\"') { + fileName = fileName.substr(1, fileName.size() - 2); } - case Osu::OsuEventType::Sample: - { - std::string fileName = event.params[1]; - fileName.erase(std::remove(fileName.begin(), fileName.end(), '\"'), fileName.end()); - - auto path = beatmap.CurrentDir / fileName; - if (std::filesystem::exists(path)) { - AutoSample sample = {}; - sample.StartTime = event.StartTime; - sample.Index = beatmap.GetCustomSampleIndex(fileName); - sample.Volume = 1; - sample.Pan = 0; - - m_autoSamples.push_back(sample); + auto path = beatmap.CurrentDir / fileName; + if (!std::filesystem::exists(path)) { + std::string extension = getFileExtension(fileName); + if (!extension.empty()) { + std::vector extensionsToTry = { ".ogg", ".wav", ".mp3" }; + for (const auto& ext : extensionsToTry) { + std::string newFileName = fileName.substr(0, fileName.find_last_of('.')) + ext; + path = beatmap.CurrentDir / newFileName; + if (std::filesystem::exists(path)) { + fileName = newFileName; + break; + } + } } + } - break; + if (std::filesystem::exists(path)) { + AutoSample sample = {}; + sample.StartTime = event.StartTime; + sample.Index = beatmap.GetCustomSampleIndex(fileName); + sample.Volume = 1; + sample.Pan = 0; + m_autoSamples.push_back(sample); + } + else { + Logs::Puts("[Chart] Custom sample file not found: %s", fileName.c_str()); } } } - { - AutoSample sample = {}; - if (beatmap.AudioLeadIn = 0) { - sample.StartTime = beatmap.AudioLeadIn - 1; // Handle if offset 0 that causing audio delay - } - else { - sample.StartTime = beatmap.AudioLeadIn; - } - sample.Index = beatmap.GetCustomSampleIndex(beatmap.AudioFilename); - sample.Volume = 1; - sample.Pan = 0; + AutoSample autoSample = {}; + autoSample.StartTime = beatmap.AudioLeadIn == 0 ? -1 : beatmap.AudioLeadIn; + autoSample.Index = beatmap.GetCustomSampleIndex(beatmap.AudioFilename); + autoSample.Volume = 1; + autoSample.Pan = 0; + m_autoSamples.push_back(autoSample); - m_autoSamples.push_back(sample); - } - - for (auto ¬e : beatmap.HitObjects) { + for (auto& note : beatmap.HitObjects) { NoteInfo info = {}; info.StartTime = note.StartTime; info.Type = NoteType::NORMAL; info.Keysound = note.KeysoundIndex; info.LaneIndex = static_cast(float_floor(note.X * static_cast(beatmap.CircleSize) / 512.0f)); - info.Volume = static_cast(note.Volume) / 100.0f; + info.Volume = 1.0f; // static_cast(note.Volume) / 100.0f causing no audio info.Pan = 0; if (note.Type == 128) { @@ -118,69 +136,50 @@ Chart::Chart(Osu::Beatmap &beatmap) m_notes.push_back(info); } - for (auto &timing : beatmap.TimingPoints) { - bool IsSV = timing.Inherited == 0 || timing.BeatLength < 0; - - if (IsSV) { + for (auto& timing : beatmap.TimingPoints) { + if (timing.Inherited == 0 || timing.BeatLength < 0) { TimingInfo info = {}; info.StartTime = timing.Offset; info.Value = std::clamp(-100.0f / timing.BeatLength, 0.1f, 10.0f); info.Type = TimingType::SV; - m_svs.push_back(info); - } else { + } + else { TimingInfo info = {}; info.StartTime = timing.Offset; info.Value = 60000.0f / timing.BeatLength; info.TimeSignature = timing.TimeSignature; info.Type = TimingType::BPM; - m_bpms.push_back(info); } } - for (int i = 0; i < beatmap.HitSamples.size(); i++) { - auto &keysound = beatmap.HitSamples[i]; + for (auto& note : m_notes) { + if (m_keyCount == 4 && note.LaneIndex >= 2) { + note.LaneIndex += 3; + } + else if (m_keyCount == 5 && (note.LaneIndex == 3 || note.LaneIndex >= 4)) { + note.LaneIndex += 2; + } + } + for (int i = 0; i < beatmap.HitSamples.size(); i++) { + auto& keysound = beatmap.HitSamples[i]; auto path = beatmap.CurrentDir / keysound; Sample sm = {}; sm.FileName = path; sm.Index = i; - m_samples.push_back(sm); } - for (auto ¬e : m_notes) { - switch (m_keyCount) { - case 4: - { - if (note.LaneIndex >= 2) { - note.LaneIndex += 3; - } - break; - } - - case 5: - { - if (note.LaneIndex == 3) { - note.LaneIndex += 1; - } else if (note.LaneIndex >= 4) { - note.LaneIndex += 2; - } - break; - } - } - } - CalculateBeat(); - SortTimings(); - NormalizeTimings(); ComputeHash(); } + Chart::Chart(BMS::BMSFile &file) { if (!file.IsValid()) { @@ -207,7 +206,7 @@ Chart::Chart(BMS::BMSFile &file) info.Type = NoteType::NORMAL; info.LaneIndex = note.Lane; info.Keysound = note.SampleIndex; - info.Volume = 1; + info.Volume = 1.0f; info.Pan = 0; if (note.EndTime != -1) { From 01bf0971ef64ca48b6a497b746eda5192ae2578d Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 31 May 2024 15:28:12 +0700 Subject: [PATCH 47/83] --- Game/src/Data/Chart.cpp | 43 +++--- Game/src/Scenes/MainMenu.cpp | 259 +++++++++++++++++------------------ 2 files changed, 150 insertions(+), 152 deletions(-) diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index 2f286590..c66f617c 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -46,7 +46,7 @@ Chart::Chart() m_keyCount = 7; } -Chart::Chart(Osu::Beatmap& beatmap) +Chart::Chart(Osu::Beatmap& beatmap) // Refactor { if (!beatmap.IsValid()) { throw std::invalid_argument("Invalid osu beatmap!"); @@ -57,7 +57,7 @@ Chart::Chart(Osu::Beatmap& beatmap) } if (beatmap.CircleSize < 1 || beatmap.CircleSize > 7) { - throw std::invalid_argument("osu beatmap's Mania key must be 7"); + throw std::invalid_argument("osu beatmap's Mania key must be between 1 and 7"); } m_title = std::u8string(beatmap.Title.begin(), beatmap.Title.end()); @@ -66,7 +66,7 @@ Chart::Chart(Osu::Beatmap& beatmap) m_difname = std::u8string(beatmap.Version.begin(), beatmap.Version.end()); m_beatmapDirectory = beatmap.CurrentDir; - for (auto& event : beatmap.Events) { // Fix some background not load properly + for (auto& event : beatmap.Events) { if (event.Type == Osu::OsuEventType::Background) { std::string fileName = event.params[0]; fileName.erase(std::remove(fileName.begin(), fileName.end(), '\"'), fileName.end()); @@ -105,8 +105,7 @@ Chart::Chart(Osu::Beatmap& beatmap) sample.Volume = 1; sample.Pan = 0; m_autoSamples.push_back(sample); - } - else { + } else { Logs::Puts("[Chart] Custom sample file not found: %s", fileName.c_str()); } } @@ -115,7 +114,7 @@ Chart::Chart(Osu::Beatmap& beatmap) AutoSample autoSample = {}; autoSample.StartTime = beatmap.AudioLeadIn == 0 ? -1 : beatmap.AudioLeadIn; autoSample.Index = beatmap.GetCustomSampleIndex(beatmap.AudioFilename); - autoSample.Volume = 1; + autoSample.Volume = 1.0f; autoSample.Pan = 0; m_autoSamples.push_back(autoSample); @@ -125,7 +124,7 @@ Chart::Chart(Osu::Beatmap& beatmap) info.Type = NoteType::NORMAL; info.Keysound = note.KeysoundIndex; info.LaneIndex = static_cast(float_floor(note.X * static_cast(beatmap.CircleSize) / 512.0f)); - info.Volume = 1.0f; // static_cast(note.Volume) / 100.0f causing no audio + info.Volume = note.Volume > 0 ? static_cast(note.Volume) / 100.0f : 1.0f; info.Pan = 0; if (note.Type == 128) { @@ -143,8 +142,7 @@ Chart::Chart(Osu::Beatmap& beatmap) info.Value = std::clamp(-100.0f / timing.BeatLength, 0.1f, 10.0f); info.Type = TimingType::SV; m_svs.push_back(info); - } - else { + } else { TimingInfo info = {}; info.StartTime = timing.Offset; info.Value = 60000.0f / timing.BeatLength; @@ -154,14 +152,15 @@ Chart::Chart(Osu::Beatmap& beatmap) } } - for (auto& note : m_notes) { - if (m_keyCount == 4 && note.LaneIndex >= 2) { - note.LaneIndex += 3; - } - else if (m_keyCount == 5 && (note.LaneIndex == 3 || note.LaneIndex >= 4)) { - note.LaneIndex += 2; - } - } + // TODO: This thing causing game crash, weird, NEED to be fixed + //for (auto& note : m_notes) { + // if (m_keyCount == 4 && note.LaneIndex >= 2) { + // note.LaneIndex += 3; + // } + // else if (m_keyCount == 5 && (note.LaneIndex == 3 || note.LaneIndex >= 4)) { + // note.LaneIndex += 2; + // } + //} for (int i = 0; i < beatmap.HitSamples.size(); i++) { auto& keysound = beatmap.HitSamples[i]; @@ -176,10 +175,10 @@ Chart::Chart(Osu::Beatmap& beatmap) CalculateBeat(); SortTimings(); NormalizeTimings(); + ComputeKeyCount(); ComputeHash(); } - Chart::Chart(BMS::BMSFile &file) { if (!file.IsValid()) { @@ -222,7 +221,7 @@ Chart::Chart(BMS::BMSFile &file) AutoSample sm = {}; sm.StartTime = note.StartTime; sm.Index = note.SampleIndex; - sm.Volume = 1; + sm.Volume = 1.0f; sm.Pan = 0; m_autoSamples.push_back(sm); @@ -266,7 +265,7 @@ Chart::Chart(BMS::BMSFile &file) AutoSample sm = {}; sm.StartTime = autoSample.StartTime; sm.Index = autoSample.SampleIndex; - sm.Volume = 1; + sm.Volume = 1.0f; sm.Pan = 0; m_autoSamples.push_back(sm); @@ -734,7 +733,7 @@ void Chart::ComputeKeyCount() // BMS-O2 4K is: X X - - - X X // BMS-O2 5K is: X X - X - X X - // BMS-O2 6K is: X X X X X X - + // BMS-O2 6K is: X X X - X X X // BMS-O2 7K is: X X X X X X X // Check for 7K first since it has the highest priority @@ -742,7 +741,7 @@ void Chart::ComputeKeyCount() m_keyCount = 7; } // Check for 6K - else if (Lanes[0] && Lanes[1] && Lanes[2] && Lanes[3] && Lanes[4] && Lanes[5] && !Lanes[6]) { + else if (Lanes[0] && Lanes[1] && Lanes[2] && !Lanes[3] && Lanes[4] && Lanes[5] && Lanes[6]) { m_keyCount = 6; } // Check for 5K diff --git a/Game/src/Scenes/MainMenu.cpp b/Game/src/Scenes/MainMenu.cpp index 5d618869..823f8cdd 100644 --- a/Game/src/Scenes/MainMenu.cpp +++ b/Game/src/Scenes/MainMenu.cpp @@ -21,138 +21,137 @@ void MainMenu::Update(double delta) { } -//void MainMenu::Render(double delta) -//{ -// ImguiUtil::NewFrame(); -// -// auto window = GameWindow::GetInstance(); -// ImGui::SetNextWindowPos(ImVec2(0, 0)); -// -// auto windowNextSz = ImVec2((float)window->GetBufferWidth(), (float)window->GetBufferHeight()); -// ImGui::SetNextWindowSize(MathUtil::ScaleVec2(windowNextSz)); -// ImGui::SetWindowPos(ImVec2(0, 0)); -// -// if (m_background) { -// m_background->Draw(); -// } -// -// auto flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBringToFrontOnFocus; -// -// int nextScene = -1; -// if (ImGui::Begin("###BEGIN", nullptr, flags)) { -// if (ImGui::BeginMenuBar()) { -// std::string title = std::string(O2GAME_TITLE) + " " + std::string(O2GAME_VERSION); -// ImGui::Text("%s", title.c_str()); -// -// std::string text = "No Account!"; -// auto textWidth = ImGui::CalcTextSize(text.c_str()).x; -// -// ImGui::SameLine(MathUtil::ScaleVec2(ImVec2(windowNextSz.x, 0)).x - textWidth - 15); -// ImGui::Text(text.c_str()); -// -// ImGui::EndMenuBar(); -// } -// -// { -// ImFont *font = FontResources::GetButtonFont(); -// ImGui::PushFont(font); -// ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); -// auto ButtonColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); -// ButtonColor.w = 0.25f; -// ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ButtonColor); -// ButtonColor.w = 0.15f; -// ImGui::PushStyleColor(ImGuiCol_ButtonActive, ButtonColor); -// ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); -// -// auto ButtonSize = MathUtil::ScaleVec2(window->GetBufferWidth(), 40); -// -// for (int i = 0; i < 5; i++) { -// ImGui::NewLine(); -// } -// -// ImGui::Spacing(); -// if (ImGui::Button("Single player", ButtonSize)) { -// nextScene = 0; -// } -// -// if (ImGui::Button("Play", ButtonSize)) { -// nextScene = 0; -// } -// -// ImGui::Spacing(); -// if (ImGui::Button("Multi player", ButtonSize)) { -// MsgBox::Show("Multiplayer", "Error", "Multiplayer is not implemented yet!"); -// } -// -// ImGui::NewLine(); -// ImGui::Spacing(); -// if (ImGui::Button("Editor", ButtonSize)) { -// nextScene = 2; -// } -// -// ImGui::NewLine(); -// ImGui::Spacing(); -// if (ImGui::Button("Options", ButtonSize)) { -// nextScene = 3; -// } -// -// ImGui::Spacing(); -// if (ImGui::Button("Quit", ButtonSize)) { -// nextScene = 4; -// } -// -// ImGui::PopStyleVar(); -// ImGui::PopStyleColor(3); -// ImGui::PopFont(); -// } -// -// ImGui::End(); -// } -// -// if (nextScene != -1) { -// switch (nextScene) { -// case 0: -// { -// SceneManager::DisplayFade(100, [this]() { -// SceneManager::ChangeScene(GameScene::SONGSELECT); -// }); -// break; -// } -// -// case 1: -// { -// break; -// } -// -// case 2: -// { -// SceneManager::DisplayFade(100, [this]() { -// SceneManager::ChangeScene(GameScene::EDITOR); -// }); -// break; -// } -// -// case 3: -// { -// SceneManager::OverlayShow(GameOverlay::SETTINGS); -// break; -// } -// -// case 4: -// { -// SDL_Event e = {}; -// e.type = SDL_QUIT; -// -// SDL_PushEvent(&e); -// break; -// } -// } -// } -//} - void MainMenu::Render(double delta) { - SceneManager::ChangeScene(GameScene::SONGSELECT); + ImguiUtil::NewFrame(); + + auto window = GameWindow::GetInstance(); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + + auto windowNextSz = ImVec2((float)window->GetBufferWidth(), (float)window->GetBufferHeight()); + ImGui::SetNextWindowSize(MathUtil::ScaleVec2(windowNextSz)); + ImGui::SetWindowPos(ImVec2(0, 0)); + + if (m_background) { + m_background->Draw(); + } + + auto flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBringToFrontOnFocus; + + int nextScene = -1; + if (ImGui::Begin("###BEGIN", nullptr, flags)) { + if (ImGui::BeginMenuBar()) { + std::string title = std::string(O2GAME_TITLE) + " " + std::string(O2GAME_VERSION); + ImGui::Text("%s", title.c_str()); + + std::string text = "Main Menu"; + auto textWidth = ImGui::CalcTextSize(text.c_str()).x; + + ImGui::SameLine(MathUtil::ScaleVec2(ImVec2(windowNextSz.x, 0)).x - textWidth - 15); + ImGui::Text(text.c_str()); + + ImGui::EndMenuBar(); + } + + { + ImFont* font = FontResources::GetButtonFont(); + ImGui::PushFont(font); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + auto ButtonColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); + ButtonColor.w = 0.25f; + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ButtonColor); + ButtonColor.w = 0.15f; + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ButtonColor); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); + + auto ButtonSize = MathUtil::ScaleVec2(window->GetBufferWidth(), 40); + + for (int i = 0; i < 5; i++) { + ImGui::NewLine(); + } + + ImGui::NewLine(); + ImGui::Spacing(); + //if (ImGui::Button("Single player", ButtonSize)) { + // nextScene = 0; + //} + + ImGui::NewLine(); + ImGui::Spacing(); + + if (ImGui::Button("Play", ButtonSize)) { + nextScene = 0; + } + + // ImGui::Spacing(); + // if (ImGui::Button("Multi player", ButtonSize)) { + // MsgBox::Show("Multiplayer", "Error", "Multiplayer is not implemented yet!"); + //} + + //ImGui::NewLine(); + //ImGui::Spacing(); + //if (ImGui::Button("Editor", ButtonSize)) { + // nextScene = 2; + //} + + ImGui::NewLine(); + ImGui::Spacing(); + if (ImGui::Button("Options", ButtonSize)) { + nextScene = 3; + } + + ImGui::Spacing(); + if (ImGui::Button("Quit", ButtonSize)) { + nextScene = 4; + } + + ImGui::PopStyleVar(); + ImGui::PopStyleColor(3); + ImGui::PopFont(); + } + + ImGui::End(); + } + + if (nextScene != -1) { + switch (nextScene) { + case 0: + { + SceneManager::DisplayFade(100, [this]() { + SceneManager::ChangeScene(GameScene::SONGSELECT); + }); + break; + } + + case 1: + { + break; + } + + case 2: + { + SceneManager::DisplayFade(100, [this]() { + SceneManager::ChangeScene(GameScene::EDITOR); + }); + break; + } + + case 3: + { + SceneManager::OverlayShow(GameOverlay::SETTINGS); + break; + } + + case 4: + { + SDL_Event e = {}; + e.type = SDL_QUIT; + + SDL_PushEvent(&e); + break; + } + } + } } bool MainMenu::Attach() From 298e2e2b71d6c57755b9ad52af1f24be39978b03 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sat, 1 Jun 2024 17:08:59 +0700 Subject: [PATCH 48/83] refactor: fix missing font and panic mod causing overlapped --- Engine/src/Fonts/FontResources.cpp | 34 +++++++++++-- Game/src/Data/Chart.cpp | 69 +++++++++------------------ Game/src/Data/Util/Util.cpp | 76 ++++++++++++++---------------- Game/src/Engine/RhythmEngine.cpp | 16 +++++-- Game/src/Scenes/GameplayScene.cpp | 15 ------ 5 files changed, 100 insertions(+), 110 deletions(-) diff --git a/Engine/src/Fonts/FontResources.cpp b/Engine/src/Fonts/FontResources.cpp index 43b91ba1..c0894b50 100644 --- a/Engine/src/Fonts/FontResources.cpp +++ b/Engine/src/Fonts/FontResources.cpp @@ -100,6 +100,34 @@ void FontResources::PreloadFontCaches() auto krFont = fontPath / "kr.ttf"; auto chFont = fontPath / "ch.ttf"; + static const ImWchar glyphRanges[] = { // Add whole fucking glyph ranges so nothing missing + 0x0020, 0x00FF, // Basic Latin + Latin Supplement + 0x0100, 0x017F, // Latin Extended-A + 0x0180, 0x024F, // Latin Extended-B + 0x0370, 0x03FF, // Greek and Coptic + 0x0400, 0x04FF, // Cyrillic + 0x0500, 0x052F, // Cyrillic Supplement + 0x2000, 0x206F, // General Punctuation + 0x20A0, 0x20CF, // Currency Symbols + 0x2100, 0x214F, // Letterlike Symbols + 0x2190, 0x21FF, // Arrows + 0x2200, 0x22FF, // Mathematical Operators + 0x2300, 0x23FF, // Miscellaneous Technical + 0x2500, 0x257F, // Box Drawing + 0x25A0, 0x25FF, // Geometric Shapes + 0x2600, 0x26FF, // Miscellaneous Symbols + 0x2E80, 0x2EFF, // CJK Radicals Supplement + 0x2F00, 0x2FDF, // Kangxi Radicals + 0x3000, 0x303F, // CJK Symbols and Punctuation + 0x3040, 0x309F, // Hiragana + 0x30A0, 0x30FF, // Katakana + 0x31F0, 0x31FF, // Katakana Phonetic Extensions + 0x4E00, 0x9FFF, // CJK Unified Ideographs + 0xAC00, 0xD7AF, // Hangul Syllables + 0xFF00, 0xFFEF, // Halfwidth and Fullwidth Forms + 0x0000, 0x0000 // End of list + }; + { float originScale = (wnd->GetBufferWidth() + wnd->GetBufferHeight()) / 15.6f; float targetScale = (wnd->GetWidth() + wnd->GetHeight()) / 15.6f; @@ -118,9 +146,9 @@ void FontResources::PreloadFontCaches() { if (std::filesystem::exists(normalfont)) { - Font.Font = io.Fonts->AddFontFromFileTTF((const char *)normalfont.u8string().c_str(), fontSize, &conf); + Font.Font = io.Fonts->AddFontFromFileTTF((const char *)normalfont.u8string().c_str(), fontSize, &conf, glyphRanges); // glyphRanges, fixing missing fonts } else { - Font.Font = io.Fonts->AddFontFromMemoryTTF((void *)get_arial_font_data(), get_arial_font_size(), fontSize, &conf); + Font.Font = io.Fonts->AddFontFromMemoryTTF((void *)get_arial_font_data(), get_arial_font_size(), fontSize, &conf, glyphRanges); } } @@ -151,7 +179,7 @@ void FontResources::PreloadFontCaches() case TextRegion::Chinese: { if (std::filesystem::exists(chFont)) { - io.Fonts->AddFontFromFileTTF((const char *)chFont.u8string().c_str(), fontSize, &conf, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); + io.Fonts->AddFontFromFileTTF((const char *)chFont.u8string().c_str(), fontSize, &conf, io.Fonts->GetGlyphRangesChineseFull()); } break; diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index c66f617c..b97bc48d 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -8,6 +8,7 @@ #include #include #include +#include float float_floor(float value) { @@ -460,74 +461,48 @@ void Chart::ApplyMod(Mod mod, void *data) case Mod::PANIC: { - std::vector lanes(m_keyCount); - for (int i = 0; i < m_keyCount; i++) { - lanes[i] = i; - } - - auto rng = std::default_random_engine{}; - rng.seed((uint32_t)time(NULL)); - - std::unordered_map> measureLane; + std::unordered_map> measureLane; // Store randomized lanes for each measure + std::unordered_map measureBPM; // Store BPM for each measure - // Keep track of BPM changes - std::unordered_map measureBPM; + // Populate measureBPM with BPM values for each measure for (const auto& bpm : m_bpms) { int measure = static_cast(bpm.StartTime / bpm.TimeSignature); measureBPM[measure] = bpm.Value; } + // Randomize note lanes while preventing overlaps for (auto& note : m_notes) { - int measure = -1; - for (size_t i = 0; i < m_bpms.size(); i++) { - if (m_bpms[i].StartTime > note.StartTime) { - measure = static_cast(m_bpms[i - 1].CalculateBeat(note.StartTime) / m_bpms[i - 1].TimeSignature); - break; - } - } - - if (measure == -1) { - measure = static_cast(m_bpms.back().CalculateBeat(note.StartTime) / m_bpms.back().TimeSignature); - } - - for (int i = measure; i > 0; i--) { - if (measureBPM.find(i) == measureBPM.end()) { - measureBPM[i] = measureBPM[i - 1]; - } - } + int measure = static_cast(note.StartTime / m_bpms[0].TimeSignature); // Calculate measure of the note + // If the measure doesn't have randomized lanes yet, generate them if (measureLane.find(measure) == measureLane.end()) { - std::shuffle(std::begin(lanes), std::end(lanes), rng); - measureLane[measure] = lanes; + std::vector lanes(m_keyCount); + std::iota(lanes.begin(), lanes.end(), 0); // Fill lanes with 0 to keyCount-1 + std::shuffle(lanes.begin(), lanes.end(), std::default_random_engine{}); // Shuffle lanes + measureLane[measure] = lanes; // Store randomized lanes for the measure } + // Apply randomized lane to the note note.LaneIndex = measureLane[measure][note.LaneIndex]; + // Check if the note overlaps with the next measure int nextMeasure = measure + 1; if (note.EndTime > nextMeasure * measureBPM[nextMeasure]) { + // If the next measure doesn't have randomized lanes yet, copy from the current measure if (measureLane.find(nextMeasure) == measureLane.end()) { measureLane[nextMeasure] = measureLane[measure]; } } } - // Log the randomization pattern for each measure - //int prevMeasure = -1; - //std::vector prevPattern; - //for (const auto& [measure, randomizedLane] : measureLane) { - // if (prevMeasure != -1 && prevPattern == randomizedLane) { - // continue; // Skip logging if the pattern is the same as the previous measure - // } - // std::stringstream pattern; - // for (int lane : randomizedLane) { - // pattern << lane; - // } - // int startMeasure = prevMeasure == -1 ? 0 : prevMeasure + 1; - // int endMeasure = measure; - // Logs::Puts("[Chart] Randomized Lane from Measure %d to %d with pattern: %s", startMeasure, endMeasure, pattern.str().c_str()); - // prevMeasure = measure; - // prevPattern = randomizedLane; - //} + // Optional: Log the randomization pattern for each measure + /*for (const auto& [measure, randomizedLane] : measureLane) { + std::stringstream pattern; + for (int lane : randomizedLane) { + pattern << lane; + } + Logs::Puts("[Chart] Randomized Lane for Measure %d: %s", measure, pattern.str().c_str()); + }*/ break; } diff --git a/Game/src/Data/Util/Util.cpp b/Game/src/Data/Util/Util.cpp index f4db3980..a98b0333 100644 --- a/Game/src/Data/Util/Util.cpp +++ b/Game/src/Data/Util/Util.cpp @@ -130,51 +130,47 @@ void flipArray(uint8_t *arr, size_t size) } } -std::u8string CodepageToUtf8(const char *string, size_t str_len, const char *encoding) -{ - std::u8string result; - iconv_t conv = iconv_open("UTF-8", encoding); +std::u8string CodepageToUtf8(const char* string, size_t str_len, const char* encoding) { + // Open iconv conversion descriptor + iconv_t conv = iconv_open("UTF-8", encoding); if (conv == (iconv_t)-1) { return u8""; } - // size_t inbytesleft = str_len; - // size_t outbytesleft = str_len * 4; - // char* inbuf = (char*)string; - // char* outbuf = (char*)malloc(outbytesleft); - // char* outbufptr = outbuf; - - // if (iconv(conv, &inbuf, &inbytesleft, &outbufptr, &outbytesleft) == (size_t)-1) { - // free(outbuf); - // iconv_close(conv); - // return std::u8string((const char8_t*)strerror(errno)); - // } - - // result = std::u8string((char8_t*)outbuf, str_len * 4 - outbytesleft); - // free(outbuf); - // iconv_close(conv); - // return result; - - size_t inbytesleft = str_len; - size_t outbytesleft = str_len * 4; - char *inbuf = (char *)string; - std::vector outbuf; - outbuf.resize(outbytesleft, 0); - - char *outbufptr = outbuf.data(); - - if (iconv(conv, &inbuf, &inbytesleft, &outbufptr, &outbytesleft) == (size_t)-1) { - iconv_close(conv); - - // return whatever we have left, even if it's not valid - size_t len = strlen(outbuf.data()); - std::u8string remaining = std::u8string((const char8_t *)outbuf.data(), len); - - return remaining; + std::u8string result; + size_t inbytesleft = str_len; + const char* inbuf = string; + size_t outbufsize = str_len * 4; // Initial output buffer size + std::vector outbuf(outbufsize); + + while (true) { + char* outbufptr = outbuf.data(); + size_t outbytesleft = outbuf.size(); + + // Reset errno to check for errors after iconv call + errno = 0; + + size_t ret = iconv(conv, (char**)&inbuf, &inbytesleft, &outbufptr, &outbytesleft); + if (ret != (size_t)-1 || errno == E2BIG) { + // Successfully converted or need more space + if (ret != (size_t)-1) { + result.assign((const char8_t*)outbuf.data(), outbuf.size() - outbytesleft); + break; + } + // Resize buffer and retry if buffer was too small + size_t processed = outbuf.size() - outbytesleft; + outbufsize *= 2; + outbuf.resize(outbufsize); + inbuf = string + (str_len - inbytesleft); + std::fill(outbuf.begin() + processed, outbuf.end(), 0); + } + else { + // Return whatever we have left, even if it's not valid + result.assign((const char8_t*)outbuf.data()); + break; + } } - result = std::u8string((char8_t *)outbuf.data(), str_len * 4 - outbytesleft); iconv_close(conv); - return result; -} +} \ No newline at end of file diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 00b20081..987d6310 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../EnvironmentSetup.hpp" #include "Configuration.h" @@ -225,21 +226,26 @@ bool RhythmEngine::Load(Chart *chart) if (EnvironmentSetup::GetInt("SongType") == 1) { m_title = chart->m_title; - sprintf(buffer, "Lv.%d %s", chart->m_level, (const char*)chart->m_title.c_str()); + std::string titleStr = std::string(chart->m_title.begin(), chart->m_title.end()); + std::snprintf(buffer, MAX_BUFFER_TXT_SIZE, "Lv.%d %s", chart->m_level, titleStr.c_str()); } else if (EnvironmentSetup::GetInt("SongType") == 2) { m_title = chart->m_title; - sprintf(buffer, "[%s] %s", chart->m_difname, (const char*)chart->m_title.c_str()); + std::string difnameStr = std::string(chart->m_difname.begin(), chart->m_difname.end()); + std::string titleStr = std::string(chart->m_title.begin(), chart->m_title.end()); + std::snprintf(buffer, MAX_BUFFER_TXT_SIZE, "[%s] %s", difnameStr.c_str(), titleStr.c_str()); } else { m_title = chart->m_title; - //sprintf(buffer, "%d %s", chart->m_level, (const char*)chart->m_title.c_str()); + std::string titleStr = std::string(chart->m_title.begin(), chart->m_title.end()); + std::snprintf(buffer, MAX_BUFFER_TXT_SIZE, "%d %s", chart->m_level, titleStr.c_str()); } - m_title = std::u8string(buffer, buffer + strlen(buffer)); + // Reset the u8string with the result of snprintf + m_title = std::u8string(buffer, buffer + std::strlen(buffer)); if (m_rate != 1.0) { memset(buffer, 0, MAX_BUFFER_TXT_SIZE); - sprintf(buffer, "[%.2fx] %s", m_rate, (const char *)m_title.c_str()); + sprintf(buffer, "[%.2fx] %s", m_rate, (const char*)m_title.c_str()); m_title = std::u8string(buffer, buffer + strlen(buffer)); } diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 3ebc777b..76e404f9 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -94,25 +94,10 @@ void GameplayScene::Update(double delta) } } - if (m_game->GetState() == GameState::PosGame && !m_ended) { - m_drawExitButton = false; - m_doExit = false; - m_minuteNum->DrawNumber(0); - m_secondNum->DrawNumber(0); - - m_ended = true; - m_counter = 0.0; // Reset - SceneManager::DisplayFade(100, [] { - SceneManager::ChangeScene(GameScene::RESULT); - }); - } - int difficulty = EnvironmentSetup::GetInt("Difficulty"); float health = m_game->GetScoreManager()->GetLife(); if (difficulty >= 1 && m_starting) { if (health <= 0) { - m_drawExitButton = false; - m_doExit = false; m_game->Stop(); EnvironmentSetup::SetInt("NowPlaying", 0); EnvironmentSetup::SetInt("Failed", 1); From cf9183e32ce4be400261edc4f6f80642c1e6e364 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sun, 2 Jun 2024 17:08:11 +0700 Subject: [PATCH 49/83] refactor: idk what i'm doing --- Game/src/Data/Chart.cpp | 75 ++++++++++++++++++++++--------- Game/src/Engine/RhythmEngine.cpp | 10 ++++- Game/src/Engine/RhythmEngine.hpp | 2 + Game/src/Scenes/GameplayScene.cpp | 13 +++++- 4 files changed, 76 insertions(+), 24 deletions(-) diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index b97bc48d..78170cd6 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -113,7 +113,12 @@ Chart::Chart(Osu::Beatmap& beatmap) // Refactor } AutoSample autoSample = {}; - autoSample.StartTime = beatmap.AudioLeadIn == 0 ? -1 : beatmap.AudioLeadIn; + if (beatmap.AudioLeadIn = 0) { + autoSample.StartTime = beatmap.AudioLeadIn - 1; // Handle if offset 0 that causing audio delay + } + else { + autoSample.StartTime = beatmap.AudioLeadIn; + } autoSample.Index = beatmap.GetCustomSampleIndex(beatmap.AudioFilename); autoSample.Volume = 1.0f; autoSample.Pan = 0; @@ -461,48 +466,74 @@ void Chart::ApplyMod(Mod mod, void *data) case Mod::PANIC: { - std::unordered_map> measureLane; // Store randomized lanes for each measure - std::unordered_map measureBPM; // Store BPM for each measure + std::vector lanes(m_keyCount); + for (int i = 0; i < m_keyCount; i++) { + lanes[i] = i; + } + + auto rng = std::default_random_engine{}; + rng.seed((uint32_t)time(NULL)); - // Populate measureBPM with BPM values for each measure + std::unordered_map> measureLane; + + // Keep track of BPM changes + std::unordered_map measureBPM; for (const auto& bpm : m_bpms) { int measure = static_cast(bpm.StartTime / bpm.TimeSignature); measureBPM[measure] = bpm.Value; } - // Randomize note lanes while preventing overlaps for (auto& note : m_notes) { - int measure = static_cast(note.StartTime / m_bpms[0].TimeSignature); // Calculate measure of the note + int measure = -1; + for (size_t i = 0; i < m_bpms.size(); i++) { + if (m_bpms[i].StartTime > note.StartTime) { + measure = static_cast(m_bpms[i - 1].CalculateBeat(note.StartTime) / m_bpms[i - 1].TimeSignature); + break; + } + } + + if (measure == -1) { + measure = static_cast(m_bpms.back().CalculateBeat(note.StartTime) / m_bpms.back().TimeSignature); + } + + for (int i = measure; i > 0; i--) { + if (measureBPM.find(i) == measureBPM.end()) { + measureBPM[i] = measureBPM[i - 1]; + } + } - // If the measure doesn't have randomized lanes yet, generate them if (measureLane.find(measure) == measureLane.end()) { - std::vector lanes(m_keyCount); - std::iota(lanes.begin(), lanes.end(), 0); // Fill lanes with 0 to keyCount-1 - std::shuffle(lanes.begin(), lanes.end(), std::default_random_engine{}); // Shuffle lanes - measureLane[measure] = lanes; // Store randomized lanes for the measure + std::shuffle(std::begin(lanes), std::end(lanes), rng); + measureLane[measure] = lanes; } - // Apply randomized lane to the note note.LaneIndex = measureLane[measure][note.LaneIndex]; - // Check if the note overlaps with the next measure int nextMeasure = measure + 1; if (note.EndTime > nextMeasure * measureBPM[nextMeasure]) { - // If the next measure doesn't have randomized lanes yet, copy from the current measure if (measureLane.find(nextMeasure) == measureLane.end()) { measureLane[nextMeasure] = measureLane[measure]; } } } - // Optional: Log the randomization pattern for each measure - /*for (const auto& [measure, randomizedLane] : measureLane) { - std::stringstream pattern; - for (int lane : randomizedLane) { - pattern << lane; - } - Logs::Puts("[Chart] Randomized Lane for Measure %d: %s", measure, pattern.str().c_str()); - }*/ + // Log the randomization pattern for each measure + //int prevMeasure = -1; + //std::vector prevPattern; + //for (const auto& [measure, randomizedLane] : measureLane) { + // if (prevMeasure != -1 && prevPattern == randomizedLane) { + // continue; // Skip logging if the pattern is the same as the previous measure + // } + // std::stringstream pattern; + // for (int lane : randomizedLane) { + // pattern << lane; + // } + // int startMeasure = prevMeasure == -1 ? 0 : prevMeasure + 1; + // int endMeasure = measure; + // Logs::Puts("[Chart] Randomized Lane from Measure %d to %d with pattern: %s", startMeasure, endMeasure, pattern.str().c_str()); + // prevMeasure = measure; + // prevPattern = randomizedLane; + //} break; } diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 987d6310..3a33b8e2 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -341,13 +341,21 @@ bool RhythmEngine::Start() bool RhythmEngine::Stop() { - EnvironmentSetup::SetInt("NowPlaying", 0); m_state = GameState::PosGame; GameAudioSampleCache::StopAll(); m_PlayTime = 0.0; return true; } + +bool RhythmEngine::Fail() +{ + m_state = GameState::Fail; + GameAudioSampleCache::StopAll(); + m_PlayTime = 0.0; + return true; +} + bool RhythmEngine::Ready() { return m_state == GameState::NotGame; diff --git a/Game/src/Engine/RhythmEngine.hpp b/Game/src/Engine/RhythmEngine.hpp index c3f0e9ab..6a3e6783 100644 --- a/Game/src/Engine/RhythmEngine.hpp +++ b/Game/src/Engine/RhythmEngine.hpp @@ -16,6 +16,7 @@ enum class GameState { NotGame, PreGame, Playing, + Fail, PosGame }; @@ -36,6 +37,7 @@ class RhythmEngine bool Start(); bool Stop(); + bool Fail(); bool Ready(); void Update(double delta); diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 76e404f9..efcaacc6 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -94,11 +94,22 @@ void GameplayScene::Update(double delta) } } + if (m_game->GetState() == GameState::Fail && !m_ended) { + m_minuteNum->DrawNumber(0); + m_secondNum->DrawNumber(0); + + m_ended = true; + m_counter = 0.0; // Reset + SceneManager::DisplayFade(100, [] { + SceneManager::ChangeScene(GameScene::RESULT); + }); + } + int difficulty = EnvironmentSetup::GetInt("Difficulty"); float health = m_game->GetScoreManager()->GetLife(); if (difficulty >= 1 && m_starting) { if (health <= 0) { - m_game->Stop(); + m_game->Fail(); EnvironmentSetup::SetInt("NowPlaying", 0); EnvironmentSetup::SetInt("Failed", 1); } From b490187d2d3baa27149b3891dcf52ded0ebc099c Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sun, 2 Jun 2024 21:15:23 +0700 Subject: [PATCH 50/83] test --- .gitmodules | 2 +- Game/CMakeLists.txt | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.gitmodules b/.gitmodules index 180fd589..904295c9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "GameResources"] path = GameResources - url = https://github.com/Estrol/O2GameResources + url = https://github.com/AlberttFrgk/O2GameResources diff --git a/Game/CMakeLists.txt b/Game/CMakeLists.txt index 8d74a4b9..29f7f1ae 100644 --- a/Game/CMakeLists.txt +++ b/Game/CMakeLists.txt @@ -79,18 +79,28 @@ if (WIN32) # copy from ${CMAKE_SOURCE_DIR}/GameResources/Resources to $/Skins/Default add_custom_command(TARGET Game POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory + COMMAND ${CMAKE_COMMAND} -E make_directory $/Skins/Default COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/GameResources/Resources $/Skins/Default) + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Notes + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Notes + $/Resources/Notes) else () add_custom_command(TARGET Game POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory - $/Skins/Default - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/GameResources/Resources - $/Skins/Default) + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Skins/Default + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Resources + $/Skins/Default) + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Notes + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Notes + $/Resources/Notes) endif () if (MSVC) From 35479d423d3adfdc9ac9b5c049bf41a90b0cb63f Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sun, 2 Jun 2024 21:21:23 +0700 Subject: [PATCH 51/83] this ok --- Game/CMakeLists.txt | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/Game/CMakeLists.txt b/Game/CMakeLists.txt index 29f7f1ae..3b7f92a5 100644 --- a/Game/CMakeLists.txt +++ b/Game/CMakeLists.txt @@ -70,37 +70,39 @@ add_executable(Game target_include_directories(Game PRIVATE "../Engine/include") if (WIN32) - add_custom_command(TARGET Game POST_BUILD + add_custom_command(TARGET Game POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/third-party/bin/x64-windows/Debug - $) + $ + ) # Create directory $/Skins/Default then # copy from ${CMAKE_SOURCE_DIR}/GameResources/Resources to $/Skins/Default - add_custom_command(TARGET Game POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory + COMMAND ${CMAKE_COMMAND} -E make_directory $/Skins/Default COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/GameResources/Resources - $/Skins/Default) - COMMAND ${CMAKE_COMMAND} -E make_directory + $/Skins/Default + COMMAND ${CMAKE_COMMAND} -E make_directory $/Resources/Notes COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/GameResources/Notes - $/Resources/Notes) + $/Resources/Notes + ) else () add_custom_command(TARGET Game POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory + COMMAND ${CMAKE_COMMAND} -E make_directory $/Skins/Default COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/GameResources/Resources - $/Skins/Default) - COMMAND ${CMAKE_COMMAND} -E make_directory + $/Skins/Default + COMMAND ${CMAKE_COMMAND} -E make_directory $/Resources/Notes COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/GameResources/Notes - $/Resources/Notes) + $/Resources/Notes + ) endif () if (MSVC) From f1d0383a9f7cb5d1dd7d9c0594ce59fbaa4f7472 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sun, 2 Jun 2024 21:29:51 +0700 Subject: [PATCH 52/83] --- Game/src/Resources/DefaultConfiguration.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Game/src/Resources/DefaultConfiguration.h b/Game/src/Resources/DefaultConfiguration.h index 4a895d31..52d2e90e 100644 --- a/Game/src/Resources/DefaultConfiguration.h +++ b/Game/src/Resources/DefaultConfiguration.h @@ -10,7 +10,10 @@ std::string defaultConfiguration = "[game]\n" "autosound = 1\n" "resolution = 1280x720\n" // Fix for most monitor "renderer = 0\n" - "guideline = 1\n\n" + "guideline = 1\n" + "background = 0\n" + "notetail = 0\n" + "measureline = 0\n\n" "[keymapping]\n" "lane1 = A\n" @@ -45,4 +48,5 @@ std::string defaultConfiguration = "[game]\n" "notespeed = 250\n" "difficulty = \n" "modifiers =\n" - "arena =\n"; \ No newline at end of file + "arena =\n"; + From 545b822413df897577a67decdd13864428872383 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sun, 2 Jun 2024 21:37:10 +0700 Subject: [PATCH 53/83] refactor(note): adjust code a little bit --- Game/src/Engine/Note.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 23f19099..12d87023 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -256,10 +256,13 @@ void Note::Render(double delta) // Code more cleared than before bool NoteTail = EnvironmentSetup::GetInt("NoteTail") == 1; - if (isTailVisible && NoteTail) { + if (isTailVisible) { m_tail->Position = UDim2::fromOffset(m_laneOffset, tailPosY); m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); - m_tail->Draw(delta, &playRect); + + if (NoteTail) { + m_tail->Draw(delta, &playRect); + } if (guideLineLength > 0) { m_trail_down->Position = m_tail->Position; From b5c115ae1491a28b273f00e02343b752e85218c3 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 5 Jun 2024 13:25:22 +0700 Subject: [PATCH 54/83] refactor: optimize --- Engine/src/Fonts/FontResources.cpp | 55 ++++++++++++++---------------- Game/src/Data/Util/Util.cpp | 22 ++++++------ 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/Engine/src/Fonts/FontResources.cpp b/Engine/src/Fonts/FontResources.cpp index c0894b50..20d5f3c9 100644 --- a/Engine/src/Fonts/FontResources.cpp +++ b/Engine/src/Fonts/FontResources.cpp @@ -1,4 +1,4 @@ -#pragma warning(disable : 4838) // Goddamit +#pragma warning(disable : 4838) // Goddamit #pragma warning(disable : 4309) #include @@ -25,9 +25,9 @@ // BEGIN FONT FALLBACK #include "FallbackFonts/arial.ttf.h" -#include "FallbackFonts/ch.ttf.h" -#include "FallbackFonts/jp.ttf.h" -#include "FallbackFonts/kr.ttf.h" +//#include "FallbackFonts/ch.ttf.h" +//#include "FallbackFonts/jp.ttf.h" +//#include "FallbackFonts/kr.ttf.h" #include // END FONT FALLBACK @@ -100,34 +100,29 @@ void FontResources::PreloadFontCaches() auto krFont = fontPath / "kr.ttf"; auto chFont = fontPath / "ch.ttf"; - static const ImWchar glyphRanges[] = { // Add whole fucking glyph ranges so nothing missing - 0x0020, 0x00FF, // Basic Latin + Latin Supplement - 0x0100, 0x017F, // Latin Extended-A - 0x0180, 0x024F, // Latin Extended-B - 0x0370, 0x03FF, // Greek and Coptic - 0x0400, 0x04FF, // Cyrillic - 0x0500, 0x052F, // Cyrillic Supplement - 0x2000, 0x206F, // General Punctuation - 0x20A0, 0x20CF, // Currency Symbols - 0x2100, 0x214F, // Letterlike Symbols - 0x2190, 0x21FF, // Arrows - 0x2200, 0x22FF, // Mathematical Operators - 0x2300, 0x23FF, // Miscellaneous Technical - 0x2500, 0x257F, // Box Drawing - 0x25A0, 0x25FF, // Geometric Shapes - 0x2600, 0x26FF, // Miscellaneous Symbols - 0x2E80, 0x2EFF, // CJK Radicals Supplement - 0x2F00, 0x2FDF, // Kangxi Radicals - 0x3000, 0x303F, // CJK Symbols and Punctuation - 0x3040, 0x309F, // Hiragana - 0x30A0, 0x30FF, // Katakana - 0x31F0, 0x31FF, // Katakana Phonetic Extensions - 0x4E00, 0x9FFF, // CJK Unified Ideographs - 0xAC00, 0xD7AF, // Hangul Syllables - 0xFF00, 0xFFEF, // Halfwidth and Fullwidth Forms - 0x0000, 0x0000 // End of list + static const ImWchar glyphRanges[] = { // Optimized + (ImWchar)0x0020, (ImWchar)0x052F, + (ImWchar)0x2000, (ImWchar)0x27BF, + (ImWchar)0x2E80, (ImWchar)0x2FA1, + (ImWchar)0x1F300, (ImWchar)0x1FAFF, + (ImWchar)0x2660, (ImWchar)0x2663, + (ImWchar)0x2665, (ImWchar)0x2666, + (ImWchar)0x2600, (ImWchar)0x2606, + (ImWchar)0x2618, (ImWchar)0x2619, + (ImWchar)0x263A, (ImWchar)0x263B, + (ImWchar)0x2708, (ImWchar)0x2714, + (ImWchar)0x2728, (ImWchar)0x2734, + (ImWchar)0x2740, (ImWchar)0x274B, + (ImWchar)0x2756, (ImWchar)0x2758, + (ImWchar)0x2764, (ImWchar)0x2767, + (ImWchar)0x2794, (ImWchar)0x27BE, + (ImWchar)0x27F0, (ImWchar)0x27FF, + (ImWchar)0x2900, (ImWchar)0x297F, + (ImWchar)0x2A00, (ImWchar)0x2AFF, + (ImWchar)0x0000, (ImWchar)0x0000 }; + { float originScale = (wnd->GetBufferWidth() + wnd->GetBufferHeight()) / 15.6f; float targetScale = (wnd->GetWidth() + wnd->GetHeight()) / 15.6f; diff --git a/Game/src/Data/Util/Util.cpp b/Game/src/Data/Util/Util.cpp index a98b0333..14dcc3a8 100644 --- a/Game/src/Data/Util/Util.cpp +++ b/Game/src/Data/Util/Util.cpp @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include std::vector splitString(std::string &input, char delimeter) { @@ -130,7 +133,7 @@ void flipArray(uint8_t *arr, size_t size) } } -std::u8string CodepageToUtf8(const char* string, size_t str_len, const char* encoding) { +std::u8string CodepageToUtf8(const char* string, size_t str_len, const char* encoding) { // Refactor // Open iconv conversion descriptor iconv_t conv = iconv_open("UTF-8", encoding); if (conv == (iconv_t)-1) { @@ -151,22 +154,21 @@ std::u8string CodepageToUtf8(const char* string, size_t str_len, const char* enc errno = 0; size_t ret = iconv(conv, (char**)&inbuf, &inbytesleft, &outbufptr, &outbytesleft); - if (ret != (size_t)-1 || errno == E2BIG) { - // Successfully converted or need more space - if (ret != (size_t)-1) { - result.assign((const char8_t*)outbuf.data(), outbuf.size() - outbytesleft); - break; - } + if (ret != (size_t)-1) { + // Successfully converted + result.append((const char8_t*)outbuf.data(), outbuf.size() - outbytesleft); + break; + } + else if (errno == E2BIG) { // Resize buffer and retry if buffer was too small size_t processed = outbuf.size() - outbytesleft; + result.append((const char8_t*)outbuf.data(), processed); outbufsize *= 2; outbuf.resize(outbufsize); - inbuf = string + (str_len - inbytesleft); - std::fill(outbuf.begin() + processed, outbuf.end(), 0); } else { // Return whatever we have left, even if it's not valid - result.assign((const char8_t*)outbuf.data()); + result.append((const char8_t*)outbuf.data(), outbuf.size() - outbytesleft); break; } } From add34b1c01938dfde78f9f4bb2d03ebdf193fc28 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Thu, 6 Jun 2024 09:42:52 +0700 Subject: [PATCH 55/83] refactor: new Resources, new note type option, optimized code on FontResources --- Engine/src/Configuration.cpp | 2 +- Engine/src/Fonts/FontResources.cpp | 4 +- Game/CMakeLists.txt | 20 +++++ Game/src/Data/Chart.cpp | 52 ++++++------- Game/src/Data/Chart.hpp | 3 +- Game/src/Engine/SkinManager.cpp | 17 ++++- Game/src/Resources/GameResources.cpp | 16 +++- Game/src/Scenes/Overlays/Settings.cpp | 103 ++++++++++++++++++++------ Game/src/Scenes/Overlays/Settings.h | 1 + 9 files changed, 162 insertions(+), 56 deletions(-) diff --git a/Engine/src/Configuration.cpp b/Engine/src/Configuration.cpp index 1628296e..530a53f9 100644 --- a/Engine/src/Configuration.cpp +++ b/Engine/src/Configuration.cpp @@ -86,7 +86,7 @@ void Configuration::Set(std::string key, std::string prop, std::string value) void Configuration::Font_SetPath(std::filesystem::path path) { - FontPath = path; + FontPath = std::filesystem::current_path() / "Resources"; } std::filesystem::path Configuration::Font_GetPath() diff --git a/Engine/src/Fonts/FontResources.cpp b/Engine/src/Fonts/FontResources.cpp index 20d5f3c9..7fc7d8bf 100644 --- a/Engine/src/Fonts/FontResources.cpp +++ b/Engine/src/Fonts/FontResources.cpp @@ -92,8 +92,8 @@ void FontResources::PreloadFontCaches() GameWindow *wnd = GameWindow::GetInstance(); - auto skinPath = Configuration::Font_GetPath(); - auto fontPath = skinPath / "Fonts"; + auto path = Configuration::Font_GetPath(); + auto fontPath = path / "Fonts"; auto normalfont = fontPath / "normal.ttf"; auto jpFont = fontPath / "jp.ttf"; diff --git a/Game/CMakeLists.txt b/Game/CMakeLists.txt index 3b7f92a5..f76580ad 100644 --- a/Game/CMakeLists.txt +++ b/Game/CMakeLists.txt @@ -89,6 +89,16 @@ if (WIN32) COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/GameResources/Notes $/Resources/Notes + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Fonts + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Fonts + $/Resources/Fonts + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Notes/Scripts + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Scripts + $/Resources/Notes/Scripts ) else () add_custom_command(TARGET Game POST_BUILD @@ -102,6 +112,16 @@ else () COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/GameResources/Notes $/Resources/Notes + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Fonts + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Fonts + $/Resources/Fonts + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Notes/Scripts + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Scripts + $/Resources/Notes/Scripts ) endif () diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index 78170cd6..2a3e6a01 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -32,7 +32,7 @@ namespace { } } -double TimingInfo::CalculateBeat(double offset) +double TimingInfo::CalculateBeat(double offset) const { if (Type == TimingType::SV) { return 0; @@ -479,10 +479,13 @@ void Chart::ApplyMod(Mod mod, void *data) // Keep track of BPM changes std::unordered_map measureBPM; for (const auto& bpm : m_bpms) { - int measure = static_cast(bpm.StartTime / bpm.TimeSignature); + int measure = static_cast(bpm.CalculateBeat(bpm.StartTime) / bpm.TimeSignature); measureBPM[measure] = bpm.Value; } + // Keep track of which lanes are occupied by hold notes + std::unordered_map> occupiedLanes; + for (auto& note : m_notes) { int measure = -1; for (size_t i = 0; i < m_bpms.size(); i++) { @@ -507,34 +510,33 @@ void Chart::ApplyMod(Mod mod, void *data) measureLane[measure] = lanes; } - note.LaneIndex = measureLane[measure][note.LaneIndex]; + // Check if the lane is occupied by a hold note + bool laneOccupied = false; + if (occupiedLanes.find(measure) != occupiedLanes.end()) { + const auto& lanesOccupiedByHold = occupiedLanes[measure]; + laneOccupied = lanesOccupiedByHold[note.LaneIndex]; + } - int nextMeasure = measure + 1; - if (note.EndTime > nextMeasure * measureBPM[nextMeasure]) { - if (measureLane.find(nextMeasure) == measureLane.end()) { - measureLane[nextMeasure] = measureLane[measure]; + if (!laneOccupied) { + // Assign lane and mark as occupied if it's a hold note + if (note.Type == NoteType::HOLD) { + note.LaneIndex = measureLane[measure][note.LaneIndex]; + occupiedLanes[measure].resize(m_keyCount, false); // Initialize the vector if not already initialized + auto& lanesOccupiedByHold = occupiedLanes[measure]; + lanesOccupiedByHold[note.LaneIndex] = true; + for (int j = note.LaneIndex + 1; j < m_keyCount; j++) { + if (note.EndTime >= measure * measureBPM[measure] && note.LaneIndex != j) { + lanesOccupiedByHold[j] = true; + } + } + } + else { + // Shuffle lanes for normal notes if the lane is not occupied by a hold note + note.LaneIndex = measureLane[measure][note.LaneIndex]; } } } - // Log the randomization pattern for each measure - //int prevMeasure = -1; - //std::vector prevPattern; - //for (const auto& [measure, randomizedLane] : measureLane) { - // if (prevMeasure != -1 && prevPattern == randomizedLane) { - // continue; // Skip logging if the pattern is the same as the previous measure - // } - // std::stringstream pattern; - // for (int lane : randomizedLane) { - // pattern << lane; - // } - // int startMeasure = prevMeasure == -1 ? 0 : prevMeasure + 1; - // int endMeasure = measure; - // Logs::Puts("[Chart] Randomized Lane from Measure %d to %d with pattern: %s", startMeasure, endMeasure, pattern.str().c_str()); - // prevMeasure = measure; - // prevPattern = randomizedLane; - //} - break; } diff --git a/Game/src/Data/Chart.hpp b/Game/src/Data/Chart.hpp index c11dc1af..546e7e38 100644 --- a/Game/src/Data/Chart.hpp +++ b/Game/src/Data/Chart.hpp @@ -52,7 +52,8 @@ struct TimingInfo float TimeSignature; TimingType Type; - double CalculateBeat(double offset); + //double CalculateBeat(double offset); + double CalculateBeat(double offset) const; }; struct Sample diff --git a/Game/src/Engine/SkinManager.cpp b/Game/src/Engine/SkinManager.cpp index c1d49b60..4eb8750b 100644 --- a/Game/src/Engine/SkinManager.cpp +++ b/Game/src/Engine/SkinManager.cpp @@ -1,4 +1,5 @@ #include "SkinManager.hpp" +#include "../EnvironmentSetup.hpp" SkinManager *SkinManager::m_instance = nullptr; @@ -225,8 +226,20 @@ SkinManager::~SkinManager() void SkinManager::TryLoadGroup(SkinGroup group) { - m_skinConfigs[group] = std::make_unique( - GetPath() / m_expected_directory[group] / m_expected_skin_config[group], m_keyCount); + std::filesystem::path configPath; + + if (group == SkinGroup::Notes && EnvironmentSetup::GetInt("NoteSkin") != 2) { + auto path = std::filesystem::current_path() / "Resources"; + if (EnvironmentSetup::GetInt("NoteSkin") == 1) { + configPath = path / "Notes" / "Circle" / "Notes.ini"; + } else { + configPath = path / "Notes" / "Square" / "Notes.ini"; + } + } else { + configPath = GetPath() / m_expected_directory[group] / m_expected_skin_config[group]; + } + + m_skinConfigs[group] = std::make_unique(configPath, m_keyCount); } void SkinManager::Update(double delta) diff --git a/Game/src/Resources/GameResources.cpp b/Game/src/Resources/GameResources.cpp index 01c043b9..a9b4f0b0 100644 --- a/Game/src/Resources/GameResources.cpp +++ b/Game/src/Resources/GameResources.cpp @@ -23,6 +23,7 @@ #endif #include "../Engine/SkinConfig.hpp" +#include "../EnvironmentSetup.hpp" #pragma warning(disable : 26451) @@ -393,9 +394,20 @@ namespace GameNoteResource { } bool IsVulkan = Renderer::GetInstance()->IsVulkan(); + std::filesystem::path skinNotePath; - auto skinPath = SkinManager::GetInstance()->GetPath(); - auto skinNotePath = skinPath / "Notes"; + if (EnvironmentSetup::GetInt("NoteSkin") == 1) { + auto path = std::filesystem::current_path() / "Resources"; + skinNotePath = path / "Notes" / "Circle"; + } + else if (EnvironmentSetup::GetInt("NoteSkin") == 2) { + auto skinPath = SkinManager::GetInstance()->GetPath(); + skinNotePath = skinPath / "Notes"; + } + else { + auto path = std::filesystem::current_path() / "Resources"; + skinNotePath = path / "Notes" / "Square"; + } auto manager = SkinManager::GetInstance(); diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index 26ab471a..a33d33c6 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -1,4 +1,4 @@ -#include "Settings.h" +#include "Settings.h" #include #include #include @@ -55,7 +55,7 @@ static std::map Graphics = { static std::array LongNote = { "None", "Short", "Normal", "Long" }; //static std::array m_fps = { "30", "60", "75", "120", "144", "165", "180", "240", "360", "480", "600", "800", "1000", "Unlimited" }; static std::array SelectedBackground = { "Arena", "Song", "Disable" }; - +static std::array NoteSkin = { "Square", "Circle", "Custom" }; static std::vector m_resolutions = {}; int currentFPSIndex = 0; @@ -386,6 +386,66 @@ void SettingsOverlay::Render(double delta) EnvironmentSetup::SetInt("MeasureLine", 1); } + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Skins")) { + ImGui::Text("Current selected skin: "); + if (ImGui::BeginCombo("##SkinsComboBox", currentSkin.c_str())) { + for (int i = 0; i < skins.size(); i++) { + bool isSelected = (currentSkin == skins[i]); + + if (ImGui::Selectable(skins[i].c_str(), &isSelected)) { + currentSkin = skins[i]; + } + + if (isSelected) { + ImGui::SetItemDefaultFocus(); + } + } + + ImGui::EndCombo(); + } + + ImGui::NewLine(); + + ImGui::Text("Note Skin"); + for (int i = 0; i < NoteSkin.size(); ++i) { + bool selected = (NoteIndex == i); + + std::string tooltipText; + if (i == 0) { + //tooltipText = ""; + } + else if (i == 1) { + //tooltipText = ""; + } + else if (i == 2) { + tooltipText = "Using custom note image from skin folder"; + } + + if (ImGui::Checkbox(NoteSkin[i].c_str(), &selected)) { + NoteIndex = i; + } + + if (!tooltipText.empty() && ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", tooltipText.c_str()); + } + + ImGui::SameLine(); + } + + if (NoteIndex == 0) { + EnvironmentSetup::SetInt("NoteSkin", 0); + } + else if (NoteIndex == 1) { + EnvironmentSetup::SetInt("NoteSkin", 1); + } + else if (NoteIndex == 2) { + EnvironmentSetup::SetInt("NoteSkin", 2); + } + + ImGui::NewLine(); ImGui::NewLine(); ImGui::Text("Background"); @@ -430,27 +490,6 @@ void SettingsOverlay::Render(double delta) ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Skins")) { - ImGui::Text("Current selected skin: "); - if (ImGui::BeginCombo("##SkinsComboBox", currentSkin.c_str())) { - for (int i = 0; i < skins.size(); i++) { - bool isSelected = (currentSkin == skins[i]); - - if (ImGui::Selectable(skins[i].c_str(), &isSelected)) { - currentSkin = skins[i]; - } - - if (isSelected) { - ImGui::SetItemDefaultFocus(); - } - } - - ImGui::EndCombo(); - } - - ImGui::EndTabItem(); - } - ImGui::EndTabBar(); } @@ -587,6 +626,23 @@ void SettingsOverlay::LoadConfiguration() EnvironmentSetup::SetInt("Black Background", 1); } + try { + NoteIndex = std::stoi(Configuration::Load("Game", "NoteSkin").c_str()); + } + catch (const std::invalid_argument&) { + NoteIndex = 2; + } + + if (NoteIndex == 0) { + EnvironmentSetup::SetInt("NoteSkin", 0); + } + else if (NoteIndex == 1) { + EnvironmentSetup::SetInt("NoteSkin", 1); + } + else if (NoteIndex == 2) { + EnvironmentSetup::SetInt("NoteSkin", 2); + } + try { int noteTailValue = std::stoi(Configuration::Load("Game", "NoteTail")); NoteTail = (noteTailValue == 1); @@ -627,6 +683,7 @@ void SettingsOverlay::SaveConfiguration() Configuration::Set("Game", "AudioVolume", std::to_string(currentVolume)); Configuration::Set("Game", "AutoSound", std::to_string(convertAutoSound ? 1 : 0)); Configuration::Set("Game", "GuideLine", std::to_string(currentGuideLineIndex)); + Configuration::Set("Game", "NoteSkin", std::to_string(NoteIndex)); Configuration::Set("Game", "Background", std::to_string(BackgroundIndex)); Configuration::Set("Game", "MeasureLine", std::to_string(MeasureLine ? 1 : 0)); Configuration::Set("Game", "NoteTail", std::to_string(NoteTail ? 1 : 0)); diff --git a/Game/src/Scenes/Overlays/Settings.h b/Game/src/Scenes/Overlays/Settings.h index 44f9f442..ca5938e3 100644 --- a/Game/src/Scenes/Overlays/Settings.h +++ b/Game/src/Scenes/Overlays/Settings.h @@ -29,6 +29,7 @@ class SettingsOverlay : public Overlay bool MeasureLine = false; bool NoteTail = false; int BackgroundIndex = 0; + int NoteIndex = 0; bool convertAutoSound = false; std::string currentSkin = ""; From c40bc1d9b28486770e45e965aac46260c64fbe79 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 7 Jun 2024 09:25:20 +0700 Subject: [PATCH 56/83] refactor(LuaScripting): fix config doesn't load Notes.ini and Notes.lua inside Resources while NoteSkin is set to Square and Circle --- Game/src/Engine/LuaScripting.cpp | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Game/src/Engine/LuaScripting.cpp b/Game/src/Engine/LuaScripting.cpp index 949a2506..e34dac12 100644 --- a/Game/src/Engine/LuaScripting.cpp +++ b/Game/src/Engine/LuaScripting.cpp @@ -147,15 +147,30 @@ void GetLuaState(ScriptState &state, sol::table &table) state.init = table["init"]; } -void LuaScripting::TryLoadGroup(SkinGroup group) + +void LuaScripting::TryLoadGroup(SkinGroup group) // Not fully testes unless someone want make skin with lua script { - auto fullPath = m_lua_dir_path / m_expected_files[group]; + std::filesystem::path fullPath; + + if (group == SkinGroup::Notes && EnvironmentSetup::GetInt("NoteSkin") != 2) { + auto path = std::filesystem::current_path() / "Resources"; + if (EnvironmentSetup::GetInt("NoteSkin") == 1) { + fullPath = path / "Scripts" / "Notes.lua"; + } + else { + fullPath = path / "Scripts" / "Notes.lua"; + } + } + else { + fullPath = m_lua_dir_path / m_expected_files[group]; + } + if (!std::filesystem::exists(fullPath)) { throw std::runtime_error("Missing file: " + fullPath.string()); } m_states[group] = {}; - auto &state = m_states[group]; + auto& state = m_states[group]; state.state = sol::state(); if (state.state.lua_state() == nullptr) { From 6c24e1e358c9a8f19443013ed2157fce556283fc Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 12 Jun 2024 21:44:46 +0700 Subject: [PATCH 57/83] fix later --- Game/src/Data/Chart.cpp | 77 +++++++++---------------------- Game/src/Scenes/GameplayScene.cpp | 9 +++- 2 files changed, 30 insertions(+), 56 deletions(-) diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index 2a3e6a01..0e49cd58 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -466,80 +466,47 @@ void Chart::ApplyMod(Mod mod, void *data) case Mod::PANIC: { + // Shuffle lanes std::vector lanes(m_keyCount); - for (int i = 0; i < m_keyCount; i++) { - lanes[i] = i; - } - - auto rng = std::default_random_engine{}; - rng.seed((uint32_t)time(NULL)); + std::iota(lanes.begin(), lanes.end(), 0); // Initialize lanes with sequential values [0, 1, 2, ..., m_keyCount - 1] + std::shuffle(lanes.begin(), lanes.end(), std::default_random_engine(std::random_device{}())); + // Map to store randomized lanes for each measure std::unordered_map> measureLane; - // Keep track of BPM changes - std::unordered_map measureBPM; - for (const auto& bpm : m_bpms) { - int measure = static_cast(bpm.CalculateBeat(bpm.StartTime) / bpm.TimeSignature); - measureBPM[measure] = bpm.Value; - } - - // Keep track of which lanes are occupied by hold notes - std::unordered_map> occupiedLanes; - + // Iterate through notes for (auto& note : m_notes) { - int measure = -1; - for (size_t i = 0; i < m_bpms.size(); i++) { - if (m_bpms[i].StartTime > note.StartTime) { - measure = static_cast(m_bpms[i - 1].CalculateBeat(note.StartTime) / m_bpms[i - 1].TimeSignature); - break; - } - } - - if (measure == -1) { - measure = static_cast(m_bpms.back().CalculateBeat(note.StartTime) / m_bpms.back().TimeSignature); - } + // Find the timing point that corresponds to the note's start time + auto timingIter = std::lower_bound(m_bpms.begin(), m_bpms.end(), note.StartTime, + [](const TimingInfo& timing, double startTime) { return timing.StartTime < startTime; }); - for (int i = measure; i > 0; i--) { - if (measureBPM.find(i) == measureBPM.end()) { - measureBPM[i] = measureBPM[i - 1]; - } - } + // Calculate the measure of the note using the timing point's time signature + int measure = static_cast(timingIter->CalculateBeat(note.StartTime) / timingIter->TimeSignature); + // Check if the measure already has a randomized lane pattern if (measureLane.find(measure) == measureLane.end()) { - std::shuffle(std::begin(lanes), std::end(lanes), rng); + // If not, shuffle the lanes and store the pattern + std::shuffle(lanes.begin(), lanes.end(), std::default_random_engine(std::random_device{}())); measureLane[measure] = lanes; } - // Check if the lane is occupied by a hold note - bool laneOccupied = false; - if (occupiedLanes.find(measure) != occupiedLanes.end()) { - const auto& lanesOccupiedByHold = occupiedLanes[measure]; - laneOccupied = lanesOccupiedByHold[note.LaneIndex]; - } + // Update the note's lane index with the randomized lane for the measure + note.LaneIndex = measureLane[measure][note.LaneIndex]; - if (!laneOccupied) { - // Assign lane and mark as occupied if it's a hold note - if (note.Type == NoteType::HOLD) { - note.LaneIndex = measureLane[measure][note.LaneIndex]; - occupiedLanes[measure].resize(m_keyCount, false); // Initialize the vector if not already initialized - auto& lanesOccupiedByHold = occupiedLanes[measure]; - lanesOccupiedByHold[note.LaneIndex] = true; - for (int j = note.LaneIndex + 1; j < m_keyCount; j++) { - if (note.EndTime >= measure * measureBPM[measure] && note.LaneIndex != j) { - lanesOccupiedByHold[j] = true; - } + // Adjust lanes for hold notes if they cross measure boundaries + if (note.Type == NoteType::HOLD) { + int endMeasure = static_cast(timingIter->CalculateBeat(note.EndTime) / timingIter->TimeSignature); + for (int i = measure + 1; i <= endMeasure; ++i) { + if (measureLane.find(i) == measureLane.end()) { + measureLane[i] = measureLane[measure]; // Use the same pattern as the previous measure } } - else { - // Shuffle lanes for normal notes if the lane is not occupied by a hold note - note.LaneIndex = measureLane[measure][note.LaneIndex]; - } } } - break; } + case Mod::REARRANGE: { int *lanes = reinterpret_cast(data); diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index efcaacc6..4b7188b9 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -400,14 +400,21 @@ void GameplayScene::Render(double delta) m_minuteNum->DrawNumber(currentMinutes); m_secondNum->DrawNumber(currentSeconds); + for (int i = 0; i < 7; i++) { if (EnvironmentSetup::GetInt("NowPlaying") == 1) { - for (int i = 0; i < 7; i++) { m_hitEffect[i]->Draw(delta); if (m_drawHold[i]) { m_holdEffect[i]->Draw(delta); } } + else { + m_hitEffect[i]->LastIndex(); + + if (m_drawHold[i]) { + m_holdEffect[i]->LastIndex(); + } + } } if (m_drawExitButton) { From 1d59ff3a3162f6d22aa60322ab218674a6d5b4c8 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sun, 16 Jun 2024 20:56:16 +0700 Subject: [PATCH 58/83] apalah --- Game/src/Data/Chart.cpp | 53 ++++++++++++++++++------------- Game/src/Scenes/GameplayScene.cpp | 20 ++++++------ 2 files changed, 41 insertions(+), 32 deletions(-) diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index 0e49cd58..cb2dda74 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -464,45 +464,54 @@ void Chart::ApplyMod(Mod mod, void *data) break; } - case Mod::PANIC: + case Mod::PANIC: // pler { - // Shuffle lanes std::vector lanes(m_keyCount); - std::iota(lanes.begin(), lanes.end(), 0); // Initialize lanes with sequential values [0, 1, 2, ..., m_keyCount - 1] - std::shuffle(lanes.begin(), lanes.end(), std::default_random_engine(std::random_device{}())); + for (int i = 0; i < m_keyCount; i++) { + lanes[i] = i; + } + + auto rng = std::default_random_engine{}; + rng.seed((uint32_t)time(NULL)); - // Map to store randomized lanes for each measure std::unordered_map> measureLane; - // Iterate through notes + // Keep track of BPM changes + std::unordered_map measureBPM; + for (const auto& bpm : m_bpms) { + int measure = static_cast(bpm.StartTime / bpm.TimeSignature); + measureBPM[measure] = bpm.Value; + } + + // Shuffle lanes per measure for (auto& note : m_notes) { - // Find the timing point that corresponds to the note's start time - auto timingIter = std::lower_bound(m_bpms.begin(), m_bpms.end(), note.StartTime, - [](const TimingInfo& timing, double startTime) { return timing.StartTime < startTime; }); + int measure = -1; + for (size_t i = 0; i < m_bpms.size(); i++) { + if (m_bpms[i].StartTime > note.StartTime) { + measure = static_cast(m_bpms[i - 1].CalculateBeat(note.StartTime) / m_bpms[i - 1].TimeSignature); + break; + } + } - // Calculate the measure of the note using the timing point's time signature - int measure = static_cast(timingIter->CalculateBeat(note.StartTime) / timingIter->TimeSignature); + if (measure == -1) { + measure = static_cast(m_bpms.back().CalculateBeat(note.StartTime) / m_bpms.back().TimeSignature); + } - // Check if the measure already has a randomized lane pattern if (measureLane.find(measure) == measureLane.end()) { - // If not, shuffle the lanes and store the pattern - std::shuffle(lanes.begin(), lanes.end(), std::default_random_engine(std::random_device{}())); + std::shuffle(std::begin(lanes), std::end(lanes), rng); measureLane[measure] = lanes; } - // Update the note's lane index with the randomized lane for the measure note.LaneIndex = measureLane[measure][note.LaneIndex]; - // Adjust lanes for hold notes if they cross measure boundaries - if (note.Type == NoteType::HOLD) { - int endMeasure = static_cast(timingIter->CalculateBeat(note.EndTime) / timingIter->TimeSignature); - for (int i = measure + 1; i <= endMeasure; ++i) { - if (measureLane.find(i) == measureLane.end()) { - measureLane[i] = measureLane[measure]; // Use the same pattern as the previous measure - } + int nextMeasure = measure + 1; + if (note.EndTime > nextMeasure * measureBPM[nextMeasure]) { + if (measureLane.find(nextMeasure) == measureLane.end()) { + measureLane[nextMeasure] = measureLane[measure]; } } } + break; } diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 4b7188b9..3af62fd6 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -82,9 +82,6 @@ void GameplayScene::Update(double delta) m_counter += delta; m_drawExitButton = false; m_doExit = false; - m_minuteNum->DrawNumber(0); - m_secondNum->DrawNumber(0); - if (m_counter > 5.0) { m_ended = true; m_counter = 0.0; // Reset @@ -95,9 +92,6 @@ void GameplayScene::Update(double delta) } if (m_game->GetState() == GameState::Fail && !m_ended) { - m_minuteNum->DrawNumber(0); - m_secondNum->DrawNumber(0); - m_ended = true; m_counter = 0.0; // Reset SceneManager::DisplayFade(100, [] { @@ -293,22 +287,28 @@ void GameplayScene::Render(double delta) } } - if (m_drawCombo && std::get<7>(scores) > 0) { // O2Jam Combo Animation 1:1 + if (m_drawCombo && std::get<7>(scores) > 0) { const double positionStart = 30.0; - const double increment = 6.0; + const double increment = 1.0; const double decrement = 6.0; - double animationSpeed = 72.0; + double animationSpeed = 90.0; double targetPosition = positionStart - decrement * m_comboTimer * animationSpeed; double currentposition = (targetPosition > 0.0) ? targetPosition : 0.0; - // If moving down, limit the wiggle to between 30px and 36px if (currentposition > positionStart) { double wiggleAmount = currentposition - positionStart; if (wiggleAmount > increment) { currentposition = positionStart + increment; + animationSpeed -= 30.0; + if (animationSpeed < 1.0) { + animationSpeed = 1.0; + } } } + else { + animationSpeed = 90.0; + } m_comboLogo->Position2 = UDim2::fromOffset(0, currentposition / 3.0); m_comboNum->Position2 = UDim2::fromOffset(0, currentposition); From 785cfb5469e58d89b5836c9a2b171a6727ae41aa Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 19 Jun 2024 12:05:15 +0700 Subject: [PATCH 59/83] refactor(gameplayscene): refactor combo animation --- Game/src/Engine/RhythmEngine.cpp | 13 +++++++---- Game/src/Scenes/GameplayScene.cpp | 39 ++++++++++++++----------------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 3a33b8e2..0795f45c 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -343,7 +343,6 @@ bool RhythmEngine::Stop() { m_state = GameState::PosGame; GameAudioSampleCache::StopAll(); - m_PlayTime = 0.0; return true; } @@ -352,7 +351,6 @@ bool RhythmEngine::Fail() { m_state = GameState::Fail; GameAudioSampleCache::StopAll(); - m_PlayTime = 0.0; return true; } @@ -369,6 +367,7 @@ void RhythmEngine::Update(double delta) // Since I'm coming from Roblox, and I had no idea how to Real-Time sync the audio // I decided to use this method again from Roblox project I did in past. double last = m_currentAudioPosition; + m_PlayTime += delta; m_currentAudioPosition += (delta * m_rate) * 1000; // check difference between last and current audio position @@ -437,7 +436,6 @@ void RhythmEngine::Update(double delta) //auto currentTime = std::chrono::system_clock::now(); //auto elapsedTime = std::chrono::duration_cast(currentTime - m_startClock); //m_PlayTime = static_cast(elapsedTime.count() - 4); - m_PlayTime += delta; } void RhythmEngine::Render(double delta) @@ -618,7 +616,14 @@ double RhythmEngine::GetGameFrame() const int RhythmEngine::GetPlayTime() const { - return static_cast(m_PlayTime - 5); + bool isPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; + if (isPlaying) + { + return static_cast(m_PlayTime - 5); + } + else { + return 0; + } } int RhythmEngine::GetNoteImageIndex() diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 3af62fd6..27a0fe09 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -287,29 +287,19 @@ void GameplayScene::Render(double delta) } } - if (m_drawCombo && std::get<7>(scores) > 0) { + if (m_drawCombo && std::get<7>(scores) > 0) { // O2Jam Replication const double positionStart = 30.0; - const double increment = 1.0; - const double decrement = 6.0; - double animationSpeed = 90.0; - - double targetPosition = positionStart - decrement * m_comboTimer * animationSpeed; - double currentposition = (targetPosition > 0.0) ? targetPosition : 0.0; - - if (currentposition > positionStart) { - double wiggleAmount = currentposition - positionStart; - if (wiggleAmount > increment) { - currentposition = positionStart + increment; - animationSpeed -= 30.0; - if (animationSpeed < 1.0) { - animationSpeed = 1.0; - } - } - } - else { - animationSpeed = 90.0; - } + const double positionEnd = 36.0; // Decrement up to 36 + double initialAnimationSpeed = 12.0; // Initial FPS + static double animationMultiplier = 1.0; // Multiplier to control FPS + + // Dynamically calculate the animation speed + double animationSpeed = initialAnimationSpeed * animationMultiplier; + double targetposition = positionStart - (positionEnd - positionStart) * m_comboTimer * animationSpeed; + double currentposition = (targetposition > 0.0) ? targetposition : 0.0; + + // Smooth transition for the position m_comboLogo->Position2 = UDim2::fromOffset(0, currentposition / 3.0); m_comboNum->Position2 = UDim2::fromOffset(0, currentposition); @@ -321,6 +311,13 @@ void GameplayScene::Render(double delta) if (m_comboTimer >= 1.0) { m_comboTimer = 0.0; m_drawCombo = false; + animationMultiplier = 1.0; // Reset the multiplier when combo ends + } + else { + animationMultiplier *= 2.0; // Double the FPS multiplier + if (animationMultiplier > 6.0) { + animationMultiplier = 6.0; // Cap the multiplier to avoid excessive FPS + } } } From 162316c70e31bf611b2c56e100258924d7476dc8 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Wed, 19 Jun 2024 14:59:08 +0700 Subject: [PATCH 60/83] --- Game/src/Scenes/GameplayScene.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 27a0fe09..6569c144 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -296,12 +296,12 @@ void GameplayScene::Render(double delta) // Dynamically calculate the animation speed double animationSpeed = initialAnimationSpeed * animationMultiplier; - double targetposition = positionStart - (positionEnd - positionStart) * m_comboTimer * animationSpeed; - double currentposition = (targetposition > 0.0) ? targetposition : 0.0; + double targetPosition = positionStart - (positionEnd - positionStart) * m_comboTimer * animationSpeed; + double currentPosition = (targetPosition > 0.0) ? targetPosition : 0.0; // Smooth transition for the position - m_comboLogo->Position2 = UDim2::fromOffset(0, currentposition / 3.0); - m_comboNum->Position2 = UDim2::fromOffset(0, currentposition); + m_comboLogo->Position2 = UDim2::fromOffset(0, currentPosition / 3.0); + m_comboNum->Position2 = UDim2::fromOffset(0, currentPosition); m_comboLogo->Draw(delta); m_comboNum->DrawNumber(std::get<7>(scores)); @@ -325,13 +325,13 @@ void GameplayScene::Render(double delta) const double positionStart = 5.0; double animationSpeed = 60.0; - double targetposition = positionStart - m_lnTimer * animationSpeed; - double currentposition = (targetposition > 0.0) ? targetposition : 0.0; + double targetPosition = positionStart - m_lnTimer * animationSpeed; + double currentPosition = (targetPosition > 0.0) ? targetPosition : 0.0; - m_lnLogo->Position2 = UDim2::fromOffset(0, currentposition); + m_lnLogo->Position2 = UDim2::fromOffset(0, currentPosition); m_lnLogo->Draw(delta); - m_lnComboNum->Position2 = UDim2::fromOffset(0, currentposition); + m_lnComboNum->Position2 = UDim2::fromOffset(0, currentPosition); m_lnComboNum->DrawNumber(std::get<9>(scores)); m_lnTimer += delta; From 3d5b64e1cdb4c40ea9f1421371d802988bb21f40 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 21 Jun 2024 15:57:12 +0700 Subject: [PATCH 61/83] refactor: ez2on look like hold note (note percy option) --- Engine/src/Rendering/Renderer.cpp | 2 +- Game/src/Engine/Note.cpp | 17 ++++++++--------- Game/src/Engine/RhythmEngine.cpp | 15 +-------------- Game/src/Scenes/GameplayScene.cpp | 20 +++++++++++++++++--- Game/src/Scenes/Overlays/Settings.cpp | 7 ++----- 5 files changed, 29 insertions(+), 32 deletions(-) diff --git a/Engine/src/Rendering/Renderer.cpp b/Engine/src/Rendering/Renderer.cpp index 62e49a39..6ffb4e3c 100644 --- a/Engine/src/Rendering/Renderer.cpp +++ b/Engine/src/Rendering/Renderer.cpp @@ -96,7 +96,7 @@ bool Renderer::Create(RendererMode mode, GameWindow *window, bool failed) } SDL_SetHint(SDL_HINT_RENDER_DRIVER, rendererName.c_str()); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "Linear"); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); } m_renderer = SDL_CreateRenderer(window->GetWindow(), -1, SDL_RENDERER_ACCELERATED /*| SDL_RENDERER_PRESENTVSYNC*/); diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 12d87023..eccb89c8 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -208,7 +208,7 @@ void Note::Update(double delta) } } -void Note::Render(double delta) // Code more cleared than before +void Note::Render(double delta) { if (IsRemoveable()) { return; @@ -236,8 +236,13 @@ void Note::Render(double delta) // Code more cleared than before double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); bool isTailVisible = isWithinRange(tailPosY, min, max); + if (EnvironmentSetup::GetInt("NoteTail") == 0) { + tailPosY += m_tail->AbsoluteSize.Y; + } + double bodyPosY = (headPosY + tailPosY) / 2.0; - double bodyHeight = std::abs(headPosY - tailPosY); + double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); + m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY); m_body->Size = { 1, 0, 0, bodyHeight }; @@ -245,7 +250,6 @@ void Note::Render(double delta) // Code more cleared than before if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { transparency = 1.0f; } - else if (m_hitResult >= NoteResult::MISS && m_state == NoteState::HOLD_MISSED_ACTIVE) { transparency = 0.7f; } @@ -254,15 +258,10 @@ void Note::Render(double delta) // Code more cleared than before m_body->SetIndexAt(m_engine->GetNoteImageIndex()); m_body->Draw(delta, &playRect); - bool NoteTail = EnvironmentSetup::GetInt("NoteTail") == 1; - if (isTailVisible) { m_tail->Position = UDim2::fromOffset(m_laneOffset, tailPosY); m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); - - if (NoteTail) { - m_tail->Draw(delta, &playRect); - } + m_tail->Draw(delta, &playRect); if (guideLineLength > 0) { m_trail_down->Position = m_tail->Position; diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 0795f45c..313069aa 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -382,16 +382,10 @@ void RhythmEngine::Update(double delta) m_state = GameState::PosGame; } - //if (static_cast(m_currentAudioPosition) % 1000 == 0) { // THIS CAUSING ISSUES NOTE FPS DOES NOT CORRECTLY APPLIED - // m_noteImageIndex = (m_noteImageIndex + 1) % m_noteMaxImageIndex; - //} - - // HACK: I had to use std chrono on this, otherwise it will not accurate and has weird inconsistent frame index static std::chrono::steady_clock::time_point lastUpdateTime = std::chrono::steady_clock::now(); auto currentTime = std::chrono::steady_clock::now(); auto lastUpdate = std::chrono::duration_cast(currentTime - lastUpdateTime); - // Check if it's time to update the note image index if (lastUpdate.count() >= 100) { m_noteImageIndex = (m_noteImageIndex + 1) % m_noteMaxImageIndex; lastUpdateTime = currentTime; @@ -616,14 +610,7 @@ double RhythmEngine::GetGameFrame() const int RhythmEngine::GetPlayTime() const { - bool isPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; - if (isPlaying) - { - return static_cast(m_PlayTime - 5); - } - else { - return 0; - } + return static_cast(m_PlayTime - 5); } int RhythmEngine::GetNoteImageIndex() diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 6569c144..3ef207bc 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -390,9 +390,23 @@ void GameplayScene::Render(double delta) m_waveGage->Draw(&rc); } - int PlayTime = std::clamp(m_game->GetPlayTime(), 0, INT_MAX); - int currentMinutes = PlayTime / 60; - int currentSeconds = PlayTime % 60; + // Fix if playtime sometimes slighly double draw + int PlayTime = 0; + int currentMinutes = 0 / 60; + int currentSeconds = 0 % 60; + + bool isPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; + if (isPlaying) // get timer if on play state + { + PlayTime = std::clamp(m_game->GetPlayTime(), 0, INT_MAX); + currentMinutes = PlayTime / 60; + currentSeconds = PlayTime % 60; + } + else { // get timer but this while game ended or failed + int lastPlayTime = PlayTime; + currentMinutes = lastPlayTime / 60; + currentSeconds = lastPlayTime % 60; + } m_minuteNum->DrawNumber(currentMinutes); m_secondNum->DrawNumber(currentSeconds); diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index a33d33c6..6704870a 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -360,11 +360,8 @@ void SettingsOverlay::Render(double delta) ImGui::SameLine(); - ImGui::Checkbox("Disable Note Tail###SetCheckbox3", &NoteTail); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Why this called No Percy? Lol"); - } - if (NoteTail) { + ImGui::Checkbox("Disable Percy###SetCheckbox3", &NoteTail); + if (NoteTail) { // Leave everything notetail untouched since no reason to make whole changes EnvironmentSetup::SetInt("NoteTail", 0); } else { From 87b58795454b539d61b3c3e0276de68dd8c216d6 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 21 Jun 2024 21:13:30 +0700 Subject: [PATCH 62/83] refactor(note):readjusted lnbody height and pos so it will in the middle of note head and tail --- Game/src/Engine/Note.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index eccb89c8..2d7b8f7a 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -243,7 +243,7 @@ void Note::Render(double delta) double bodyPosY = (headPosY + tailPosY) / 2.0; double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); - m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY); + m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY - (m_head->AbsoluteSize.Y / 2.0)); m_body->Size = { 1, 0, 0, bodyHeight }; float transparency = 0.9f; From 151f3194d2fe23bb43f0a08fe9317f63060a0b5a Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 21 Jun 2024 22:32:52 +0700 Subject: [PATCH 63/83] remove percy option --- Game/src/Engine/Note.cpp | 6 ++-- Game/src/Resources/DefaultConfiguration.h | 2 +- Game/src/Scenes/Overlays/Settings.cpp | 44 ++++++++++++----------- Game/src/Scenes/Overlays/Settings.h | 2 +- 4 files changed, 28 insertions(+), 26 deletions(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 2d7b8f7a..d98eb7e2 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -236,9 +236,9 @@ void Note::Render(double delta) double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); bool isTailVisible = isWithinRange(tailPosY, min, max); - if (EnvironmentSetup::GetInt("NoteTail") == 0) { - tailPosY += m_tail->AbsoluteSize.Y; - } + //if (EnvironmentSetup::GetInt("Percy") == 0) { + // tailPosY += m_tail->AbsoluteSize.Y; + //} double bodyPosY = (headPosY + tailPosY) / 2.0; double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); diff --git a/Game/src/Resources/DefaultConfiguration.h b/Game/src/Resources/DefaultConfiguration.h index 52d2e90e..3fd6a2b6 100644 --- a/Game/src/Resources/DefaultConfiguration.h +++ b/Game/src/Resources/DefaultConfiguration.h @@ -12,7 +12,7 @@ std::string defaultConfiguration = "[game]\n" "renderer = 0\n" "guideline = 1\n" "background = 0\n" - "notetail = 0\n" + //"percy = 1\n" "measureline = 0\n\n" "[keymapping]\n" diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index 6704870a..f5f168dc 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -360,13 +360,15 @@ void SettingsOverlay::Render(double delta) ImGui::SameLine(); - ImGui::Checkbox("Disable Percy###SetCheckbox3", &NoteTail); - if (NoteTail) { // Leave everything notetail untouched since no reason to make whole changes - EnvironmentSetup::SetInt("NoteTail", 0); - } - else { - EnvironmentSetup::SetInt("NoteTail", 1); - } + //ImGui::Checkbox("Disable Percy###SetCheckbox3", &Percy); + //if (Percy) { + // EnvironmentSetup::SetInt("Percy", 0); + //} + //else { + // EnvironmentSetup::SetInt("Percy", 1); + //} + + //TODO: Make new measure line system ImGui::Checkbox("Long Note Head Position at HitPos###SetCheckbox2", &LongNoteOnHitPos); if (ImGui::IsItemHovered()) { @@ -640,20 +642,20 @@ void SettingsOverlay::LoadConfiguration() EnvironmentSetup::SetInt("NoteSkin", 2); } - try { - int noteTailValue = std::stoi(Configuration::Load("Game", "NoteTail")); - NoteTail = (noteTailValue == 1); - } - catch (const std::invalid_argument&) { - NoteTail = true; - } + //try { + // int PercyValue = std::stoi(Configuration::Load("Game", "Percy")); + // Percy = (PercyValue == 1); + //} + //catch (const std::invalid_argument&) { + // Percy = true; + //} - if (NoteTail) { // HACK: Same workaround like Background :troll: - EnvironmentSetup::SetInt("NoteTail", 0); - } - else { - EnvironmentSetup::SetInt("NoteTail", 1); - } + //if (Percy) { // HACK: Same workaround like Background :troll: + // EnvironmentSetup::SetInt("Percy", 0); + //} + //else { + // EnvironmentSetup::SetInt("Percy", 1); + //} try { int measureLineValue = std::stoi(Configuration::Load("Game", "MeasureLine")); @@ -683,7 +685,7 @@ void SettingsOverlay::SaveConfiguration() Configuration::Set("Game", "NoteSkin", std::to_string(NoteIndex)); Configuration::Set("Game", "Background", std::to_string(BackgroundIndex)); Configuration::Set("Game", "MeasureLine", std::to_string(MeasureLine ? 1 : 0)); - Configuration::Set("Game", "NoteTail", std::to_string(NoteTail ? 1 : 0)); + //Configuration::Set("Game", "Percy", std::to_string(Percy ? 1 : 0)); if (currentFPSIndex == GetFpsOptions().size() - 1 && customFPS > 0) { Configuration::Set("Game", "FrameLimit", std::to_string(customFPS)); diff --git a/Game/src/Scenes/Overlays/Settings.h b/Game/src/Scenes/Overlays/Settings.h index ca5938e3..5c2d6593 100644 --- a/Game/src/Scenes/Overlays/Settings.h +++ b/Game/src/Scenes/Overlays/Settings.h @@ -27,7 +27,7 @@ class SettingsOverlay : public Overlay bool LongNoteLighting = false; bool LongNoteOnHitPos = false; bool MeasureLine = false; - bool NoteTail = false; + bool Percy = false; int BackgroundIndex = 0; int NoteIndex = 0; bool convertAutoSound = false; From e6b399dac02f2c59f0e6dd7dc2549bc5f38fa541 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sat, 22 Jun 2024 11:29:52 +0700 Subject: [PATCH 64/83] refactor: add new measure line type, remove useless options --- Game/src/Engine/Note.cpp | 13 ++-- Game/src/Engine/Note.hpp | 14 ++-- Game/src/Engine/RhythmEngine.cpp | 2 +- Game/src/Engine/TimingLine.cpp | 12 +++- Game/src/Resources/DefaultConfiguration.h | 6 +- Game/src/Scenes/GameplayScene.cpp | 7 +- Game/src/Scenes/Overlays/Settings.cpp | 85 +++++++++-------------- Game/src/Scenes/Overlays/Settings.h | 2 +- 8 files changed, 65 insertions(+), 76 deletions(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index d98eb7e2..2fefe28c 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -290,6 +290,7 @@ void Note::Render(double delta) } if (isHeadVisible) { + EnvironmentSetup::SetInt("HalfNoteSize", m_head->AbsoluteSize.Y / 2.0); m_head->Position = UDim2::fromOffset(m_laneOffset, headPosY); m_head->SetIndexAt(m_engine->GetNoteImageIndex()); m_head->Draw(delta, &playRect); @@ -533,12 +534,12 @@ void Note::SetDrawable(bool drawable) m_drawAble = drawable; } -bool Note::IsHoldEffectDrawable() +bool Note::IsHoldEffectDrawable() const { return m_shouldDrawHoldEffect; } -bool Note::IsDrawable() +bool Note::IsDrawable() const { if (m_removeAble) return false; @@ -546,22 +547,22 @@ bool Note::IsDrawable() return m_drawAble; } -bool Note::IsRemoveable() +bool Note::IsRemoveable() const { return m_state == NoteState::DO_REMOVE; } -bool Note::IsPassed() +bool Note::IsPassed() const { return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED || IsRemoveable(); } -bool Note::IsHeadHit() +bool Note::IsHeadHit() const { return m_didHitHead; } -bool Note::IsTailHit() +bool Note::IsTailHit() const { return m_didHitTail; } diff --git a/Game/src/Engine/Note.hpp b/Game/src/Engine/Note.hpp index 8061113a..bad8979b 100644 --- a/Game/src/Engine/Note.hpp +++ b/Game/src/Engine/Note.hpp @@ -71,14 +71,14 @@ class Note { void SetXPosition(int x); void SetDrawable(bool drawable); - - bool IsHoldEffectDrawable(); - bool IsDrawable(); - bool IsRemoveable(); - bool IsPassed(); - bool IsHeadHit(); - bool IsTailHit(); + bool IsHoldEffectDrawable() const; + bool IsDrawable() const; + bool IsRemoveable() const; + bool IsPassed() const; + + bool IsHeadHit() const; + bool IsTailHit() const; void Release(); diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 313069aa..fc2327fc 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "../EnvironmentSetup.hpp" #include "Configuration.h" diff --git a/Game/src/Engine/TimingLine.cpp b/Game/src/Engine/TimingLine.cpp index f9724811..b08b5bf0 100644 --- a/Game/src/Engine/TimingLine.cpp +++ b/Game/src/Engine/TimingLine.cpp @@ -1,6 +1,7 @@ #include "TimingLine.hpp" #include "RhythmEngine.hpp" #include "Texture/ResizableImage.h" +#include "../EnvironmentSetup.hpp" namespace { double CalculateLinePosition(double trackOffset, double offset, double noteSpeed, bool upscroll = false) @@ -62,8 +63,17 @@ void TimingLine::Render(double delta) double min = 0, max = hitPos; double pos_y = min + (max - min) * alpha; + int halfNoteSize; + + if (EnvironmentSetup::GetInt("MeasureLineType") == 1) { + halfNoteSize = static_cast(EnvironmentSetup::GetInt("HalfNoteSize")); + } + else { + halfNoteSize = 0; + } + m_line->Size = UDim2::fromOffset(m_imageSize, 1); - m_line->Position = UDim2::fromOffset(m_imagePos, pos_y); //+ start.Lerp(end, alpha); + m_line->Position = UDim2::fromOffset(m_imagePos, pos_y - halfNoteSize); //+ start.Lerp(end, alpha); if (m_line->Position.Y.Offset >= 0 && m_line->Position.Y.Offset < hitPos + 10) { m_line->TintColor = { 0.7f, 0.7f, 0.7f }; diff --git a/Game/src/Resources/DefaultConfiguration.h b/Game/src/Resources/DefaultConfiguration.h index 3fd6a2b6..4824ee27 100644 --- a/Game/src/Resources/DefaultConfiguration.h +++ b/Game/src/Resources/DefaultConfiguration.h @@ -7,13 +7,13 @@ std::string defaultConfiguration = "[game]\n" "framelimit = 240\n" // Default 144 but i set this for more reasonable "audiooffset = 0\n" "audiovolume = 100\n" - "autosound = 1\n" + "autosound = 0\n" "resolution = 1280x720\n" // Fix for most monitor "renderer = 0\n" "guideline = 1\n" "background = 0\n" - //"percy = 1\n" - "measureline = 0\n\n" + "measureline = 1\n" + "measurelinetype = 0\n\n" "[keymapping]\n" "lane1 = A\n" diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 3ef207bc..b92c219f 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -151,17 +151,14 @@ void GameplayScene::Render(double delta) int arena = EnvironmentSetup::GetInt("Arena"); - bool useSongBG = EnvironmentSetup::GetInt("Song Background") == 1; - bool blackBG = EnvironmentSetup::GetInt("Black Background") == 1; - - if (useSongBG) { + if (EnvironmentSetup::GetInt("Background") == 1) { auto songBG = (Texture2D*)EnvironmentSetup::GetObj("SongBackground"); if (songBG) { songBG->TintColor = Color3::FromRGB(128, 128, 128); songBG->Draw(); } } - else if (blackBG) { + else if (EnvironmentSetup::GetInt("Background") == 2) { // Do nothing } else { diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index f5f168dc..252754d4 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -353,29 +353,16 @@ void SettingsOverlay::Render(double delta) ImGui::Text("Gameplay-Related Configuration"); - ImGui::Checkbox("Long Note Lighting###SetCheckbox1", &LongNoteLighting); + ImGui::Checkbox("Use New Measure Line###SetCheckbox3", &MeasureLineType); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("When Long note on hold, change the lighting brightness to 100%% else 90%% brightness"); + ImGui::SetTooltip("Measure line position in the middle of the note; otherwise, it will be at the bottom of the note"); } - - ImGui::SameLine(); - - //ImGui::Checkbox("Disable Percy###SetCheckbox3", &Percy); - //if (Percy) { - // EnvironmentSetup::SetInt("Percy", 0); - //} - //else { - // EnvironmentSetup::SetInt("Percy", 1); - //} - - //TODO: Make new measure line system - - ImGui::Checkbox("Long Note Head Position at HitPos###SetCheckbox2", &LongNoteOnHitPos); - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("When Long note on hold, make the head position at hit position else keep going to bottom"); + if (MeasureLineType) { + EnvironmentSetup::SetInt("MeasureLineType", 1); + } + else { + EnvironmentSetup::SetInt("MeasureLineType", 0); } - - ImGui::SameLine(); ImGui::Checkbox("Disable Measure Line###SetCheckbox4", &MeasureLine); if (MeasureLine) { @@ -473,17 +460,14 @@ void SettingsOverlay::Render(double delta) ImGui::SameLine(); } - if (BackgroundIndex == 0) { - EnvironmentSetup::SetInt("Song Background", 0); - EnvironmentSetup::SetInt("Black Background", 0); - } - else if (BackgroundIndex == 1) { - EnvironmentSetup::SetInt("Song Background", 1); - EnvironmentSetup::SetInt("Black Background", 0); + if (BackgroundIndex == 1) { + EnvironmentSetup::SetInt("Background", 1); } else if (BackgroundIndex == 2) { - EnvironmentSetup::SetInt("Song Background", 0); - EnvironmentSetup::SetInt("Black Background", 1); + EnvironmentSetup::SetInt("Background", 2); + } + else { + EnvironmentSetup::SetInt("Background", 0); } ImGui::EndTabItem(); @@ -612,17 +596,14 @@ void SettingsOverlay::LoadConfiguration() BackgroundIndex = 0; } - if (BackgroundIndex == 0) { // HACK: Solution for issue background not applied even configuration already loaded - EnvironmentSetup::SetInt("Song Background", 0); - EnvironmentSetup::SetInt("Black Background", 0); - } - else if (BackgroundIndex == 1) { - EnvironmentSetup::SetInt("Song Background", 1); - EnvironmentSetup::SetInt("Black Background", 0); + if (BackgroundIndex == 1) { + EnvironmentSetup::SetInt("Background", 1); } else if (BackgroundIndex == 2) { - EnvironmentSetup::SetInt("Song Background", 0); - EnvironmentSetup::SetInt("Black Background", 1); + EnvironmentSetup::SetInt("Background", 2); + } + else { + EnvironmentSetup::SetInt("Background", 0); } try { @@ -642,20 +623,20 @@ void SettingsOverlay::LoadConfiguration() EnvironmentSetup::SetInt("NoteSkin", 2); } - //try { - // int PercyValue = std::stoi(Configuration::Load("Game", "Percy")); - // Percy = (PercyValue == 1); - //} - //catch (const std::invalid_argument&) { - // Percy = true; - //} + try { + int MeasureLineTypeValue = std::stoi(Configuration::Load("Game", "MeasureLineType")); + MeasureLineType = (MeasureLineTypeValue == 1); + } + catch (const std::invalid_argument&) { + MeasureLineType = false; + } - //if (Percy) { // HACK: Same workaround like Background :troll: - // EnvironmentSetup::SetInt("Percy", 0); - //} - //else { - // EnvironmentSetup::SetInt("Percy", 1); - //} + if (MeasureLineType) { + EnvironmentSetup::SetInt("MeasureLineType", 1); + } + else { + EnvironmentSetup::SetInt("MeasureLineType", 0); + } try { int measureLineValue = std::stoi(Configuration::Load("Game", "MeasureLine")); @@ -685,7 +666,7 @@ void SettingsOverlay::SaveConfiguration() Configuration::Set("Game", "NoteSkin", std::to_string(NoteIndex)); Configuration::Set("Game", "Background", std::to_string(BackgroundIndex)); Configuration::Set("Game", "MeasureLine", std::to_string(MeasureLine ? 1 : 0)); - //Configuration::Set("Game", "Percy", std::to_string(Percy ? 1 : 0)); + Configuration::Set("Game", "MeasureLineType", std::to_string(MeasureLineType ? 1 : 0)); if (currentFPSIndex == GetFpsOptions().size() - 1 && customFPS > 0) { Configuration::Set("Game", "FrameLimit", std::to_string(customFPS)); diff --git a/Game/src/Scenes/Overlays/Settings.h b/Game/src/Scenes/Overlays/Settings.h index 5c2d6593..63c9dde1 100644 --- a/Game/src/Scenes/Overlays/Settings.h +++ b/Game/src/Scenes/Overlays/Settings.h @@ -27,7 +27,7 @@ class SettingsOverlay : public Overlay bool LongNoteLighting = false; bool LongNoteOnHitPos = false; bool MeasureLine = false; - bool Percy = false; + bool MeasureLineType = false; int BackgroundIndex = 0; int NoteIndex = 0; bool convertAutoSound = false; From 3c2bce721a2cb9b8e1ebc41dbe12b20fdf7a91d9 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:18:16 +0700 Subject: [PATCH 65/83] refactor(note):add option Long Note Body On Top for few skins and refactor note code --- Game/src/Engine/Note.cpp | 198 ++++++++++++++++---------- Game/src/Engine/Note.hpp | 4 + Game/src/Scenes/Overlays/Settings.cpp | 34 ++++- Game/src/Scenes/Overlays/Settings.h | 3 +- 4 files changed, 157 insertions(+), 82 deletions(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 2fefe28c..a0bca658 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -208,6 +208,87 @@ void Note::Update(double delta) } } +// I ended refactor whole note code +void Note::DrawNoteHead(double delta, double headPosY, int guideLineLength, Rect &playRect) { + m_head->Position = UDim2::fromOffset(m_laneOffset, headPosY); + m_head->SetIndexAt(m_engine->GetNoteImageIndex()); + m_head->Draw(delta, &playRect); + + if (guideLineLength > 0) { + m_trail_down->Position = m_head->Position; + m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_down->AnchorPoint = { 0, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); + m_trail_down->AnchorPoint = { 1, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_up->Position = m_head->Position + UDim2::fromOffset(0, -m_head->AbsoluteSize.Y); + m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_up->AnchorPoint = { 0, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + + m_trail_up->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, -m_head->AbsoluteSize.Y); + m_trail_up->AnchorPoint = { 1, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + } +} + +void Note::DrawNoteBody(double delta, double bodyPosY, double bodyHeight, Rect &playRect) { + m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY - (m_head->AbsoluteSize.Y / 2.0)); + m_body->Size = { 1, 0, 0, bodyHeight }; + m_body->SetIndexAt(m_engine->GetNoteImageIndex()); + m_body->Draw(delta, &playRect); +} + +void Note::DrawNoteTail(double delta, double tailPosY, int guideLineLength, Rect &playRect) { + m_tail->Position = UDim2::fromOffset(m_laneOffset, tailPosY); + m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); + m_tail->Draw(delta, &playRect); + + if (guideLineLength > 0) { + m_trail_down->Position = m_tail->Position; + m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_down->AnchorPoint = { 0, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_down->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, 0); + m_trail_down->AnchorPoint = { 1, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_up->Position = m_tail->Position + UDim2::fromOffset(0, -m_tail->AbsoluteSize.Y); + m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_up->AnchorPoint = { 0, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + + m_trail_up->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, -m_tail->AbsoluteSize.Y); + m_trail_up->AnchorPoint = { 1, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + } +} + +void Note::SetTransparency() { + float transparency = 0.9f; + if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { + transparency = 1.0f; + } + else if (m_hitResult >= NoteResult::MISS && m_state == NoteState::HOLD_MISSED_ACTIVE) { + transparency = 0.7f; + } + m_head->TintColor = { transparency, transparency, transparency }; + m_body->TintColor = { transparency, transparency, transparency }; + m_tail->TintColor = { transparency, transparency, transparency }; +} + void Note::Render(double delta) { if (IsRemoveable()) { @@ -231,92 +312,55 @@ void Note::Render(double delta) double headPosY = lerp(0.0, static_cast(hitPos), static_cast(y1)); bool isHeadVisible = isWithinRange(headPosY, min, max); - if (m_type == NoteType::HOLD) { - double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; - double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); - bool isTailVisible = isWithinRange(tailPosY, min, max); + if (EnvironmentSetup::GetInt("LNBodyOnTop") == 1) { + if (isHeadVisible) { + EnvironmentSetup::SetInt("HalfNoteSize", m_head->AbsoluteSize.Y / 2.0); + DrawNoteHead(delta, headPosY, guideLineLength, playRect); + } - //if (EnvironmentSetup::GetInt("Percy") == 0) { - // tailPosY += m_tail->AbsoluteSize.Y; - //} + if (m_type == NoteType::HOLD) { + double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; + double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); + bool isTailVisible = isWithinRange(tailPosY, min, max); - double bodyPosY = (headPosY + tailPosY) / 2.0; - double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); + if (EnvironmentSetup::GetInt("NoPercy") == 1) { + tailPosY += m_tail->AbsoluteSize.Y; + } - m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY - (m_head->AbsoluteSize.Y / 2.0)); - m_body->Size = { 1, 0, 0, bodyHeight }; + double bodyPosY = (headPosY + tailPosY) / 2.0; + double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); - float transparency = 0.9f; - if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { - transparency = 1.0f; - } - else if (m_hitResult >= NoteResult::MISS && m_state == NoteState::HOLD_MISSED_ACTIVE) { - transparency = 0.7f; + if (isTailVisible) { + DrawNoteTail(delta, tailPosY, guideLineLength, playRect); + } + + SetTransparency(); + DrawNoteBody(delta, bodyPosY, bodyHeight, playRect); } + } + else { + if (m_type == NoteType::HOLD) { + double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; + double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); + bool isTailVisible = isWithinRange(tailPosY, min, max); + + if (EnvironmentSetup::GetInt("NoPercy") == 1) { + tailPosY += m_tail->AbsoluteSize.Y; + } - m_body->TintColor = { transparency, transparency, transparency }; - m_body->SetIndexAt(m_engine->GetNoteImageIndex()); - m_body->Draw(delta, &playRect); - - if (isTailVisible) { - m_tail->Position = UDim2::fromOffset(m_laneOffset, tailPosY); - m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); - m_tail->Draw(delta, &playRect); - - if (guideLineLength > 0) { - m_trail_down->Position = m_tail->Position; - m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_down->AnchorPoint = { 0, 0 }; - m_trail_down->AlphaBlend = true; - m_trail_down->Draw(delta, &playRect); - - m_trail_down->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, 0); - m_trail_down->AnchorPoint = { 1, 0 }; - m_trail_down->AlphaBlend = true; - m_trail_down->Draw(delta, &playRect); - - m_trail_up->Position = m_tail->Position + UDim2::fromOffset(0, -m_tail->AbsoluteSize.Y); - m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_up->AnchorPoint = { 0, 1 }; - m_trail_up->AlphaBlend = true; - m_trail_up->Draw(delta, &playRect); - - m_trail_up->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, -m_tail->AbsoluteSize.Y); - m_trail_up->AnchorPoint = { 1, 1 }; - m_trail_up->AlphaBlend = true; - m_trail_up->Draw(delta, &playRect); + double bodyPosY = (headPosY + tailPosY) / 2.0; + double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); + + SetTransparency(); + DrawNoteBody(delta, bodyPosY, bodyHeight, playRect); + + if (isTailVisible) { + DrawNoteTail(delta, tailPosY, guideLineLength, playRect); } } - } - if (isHeadVisible) { - EnvironmentSetup::SetInt("HalfNoteSize", m_head->AbsoluteSize.Y / 2.0); - m_head->Position = UDim2::fromOffset(m_laneOffset, headPosY); - m_head->SetIndexAt(m_engine->GetNoteImageIndex()); - m_head->Draw(delta, &playRect); - - if (guideLineLength > 0) { - m_trail_down->Position = m_head->Position; - m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_down->AnchorPoint = { 0, 0 }; - m_trail_down->AlphaBlend = true; - m_trail_down->Draw(delta, &playRect); - - m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); - m_trail_down->AnchorPoint = { 1, 0 }; - m_trail_down->AlphaBlend = true; - m_trail_down->Draw(delta, &playRect); - - m_trail_up->Position = m_head->Position + UDim2::fromOffset(0, -m_head->AbsoluteSize.Y); - m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_up->AnchorPoint = { 0, 1 }; - m_trail_up->AlphaBlend = true; - m_trail_up->Draw(delta, &playRect); - - m_trail_up->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, -m_head->AbsoluteSize.Y); - m_trail_up->AnchorPoint = { 1, 1 }; - m_trail_up->AlphaBlend = true; - m_trail_up->Draw(delta, &playRect); + if (isHeadVisible) { + DrawNoteHead(delta, headPosY, guideLineLength, playRect); } } } diff --git a/Game/src/Engine/Note.hpp b/Game/src/Engine/Note.hpp index bad8979b..1af5bf4a 100644 --- a/Game/src/Engine/Note.hpp +++ b/Game/src/Engine/Note.hpp @@ -52,6 +52,10 @@ class Note { void Load(NoteInfoDesc* desc); void Update(double delta); + void DrawNoteHead(double delta, double headPosY, int guideLineLength, Rect& playRect); + void DrawNoteBody(double delta, double bodyPosY, double bodyHeight, Rect& playRect); + void DrawNoteTail(double delta, double tailPosY, int guideLineLength, Rect& playRect); + void SetTransparency(); void Render(double delta); double GetInitialTrackPosition() const; diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index 252754d4..20ca63e1 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -348,12 +348,13 @@ void SettingsOverlay::Render(double delta) } } + ImGui::NewLine(); ImGui::NewLine(); ImGui::NewLine(); ImGui::Text("Gameplay-Related Configuration"); - ImGui::Checkbox("Use New Measure Line###SetCheckbox3", &MeasureLineType); + ImGui::Checkbox("Use New Measure Line###SetCheckbox1", &MeasureLineType); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Measure line position in the middle of the note; otherwise, it will be at the bottom of the note"); } @@ -364,7 +365,7 @@ void SettingsOverlay::Render(double delta) EnvironmentSetup::SetInt("MeasureLineType", 0); } - ImGui::Checkbox("Disable Measure Line###SetCheckbox4", &MeasureLine); + ImGui::Checkbox("Disable Measure Line###SetCheckbox2", &MeasureLine); if (MeasureLine) { EnvironmentSetup::SetInt("MeasureLine", 0); } @@ -372,6 +373,17 @@ void SettingsOverlay::Render(double delta) EnvironmentSetup::SetInt("MeasureLine", 1); } + ImGui::Checkbox("Long Note Body On Top###SetCheckbox3", &LNBodyOnTop); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("If your note skin has issues, enable this option!"); + } + if (LNBodyOnTop) { + EnvironmentSetup::SetInt("LNBodyOnTop", 1); + } + else { + EnvironmentSetup::SetInt("LNBodyOnTop", 0); + } + ImGui::EndTabItem(); } @@ -646,13 +658,28 @@ void SettingsOverlay::LoadConfiguration() MeasureLine = true; } - if (MeasureLine) { // HACK: Same workaround like Background :troll: + if (MeasureLine) { EnvironmentSetup::SetInt("MeasureLine", 0); } else { EnvironmentSetup::SetInt("MeasureLine", 1); } + try { + int LNBodyOnTopValue = std::stoi(Configuration::Load("Game", "LNBodyOnTop")); + LNBodyOnTop = (LNBodyOnTopValue == 1); + } + catch (const std::invalid_argument&) { + LNBodyOnTop = true; + } + + if (LNBodyOnTop) { + EnvironmentSetup::SetInt("LNBodyOnTop", 1); + } + else { + EnvironmentSetup::SetInt("LNBodyOnTop", 0); + } + currentSkin = Configuration::Load("Game", "Skin"); PreloadSkin(); } @@ -667,6 +694,7 @@ void SettingsOverlay::SaveConfiguration() Configuration::Set("Game", "Background", std::to_string(BackgroundIndex)); Configuration::Set("Game", "MeasureLine", std::to_string(MeasureLine ? 1 : 0)); Configuration::Set("Game", "MeasureLineType", std::to_string(MeasureLineType ? 1 : 0)); + Configuration::Set("Game", "LNBodyOnTop", std::to_string(LNBodyOnTop ? 1 : 0)); if (currentFPSIndex == GetFpsOptions().size() - 1 && customFPS > 0) { Configuration::Set("Game", "FrameLimit", std::to_string(customFPS)); diff --git a/Game/src/Scenes/Overlays/Settings.h b/Game/src/Scenes/Overlays/Settings.h index 63c9dde1..65732c29 100644 --- a/Game/src/Scenes/Overlays/Settings.h +++ b/Game/src/Scenes/Overlays/Settings.h @@ -24,9 +24,8 @@ class SettingsOverlay : public Overlay int currentOffset = 0; int currentResolutionIndex = 0; int currentGuideLineIndex = 0; - bool LongNoteLighting = false; - bool LongNoteOnHitPos = false; bool MeasureLine = false; + bool LNBodyOnTop = false; bool MeasureLineType = false; int BackgroundIndex = 0; int NoteIndex = 0; From 2c6253916c4fb7c43dd7fb8a651d31195521a734 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:20:43 +0700 Subject: [PATCH 66/83] --- Game/src/Resources/DefaultConfiguration.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Game/src/Resources/DefaultConfiguration.h b/Game/src/Resources/DefaultConfiguration.h index 4824ee27..260f7500 100644 --- a/Game/src/Resources/DefaultConfiguration.h +++ b/Game/src/Resources/DefaultConfiguration.h @@ -13,7 +13,8 @@ std::string defaultConfiguration = "[game]\n" "guideline = 1\n" "background = 0\n" "measureline = 1\n" - "measurelinetype = 0\n\n" + "measurelinetype = 0\n" + "lnbodyontop = 0\n\n" "[keymapping]\n" "lane1 = A\n" From 06891f2bd0290e6b24d35e52d3e8003323507500 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:36:51 +0700 Subject: [PATCH 67/83] --- Game/src/Engine/Note.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index a0bca658..b62a8fef 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -360,6 +360,7 @@ void Note::Render(double delta) } if (isHeadVisible) { + EnvironmentSetup::SetInt("HalfNoteSize", m_head->AbsoluteSize.Y / 2.0); DrawNoteHead(delta, headPosY, guideLineLength, playRect); } } From ecf34746e898d43e79f2313e28cca748a61c48de Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sat, 22 Jun 2024 16:39:06 +0700 Subject: [PATCH 68/83] --- Game/src/Engine/TimingLine.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Game/src/Engine/TimingLine.cpp b/Game/src/Engine/TimingLine.cpp index b08b5bf0..57979304 100644 --- a/Game/src/Engine/TimingLine.cpp +++ b/Game/src/Engine/TimingLine.cpp @@ -83,5 +83,6 @@ void TimingLine::Render(double delta) void TimingLine::Release() { + EnvironmentSetup::SetInt("HalfNoteSize", 0); delete m_line; } From 11ff090607e5acc1caec033d7424bc3fc5608e68 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Thu, 27 Jun 2024 16:04:38 +0700 Subject: [PATCH 69/83] refactor(chart): fix stupid vector subscript out of range and adjustLaneIndex based on keyCount --- Game/src/Data/Chart.cpp | 51 ++++++++++++++++++++------- Game/src/Data/Chart.hpp | 2 ++ Game/src/Engine/Note.cpp | 4 +-- Game/src/Scenes/Overlays/Settings.cpp | 4 +-- 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index cb2dda74..c68fa0d8 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -158,16 +158,6 @@ Chart::Chart(Osu::Beatmap& beatmap) // Refactor } } - // TODO: This thing causing game crash, weird, NEED to be fixed - //for (auto& note : m_notes) { - // if (m_keyCount == 4 && note.LaneIndex >= 2) { - // note.LaneIndex += 3; - // } - // else if (m_keyCount == 5 && (note.LaneIndex == 3 || note.LaneIndex >= 4)) { - // note.LaneIndex += 2; - // } - //} - for (int i = 0; i < beatmap.HitSamples.size(); i++) { auto& keysound = beatmap.HitSamples[i]; auto path = beatmap.CurrentDir / keysound; @@ -181,6 +171,7 @@ Chart::Chart(Osu::Beatmap& beatmap) // Refactor CalculateBeat(); SortTimings(); NormalizeTimings(); + AdjustLaneIndex(); ComputeKeyCount(); ComputeHash(); } @@ -705,6 +696,41 @@ void Chart::NormalizeTimings() m_svs = result; } +void Chart::AdjustLaneIndex() // Fix vector subscript out of range +{ + for (auto& note : m_notes) { + switch (m_keyCount) { // Fuck, this hard to figure out + case 4: + { + if (note.LaneIndex >= 2) { + note.LaneIndex += 3; + } + break; + } + case 5: + { + if (note.LaneIndex == 2) { + note.LaneIndex += 1; + } + else if (note.LaneIndex >= 3) { + note.LaneIndex += 2; + } + break; + } + case 6: + { + if (note.LaneIndex >= 3) { + note.LaneIndex += 1; + } + break; + } + default: + m_keyCount = 7; + break; + } + } +} + void Chart::ComputeKeyCount() { bool Lanes[7] = { false, false, false, false, false, false }; @@ -717,7 +743,7 @@ void Chart::ComputeKeyCount() // BMS-O2 4K is: X X - - - X X // BMS-O2 5K is: X X - X - X X - // BMS-O2 6K is: X X X - X X X + // BMS-O2 6K is: X X X X X X - // BMS-O2 7K is: X X X X X X X // Check for 7K first since it has the highest priority @@ -725,7 +751,7 @@ void Chart::ComputeKeyCount() m_keyCount = 7; } // Check for 6K - else if (Lanes[0] && Lanes[1] && Lanes[2] && !Lanes[3] && Lanes[4] && Lanes[5] && Lanes[6]) { + else if (Lanes[0] && Lanes[1] && Lanes[2] && Lanes[3] && Lanes[4] && Lanes[5] && !Lanes[6]) { m_keyCount = 6; } // Check for 5K @@ -736,7 +762,6 @@ void Chart::ComputeKeyCount() else if (Lanes[0] && Lanes[1] && !Lanes[2] && !Lanes[3] && !Lanes[4] && Lanes[5] && Lanes[6]) { m_keyCount = 4; } - // Otherwise, the pattern does not match any of the known K values else { Logs::Puts("[Chart] Unknown lane pattern, fallback to 7K"); m_keyCount = 7; diff --git a/Game/src/Data/Chart.hpp b/Game/src/Data/Chart.hpp index 546e7e38..e069bfe0 100644 --- a/Game/src/Data/Chart.hpp +++ b/Game/src/Data/Chart.hpp @@ -118,6 +118,8 @@ class Chart std::vector m_samples; std::vector m_autoSamples; + void AdjustLaneIndex(); + private: double PredefinedAudioLength = -1; diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index b62a8fef..d24edc3e 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -314,7 +314,7 @@ void Note::Render(double delta) if (EnvironmentSetup::GetInt("LNBodyOnTop") == 1) { if (isHeadVisible) { - EnvironmentSetup::SetInt("HalfNoteSize", m_head->AbsoluteSize.Y / 2.0); + EnvironmentSetup::SetInt("HalfNoteSize", static_cast(m_head->AbsoluteSize.Y) / 2); DrawNoteHead(delta, headPosY, guideLineLength, playRect); } @@ -360,7 +360,7 @@ void Note::Render(double delta) } if (isHeadVisible) { - EnvironmentSetup::SetInt("HalfNoteSize", m_head->AbsoluteSize.Y / 2.0); + EnvironmentSetup::SetInt("HalfNoteSize", static_cast(m_head->AbsoluteSize.Y) / 2); DrawNoteHead(delta, headPosY, guideLineLength, playRect); } } diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index 20ca63e1..15d7ba8b 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -582,11 +582,11 @@ void SettingsOverlay::LoadConfiguration() auto fpsOptions = GetFpsOptions(); auto it = std::find(fpsOptions.begin(), fpsOptions.end(), frameLimit); if (it != fpsOptions.end()) { - currentFPSIndex = std::distance(fpsOptions.begin(), it); + currentFPSIndex = static_cast(std::distance(fpsOptions.begin(), it)); customFPS = 0; } else { - currentFPSIndex = fpsOptions.size() - 1; + currentFPSIndex = static_cast(fpsOptions.size()) - 1; customFPS = 9999; } } From aa5b13ef9934dbe909e54a5b334b4dbc9799bf92 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Thu, 27 Jun 2024 16:15:28 +0700 Subject: [PATCH 70/83] refector(noteimagecachemanaher): remove useless code --- Game/src/Engine/NoteImageCacheManager.cpp | 7 ------- Game/src/Engine/NoteImageCacheManager.hpp | 5 ----- 2 files changed, 12 deletions(-) diff --git a/Game/src/Engine/NoteImageCacheManager.cpp b/Game/src/Engine/NoteImageCacheManager.cpp index b148740c..a5debe85 100644 --- a/Game/src/Engine/NoteImageCacheManager.cpp +++ b/Game/src/Engine/NoteImageCacheManager.cpp @@ -4,10 +4,6 @@ constexpr int MAX_OBJECTS = 64; NoteImageCacheManager::NoteImageCacheManager() { - m_totalCount = 0; - m_totalNoteCount = 0; - m_totalHoldCount = 0; - m_totalTrailCount = 0; } NoteImageCacheManager::~NoteImageCacheManager() { @@ -59,7 +55,6 @@ void NoteImageCacheManager::Repool(DrawableNote* image, NoteImageType noteType) return; m_noteTextures[noteType].push_back(image); - m_totalNoteCount++; } void NoteImageCacheManager::RepoolHold(DrawableNote* image, NoteImageType noteType) { @@ -67,7 +62,6 @@ void NoteImageCacheManager::RepoolHold(DrawableNote* image, NoteImageType noteTy return; m_holdTextures[noteType].push_back(image); - m_totalHoldCount++; } void NoteImageCacheManager::RepoolTrail(DrawableNote* image, NoteImageType noteType) { @@ -75,7 +69,6 @@ void NoteImageCacheManager::RepoolTrail(DrawableNote* image, NoteImageType noteT return; m_trailTextures[noteType].push_back(image); - m_totalTrailCount++; } DrawableNote* NoteImageCacheManager::Depool(NoteImageType noteType) { diff --git a/Game/src/Engine/NoteImageCacheManager.hpp b/Game/src/Engine/NoteImageCacheManager.hpp index 37957fa7..3850a41b 100644 --- a/Game/src/Engine/NoteImageCacheManager.hpp +++ b/Game/src/Engine/NoteImageCacheManager.hpp @@ -25,11 +25,6 @@ class NoteImageCacheManager static void Release(); private: - size_t m_totalCount; - size_t m_totalNoteCount; - size_t m_totalHoldCount; - size_t m_totalTrailCount; - static NoteImageCacheManager* s_instance; std::unordered_map> m_noteTextures; From edcac055e567ee6781ad723d5135ec1a4bb813a2 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Thu, 4 Jul 2024 23:19:55 +0700 Subject: [PATCH 71/83] --- Game/src/Engine/Note.cpp | 18 +++++++++--------- Game/src/Engine/Note.hpp | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index d24edc3e..ad591ec6 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -209,7 +209,7 @@ void Note::Update(double delta) } // I ended refactor whole note code -void Note::DrawNoteHead(double delta, double headPosY, int guideLineLength, Rect &playRect) { +void Note::DrawHead(double delta, double headPosY, int guideLineLength, Rect &playRect) { m_head->Position = UDim2::fromOffset(m_laneOffset, headPosY); m_head->SetIndexAt(m_engine->GetNoteImageIndex()); m_head->Draw(delta, &playRect); @@ -239,14 +239,14 @@ void Note::DrawNoteHead(double delta, double headPosY, int guideLineLength, Rect } } -void Note::DrawNoteBody(double delta, double bodyPosY, double bodyHeight, Rect &playRect) { +void Note::DrawBody(double delta, double bodyPosY, double bodyHeight, Rect &playRect) { m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY - (m_head->AbsoluteSize.Y / 2.0)); m_body->Size = { 1, 0, 0, bodyHeight }; m_body->SetIndexAt(m_engine->GetNoteImageIndex()); m_body->Draw(delta, &playRect); } -void Note::DrawNoteTail(double delta, double tailPosY, int guideLineLength, Rect &playRect) { +void Note::DrawTail(double delta, double tailPosY, int guideLineLength, Rect &playRect) { m_tail->Position = UDim2::fromOffset(m_laneOffset, tailPosY); m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); m_tail->Draw(delta, &playRect); @@ -315,7 +315,7 @@ void Note::Render(double delta) if (EnvironmentSetup::GetInt("LNBodyOnTop") == 1) { if (isHeadVisible) { EnvironmentSetup::SetInt("HalfNoteSize", static_cast(m_head->AbsoluteSize.Y) / 2); - DrawNoteHead(delta, headPosY, guideLineLength, playRect); + DrawHead(delta, headPosY, guideLineLength, playRect); } if (m_type == NoteType::HOLD) { @@ -331,11 +331,11 @@ void Note::Render(double delta) double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); if (isTailVisible) { - DrawNoteTail(delta, tailPosY, guideLineLength, playRect); + DrawTail(delta, tailPosY, guideLineLength, playRect); } SetTransparency(); - DrawNoteBody(delta, bodyPosY, bodyHeight, playRect); + DrawBody(delta, bodyPosY, bodyHeight, playRect); } } else { @@ -352,16 +352,16 @@ void Note::Render(double delta) double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); SetTransparency(); - DrawNoteBody(delta, bodyPosY, bodyHeight, playRect); + DrawBody(delta, bodyPosY, bodyHeight, playRect); if (isTailVisible) { - DrawNoteTail(delta, tailPosY, guideLineLength, playRect); + DrawTail(delta, tailPosY, guideLineLength, playRect); } } if (isHeadVisible) { EnvironmentSetup::SetInt("HalfNoteSize", static_cast(m_head->AbsoluteSize.Y) / 2); - DrawNoteHead(delta, headPosY, guideLineLength, playRect); + DrawHead(delta, headPosY, guideLineLength, playRect); } } } diff --git a/Game/src/Engine/Note.hpp b/Game/src/Engine/Note.hpp index 1af5bf4a..f1230f2f 100644 --- a/Game/src/Engine/Note.hpp +++ b/Game/src/Engine/Note.hpp @@ -52,9 +52,9 @@ class Note { void Load(NoteInfoDesc* desc); void Update(double delta); - void DrawNoteHead(double delta, double headPosY, int guideLineLength, Rect& playRect); - void DrawNoteBody(double delta, double bodyPosY, double bodyHeight, Rect& playRect); - void DrawNoteTail(double delta, double tailPosY, int guideLineLength, Rect& playRect); + void DrawHead(double delta, double headPosY, int guideLineLength, Rect& playRect); + void DrawBody(double delta, double bodyPosY, double bodyHeight, Rect& playRect); + void DrawTail(double delta, double tailPosY, int guideLineLength, Rect& playRect); void SetTransparency(); void Render(double delta); From dd3b7aee8f4b1a4e12248f93be97e45cb36d0176 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 5 Jul 2024 00:49:10 +0700 Subject: [PATCH 72/83] refactor(note): code now easier to read --- Game/src/Engine/Note.cpp | 56 +++++++++++++++---------------- Game/src/Engine/Note.hpp | 2 ++ Game/src/Engine/TimingLine.cpp | 2 +- Game/src/Scenes/GameplayScene.cpp | 4 +-- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index ad591ec6..21f5e0c2 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -6,6 +6,7 @@ #include "GameAudioSampleCache.hpp" #include "NoteImageCacheManager.hpp" #include "RhythmEngine.hpp" +#include #define REMOVE_TIME 800 #define HOLD_COMBO_TICK 100 @@ -152,6 +153,7 @@ void Note::Load(NoteInfoDesc *desc) m_relPos = 0; m_lastScoreTime = -1; + GetNoteSize(); } void Note::Update(double delta) @@ -302,7 +304,7 @@ void Note::Render(double delta) auto hitPos = m_engine->GetHitPosition(); double trackPosition = m_engine->GetTrackPosition(); - int min = -100, max = hitPos + 25; + int min = -100, max = GameWindow::GetInstance()->GetBufferHeight(); auto playRect = m_engine->GetPlayRectangle(); int guideLineIndex = m_engine->GetGuideLineIndex(); @@ -312,24 +314,23 @@ void Note::Render(double delta) double headPosY = lerp(0.0, static_cast(hitPos), static_cast(y1)); bool isHeadVisible = isWithinRange(headPosY, min, max); - if (EnvironmentSetup::GetInt("LNBodyOnTop") == 1) { - if (isHeadVisible) { - EnvironmentSetup::SetInt("HalfNoteSize", static_cast(m_head->AbsoluteSize.Y) / 2); - DrawHead(delta, headPosY, guideLineLength, playRect); + if (m_type == NoteType::HOLD) { + double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; + double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); + bool isTailVisible = isWithinRange(tailPosY, min, max); + + if (EnvironmentSetup::GetInt("NoPercy") == 1) { + tailPosY += m_tail->AbsoluteSize.Y; } - if (m_type == NoteType::HOLD) { - double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; - double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); - bool isTailVisible = isWithinRange(tailPosY, min, max); + double bodyPosY = (headPosY + tailPosY) / 2.0; + double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); - if (EnvironmentSetup::GetInt("NoPercy") == 1) { - tailPosY += m_tail->AbsoluteSize.Y; + if (EnvironmentSetup::GetInt("LNBodyOnTop") == 1) { + if (isHeadVisible) { + DrawHead(delta, headPosY, guideLineLength, playRect); } - double bodyPosY = (headPosY + tailPosY) / 2.0; - double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); - if (isTailVisible) { DrawTail(delta, tailPosY, guideLineLength, playRect); } @@ -337,30 +338,22 @@ void Note::Render(double delta) SetTransparency(); DrawBody(delta, bodyPosY, bodyHeight, playRect); } - } - else { - if (m_type == NoteType::HOLD) { - double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; - double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); - bool isTailVisible = isWithinRange(tailPosY, min, max); - - if (EnvironmentSetup::GetInt("NoPercy") == 1) { - tailPosY += m_tail->AbsoluteSize.Y; - } - - double bodyPosY = (headPosY + tailPosY) / 2.0; - double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); - + else { SetTransparency(); DrawBody(delta, bodyPosY, bodyHeight, playRect); if (isTailVisible) { DrawTail(delta, tailPosY, guideLineLength, playRect); } + + if (isHeadVisible) { + DrawHead(delta, headPosY, guideLineLength, playRect); + } } + } + else { if (isHeadVisible) { - EnvironmentSetup::SetInt("HalfNoteSize", static_cast(m_head->AbsoluteSize.Y) / 2); DrawHead(delta, headPosY, guideLineLength, playRect); } } @@ -579,6 +572,11 @@ void Note::SetDrawable(bool drawable) m_drawAble = drawable; } +void Note::GetNoteSize() +{ + EnvironmentSetup::SetInt("NoteSize", static_cast(m_head->AbsoluteSize.Y)); +} + bool Note::IsHoldEffectDrawable() const { return m_shouldDrawHoldEffect; diff --git a/Game/src/Engine/Note.hpp b/Game/src/Engine/Note.hpp index f1230f2f..4fdd8510 100644 --- a/Game/src/Engine/Note.hpp +++ b/Game/src/Engine/Note.hpp @@ -76,6 +76,8 @@ class Note { void SetXPosition(int x); void SetDrawable(bool drawable); + void GetNoteSize(); + bool IsHoldEffectDrawable() const; bool IsDrawable() const; bool IsRemoveable() const; diff --git a/Game/src/Engine/TimingLine.cpp b/Game/src/Engine/TimingLine.cpp index 57979304..866975c2 100644 --- a/Game/src/Engine/TimingLine.cpp +++ b/Game/src/Engine/TimingLine.cpp @@ -66,7 +66,7 @@ void TimingLine::Render(double delta) int halfNoteSize; if (EnvironmentSetup::GetInt("MeasureLineType") == 1) { - halfNoteSize = static_cast(EnvironmentSetup::GetInt("HalfNoteSize")); + halfNoteSize = static_cast(EnvironmentSetup::GetInt("NoteSize") / 2); } else { halfNoteSize = 0; diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index b92c219f..52b8eafc 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -287,7 +287,7 @@ void GameplayScene::Render(double delta) if (m_drawCombo && std::get<7>(scores) > 0) { // O2Jam Replication const double positionStart = 30.0; const double positionEnd = 36.0; // Decrement up to 36 - double initialAnimationSpeed = 12.0; // Initial FPS + double initialAnimationSpeed = 15.0; // Initial FPS static double animationMultiplier = 1.0; // Multiplier to control FPS // Dynamically calculate the animation speed @@ -311,7 +311,7 @@ void GameplayScene::Render(double delta) animationMultiplier = 1.0; // Reset the multiplier when combo ends } else { - animationMultiplier *= 2.0; // Double the FPS multiplier + animationMultiplier += 1.0; // Double the FPS multiplier if (animationMultiplier > 6.0) { animationMultiplier = 6.0; // Cap the multiplier to avoid excessive FPS } From 3f7121f8e5aa4b96e430ad51945e925061e8a0f8 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Fri, 5 Jul 2024 00:53:25 +0700 Subject: [PATCH 73/83] --- Engine/src/Scenes/SceneManager.cpp | 48 ++++++++++-------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/Engine/src/Scenes/SceneManager.cpp b/Engine/src/Scenes/SceneManager.cpp index c6c4f7ee..ac651219 100644 --- a/Engine/src/Scenes/SceneManager.cpp +++ b/Engine/src/Scenes/SceneManager.cpp @@ -40,11 +40,6 @@ SceneManager *SceneManager::s_instance = nullptr; void SceneManager::Update(double delta) { - if (m_ready_change_state) { - std::unique_lock lock(m_mutex); // Lock the mutex - m_cv.wait(lock); // Wait until notified by the scene transition - } - if (m_nextScene != nullptr) { // std::lock_guard lock(m_mutex); if (m_onSceneChange) { @@ -116,17 +111,11 @@ void SceneManager::Update(double delta) void SceneManager::Render(double delta) { - if (m_ready_change_state) { - std::unique_lock lock(m_mutex); // Lock the mutex - m_cv.wait(lock); // Wait until notified by the scene transition - } - if (m_currentScene) m_currentScene->Render(delta); - if (m_currentOverlay && !MsgBox::Any()) { ImguiUtil::NewFrame(); - auto& io = ImGui::GetIO(); + auto &io = ImGui::GetIO(); ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(m_currentOverlay->GetSize(), ImGuiCond_Always); @@ -185,11 +174,6 @@ void SceneManager::Render(double delta) void SceneManager::Input(double delta) { - if (m_ready_change_state) { - std::unique_lock lock(m_mutex); // Lock the mutex - m_cv.wait(lock); // Wait until notified by the scene transition - } - m_inputId = std::this_thread::get_id(); if (m_currentScene) @@ -308,8 +292,8 @@ void SceneManager::IChangeScene(int idx) m_currentSceneId = idx; m_nextScene = m_scenes[idx].get(); - m_ready_change_state = false; - m_cv.notify_all(); + m_ready_change_state = true; + m_cv.notify_one(); } void SceneManager::SetParent(Game *parent) @@ -348,7 +332,7 @@ void SceneManager::DisplayFade(int transparency, std::function callback) } callback(); - }).detach(); + }).detach(); } void SceneManager::ExecuteAfter(int ms_time, std::function callback) @@ -373,19 +357,17 @@ void SceneManager::GameExecuteAfter(ExecuteThread thread, int ms_time, std::func game->GetMainThread()->QueueAction(callback); } else { switch (thread) { - case ExecuteThread::UPDATE: - { - game->GetRenderThread()->QueueAction(callback); - game->GetMainThread()->QueueAction(callback); // w - break; - } + case ExecuteThread::UPDATE: + { + game->GetRenderThread()->QueueAction(callback); + break; + } - case ExecuteThread::WINDOW: - { - game->GetRenderThread()->QueueAction(callback); // w - game->GetMainThread()->QueueAction(callback); - break; - } + case ExecuteThread::WINDOW: + { + game->GetMainThread()->QueueAction(callback); + break; + } } } } @@ -409,4 +391,4 @@ void SceneManager::Release() if (s_instance != nullptr) { delete s_instance; } -} +} \ No newline at end of file From 8c6030abc006c6b80e4fa501e378e0e7aee3ee3f Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sun, 7 Jul 2024 14:40:11 +0700 Subject: [PATCH 74/83] refactor(gameplayscene): O2JAM COMBO ANIMATION (FINAL) --- Game/src/Scenes/GameplayScene.cpp | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 52b8eafc..5da25746 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -284,21 +284,28 @@ void GameplayScene::Render(double delta) } } - if (m_drawCombo && std::get<7>(scores) > 0) { // O2Jam Replication + if (m_drawCombo && std::get<7>(scores) > 0) { // This should be O2Jam Replication const double positionStart = 30.0; - const double positionEnd = 36.0; // Decrement up to 36 - double initialAnimationSpeed = 15.0; // Initial FPS - static double animationMultiplier = 1.0; // Multiplier to control FPS + const double decrement = 6.0; + double animationSpeed = 90.0; + double maxSpeed = animationSpeed; - // Dynamically calculate the animation speed - double animationSpeed = initialAnimationSpeed * animationMultiplier; + if (m_comboTimer > 0.5) { + animationSpeed += 15.0 * delta; + } + else { + animationSpeed -= 15.0 * delta; + } - double targetPosition = positionStart - (positionEnd - positionStart) * m_comboTimer * animationSpeed; - double currentPosition = (targetPosition > 0.0) ? targetPosition : 0.0; + if (animationSpeed > 90.0) { + animationSpeed = maxSpeed; + } - // Smooth transition for the position - m_comboLogo->Position2 = UDim2::fromOffset(0, currentPosition / 3.0); - m_comboNum->Position2 = UDim2::fromOffset(0, currentPosition); + double targetposition = positionStart - decrement * m_comboTimer * animationSpeed; + double currentposition = (targetposition > 0.0) ? targetposition : 0.0; + + m_comboLogo->Position2 = UDim2::fromOffset(0, currentposition / 3.0); + m_comboNum->Position2 = UDim2::fromOffset(0, currentposition); m_comboLogo->Draw(delta); m_comboNum->DrawNumber(std::get<7>(scores)); @@ -308,13 +315,6 @@ void GameplayScene::Render(double delta) if (m_comboTimer >= 1.0) { m_comboTimer = 0.0; m_drawCombo = false; - animationMultiplier = 1.0; // Reset the multiplier when combo ends - } - else { - animationMultiplier += 1.0; // Double the FPS multiplier - if (animationMultiplier > 6.0) { - animationMultiplier = 6.0; // Cap the multiplier to avoid excessive FPS - } } } From 8c2e0572110aae11bec3fb89b5ffb7e175fd5e9e Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:27:11 +0700 Subject: [PATCH 75/83] --- Game/src/Scenes/GameplayScene.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 5da25746..8552a889 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -286,7 +286,7 @@ void GameplayScene::Render(double delta) if (m_drawCombo && std::get<7>(scores) > 0) { // This should be O2Jam Replication const double positionStart = 30.0; - const double decrement = 6.0; + const double step = 6.0; double animationSpeed = 90.0; double maxSpeed = animationSpeed; @@ -301,7 +301,7 @@ void GameplayScene::Render(double delta) animationSpeed = maxSpeed; } - double targetposition = positionStart - decrement * m_comboTimer * animationSpeed; + double targetposition = positionStart - step * m_comboTimer * animationSpeed; double currentposition = (targetposition > 0.0) ? targetposition : 0.0; m_comboLogo->Position2 = UDim2::fromOffset(0, currentposition / 3.0); From 944f85cbd3967c73d9eb5fd54910f00ce9a98008 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:31:07 +0700 Subject: [PATCH 76/83] stupid github desktop --- .gitmodules | 2 +- Engine/include/Game.h | 2 +- Engine/include/Rendering/Window.h | 2 +- Engine/include/Texture/Sprite2D.h | 15 +- Engine/include/Texture/Texture2D.h | 8 +- Engine/src/Configuration.cpp | 2 +- Engine/src/Fonts/FontResources.cpp | 41 ++- Engine/src/Game.cpp | 16 +- Engine/src/Rendering/GameWindow.cpp | 2 +- Engine/src/Rendering/Renderer.cpp | 6 +- .../src/Rendering/Vulkan/Texture2DVulkan.cpp | 8 + Engine/src/Scenes/SceneManager.cpp | 29 +- Engine/src/Texture/Sprite2D.cpp | 112 +++---- Engine/src/Texture/Texture2D.cpp | 297 ++++++----------- Game/CMakeLists.txt | 50 ++- Game/src/Data/Chart.cpp | 220 +++++++------ Game/src/Data/Chart.hpp | 6 +- Game/src/Data/OJM.cpp | 46 ++- Game/src/Data/Util/Util.cpp | 78 +++-- Game/src/Engine/DrawableNote.cpp | 3 +- Game/src/Engine/FrameTimer.cpp | 79 +++-- Game/src/Engine/FrameTimer.hpp | 10 +- Game/src/Engine/LuaScripting.cpp | 21 +- Game/src/Engine/Note.cpp | 262 +++++++++------ Game/src/Engine/Note.hpp | 20 +- Game/src/Engine/NoteImageCacheManager.cpp | 7 - Game/src/Engine/NoteImageCacheManager.hpp | 5 - Game/src/Engine/RhythmEngine.cpp | 69 ++-- Game/src/Engine/RhythmEngine.hpp | 2 + Game/src/Engine/ScoreManager.cpp | 213 +++++------- Game/src/Engine/ScoreManager.hpp | 8 + Game/src/Engine/SkinManager.cpp | 17 +- Game/src/Engine/TimingLine.cpp | 14 +- Game/src/EnvironmentSetup.cpp | 15 +- Game/src/Resources/DefaultConfiguration.h | 14 +- Game/src/Resources/GameResources.cpp | 16 +- Game/src/Scenes/GameplayScene.cpp | 111 +++++-- Game/src/Scenes/GameplayScene.h | 5 + Game/src/Scenes/LoadingScene.cpp | 42 ++- Game/src/Scenes/LoadingScene.h | 1 + Game/src/Scenes/MainMenu.cpp | 259 ++++++++------- Game/src/Scenes/Overlays/Settings.cpp | 303 +++++++++++++++--- Game/src/Scenes/Overlays/Settings.h | 7 +- Game/src/Scenes/ResultScene.cpp | 10 +- Game/src/Scenes/SongSelectScene.cpp | 86 +++-- Game/src/Scenes/SongSelectScene.h | 5 + Game/src/main.cpp | 9 +- 47 files changed, 1492 insertions(+), 1063 deletions(-) diff --git a/.gitmodules b/.gitmodules index 180fd589..904295c9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "GameResources"] path = GameResources - url = https://github.com/Estrol/O2GameResources + url = https://github.com/AlberttFrgk/O2GameResources diff --git a/Engine/include/Game.h b/Engine/include/Game.h index 4e764017..d31eb36c 100644 --- a/Engine/include/Game.h +++ b/Engine/include/Game.h @@ -89,5 +89,5 @@ class Game GameThread mLocalThread; std::mutex m_mutex; - std::condition_variable m_conditionVariable; + std::condition_variable m_cv; }; diff --git a/Engine/include/Rendering/Window.h b/Engine/include/Rendering/Window.h index 6ce2e40d..4f3b575e 100644 --- a/Engine/include/Rendering/Window.h +++ b/Engine/include/Rendering/Window.h @@ -26,7 +26,7 @@ class GameWindow float GetHeightScale(); void SetScaleOutput(bool value); - bool IsScaleOutput(); + bool IsScaleOutput() const; void SetWindowTitle(std::string &title); void SetWindowSubTitle(std::string &subTitle); diff --git a/Engine/include/Texture/Sprite2D.h b/Engine/include/Texture/Sprite2D.h index 479f2435..55025cdf 100644 --- a/Engine/include/Texture/Sprite2D.h +++ b/Engine/include/Texture/Sprite2D.h @@ -18,10 +18,10 @@ class Sprite2D public: Sprite2D() = default; - Sprite2D(std::vector textures, float delay = 1.0f); - Sprite2D(std::vector textures, float delay = 1.0f); - Sprite2D(std::vector textures, float delay = 1.0f); - Sprite2D(std::vector textures, float delay = 1.0f); + Sprite2D(std::vector textures, double delay = 1.0); + Sprite2D(std::vector textures, double delay = 1.0); + Sprite2D(std::vector textures, double delay = 1.0); + Sprite2D(std::vector textures, double delay = 1.0); ~Sprite2D(); @@ -37,15 +37,18 @@ class Sprite2D void DrawOnce(double delta, bool manual = false); Texture2D *GetTexture(); - void SetFPS(float fps); + void SetFPS(double fps); void Reset(); -private: double m_spritespeed = 1.0; + +private: float m_currentTime = 0; int m_currentIndex = 0; bool m_drawOnce = false; std::vector m_textures; + + void DrawInternal(double delta, bool playOnce, Rect* rect, bool manual); }; diff --git a/Engine/include/Texture/Texture2D.h b/Engine/include/Texture/Texture2D.h index 8596abd0..72a4d7fa 100644 --- a/Engine/include/Texture/Texture2D.h +++ b/Engine/include/Texture/Texture2D.h @@ -20,9 +20,9 @@ class Texture2D public: Texture2D(); - Texture2D(std::string fileName); - Texture2D(std::filesystem::path path); - Texture2D(uint8_t *fileData, size_t size); + Texture2D(const std::string& fileName); + Texture2D(const std::filesystem::path& path); + Texture2D(const uint8_t *fileData, size_t size); Texture2D(SDL_Texture *texture); Texture2D(Texture2D_Vulkan *texture); ~Texture2D(); @@ -51,7 +51,7 @@ class Texture2D Rect GetOriginalRECT(); void SetOriginalRECT(Rect size); - static Texture2D *FromTexture2D(Texture2D *tex); + // static Texture2D *FromTexture2D(Texture2D *tex); static Texture2D *FromBMP(uint8_t *fileData, size_t size); static Texture2D *FromBMP(std::string fileName); diff --git a/Engine/src/Configuration.cpp b/Engine/src/Configuration.cpp index 1628296e..530a53f9 100644 --- a/Engine/src/Configuration.cpp +++ b/Engine/src/Configuration.cpp @@ -86,7 +86,7 @@ void Configuration::Set(std::string key, std::string prop, std::string value) void Configuration::Font_SetPath(std::filesystem::path path) { - FontPath = path; + FontPath = std::filesystem::current_path() / "Resources"; } std::filesystem::path Configuration::Font_GetPath() diff --git a/Engine/src/Fonts/FontResources.cpp b/Engine/src/Fonts/FontResources.cpp index 43b91ba1..7fc7d8bf 100644 --- a/Engine/src/Fonts/FontResources.cpp +++ b/Engine/src/Fonts/FontResources.cpp @@ -1,4 +1,4 @@ -#pragma warning(disable : 4838) // Goddamit +#pragma warning(disable : 4838) // Goddamit #pragma warning(disable : 4309) #include @@ -25,9 +25,9 @@ // BEGIN FONT FALLBACK #include "FallbackFonts/arial.ttf.h" -#include "FallbackFonts/ch.ttf.h" -#include "FallbackFonts/jp.ttf.h" -#include "FallbackFonts/kr.ttf.h" +//#include "FallbackFonts/ch.ttf.h" +//#include "FallbackFonts/jp.ttf.h" +//#include "FallbackFonts/kr.ttf.h" #include // END FONT FALLBACK @@ -92,14 +92,37 @@ void FontResources::PreloadFontCaches() GameWindow *wnd = GameWindow::GetInstance(); - auto skinPath = Configuration::Font_GetPath(); - auto fontPath = skinPath / "Fonts"; + auto path = Configuration::Font_GetPath(); + auto fontPath = path / "Fonts"; auto normalfont = fontPath / "normal.ttf"; auto jpFont = fontPath / "jp.ttf"; auto krFont = fontPath / "kr.ttf"; auto chFont = fontPath / "ch.ttf"; + static const ImWchar glyphRanges[] = { // Optimized + (ImWchar)0x0020, (ImWchar)0x052F, + (ImWchar)0x2000, (ImWchar)0x27BF, + (ImWchar)0x2E80, (ImWchar)0x2FA1, + (ImWchar)0x1F300, (ImWchar)0x1FAFF, + (ImWchar)0x2660, (ImWchar)0x2663, + (ImWchar)0x2665, (ImWchar)0x2666, + (ImWchar)0x2600, (ImWchar)0x2606, + (ImWchar)0x2618, (ImWchar)0x2619, + (ImWchar)0x263A, (ImWchar)0x263B, + (ImWchar)0x2708, (ImWchar)0x2714, + (ImWchar)0x2728, (ImWchar)0x2734, + (ImWchar)0x2740, (ImWchar)0x274B, + (ImWchar)0x2756, (ImWchar)0x2758, + (ImWchar)0x2764, (ImWchar)0x2767, + (ImWchar)0x2794, (ImWchar)0x27BE, + (ImWchar)0x27F0, (ImWchar)0x27FF, + (ImWchar)0x2900, (ImWchar)0x297F, + (ImWchar)0x2A00, (ImWchar)0x2AFF, + (ImWchar)0x0000, (ImWchar)0x0000 + }; + + { float originScale = (wnd->GetBufferWidth() + wnd->GetBufferHeight()) / 15.6f; float targetScale = (wnd->GetWidth() + wnd->GetHeight()) / 15.6f; @@ -118,9 +141,9 @@ void FontResources::PreloadFontCaches() { if (std::filesystem::exists(normalfont)) { - Font.Font = io.Fonts->AddFontFromFileTTF((const char *)normalfont.u8string().c_str(), fontSize, &conf); + Font.Font = io.Fonts->AddFontFromFileTTF((const char *)normalfont.u8string().c_str(), fontSize, &conf, glyphRanges); // glyphRanges, fixing missing fonts } else { - Font.Font = io.Fonts->AddFontFromMemoryTTF((void *)get_arial_font_data(), get_arial_font_size(), fontSize, &conf); + Font.Font = io.Fonts->AddFontFromMemoryTTF((void *)get_arial_font_data(), get_arial_font_size(), fontSize, &conf, glyphRanges); } } @@ -151,7 +174,7 @@ void FontResources::PreloadFontCaches() case TextRegion::Chinese: { if (std::filesystem::exists(chFont)) { - io.Fonts->AddFontFromFileTTF((const char *)chFont.u8string().c_str(), fontSize, &conf, io.Fonts->GetGlyphRangesChineseSimplifiedCommon()); + io.Fonts->AddFontFromFileTTF((const char *)chFont.u8string().c_str(), fontSize, &conf, io.Fonts->GetGlyphRangesChineseFull()); } break; diff --git a/Engine/src/Game.cpp b/Engine/src/Game.cpp index cad829e1..b79c5c5b 100644 --- a/Engine/src/Game.cpp +++ b/Engine/src/Game.cpp @@ -16,7 +16,7 @@ constexpr auto kInputDefaultRate = 1000.0; constexpr auto kMenuDefaultRate = 60.0; -constexpr auto kAudioDefaultRate = 24.0; +constexpr auto kAudioDefaultRate = 60.0; namespace { @@ -42,13 +42,14 @@ namespace { { const double targetFrameTime = 1000.0 / MaxFrameRate; - double newTick = SDL_GetTicks(); + double newTick = static_cast(std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count()); double frameTime = newTick - curTick; if (frameTime < targetFrameTime) { double delayTime = targetFrameTime - frameTime; - SDL_Delay(static_cast(delayTime)); + std::this_thread::sleep_for(std::chrono::milliseconds(static_cast(delayTime))); + std::this_thread::yield(); newTick += delayTime; } @@ -83,7 +84,7 @@ Game::~Game() if (m_notify) { std::unique_lock lock(m_mutex); - m_conditionVariable.wait(lock, [this] { return !m_notify; }); + m_cv.wait(lock, [this] { return !m_notify; }); } } @@ -369,13 +370,12 @@ void Game::CheckFont() void Game::Stop() { if (m_running) { - m_running = false; - { - std::lock_guard lock(m_mutex); // TODO: Fix game does not properly exit while crash (if not just revert back to SDL_Delay Sleep) + std::unique_lock lock(m_mutex); + m_running = false; m_notify = true; } - m_conditionVariable.notify_one(); + m_cv.notify_one(); } } diff --git a/Engine/src/Rendering/GameWindow.cpp b/Engine/src/Rendering/GameWindow.cpp index 9d2cf067..60bdbb19 100644 --- a/Engine/src/Rendering/GameWindow.cpp +++ b/Engine/src/Rendering/GameWindow.cpp @@ -193,7 +193,7 @@ void GameWindow::SetScaleOutput(bool value) m_scaleOutput = value; } -bool GameWindow::IsScaleOutput() +bool GameWindow::IsScaleOutput() const { return m_scaleOutput; } diff --git a/Engine/src/Rendering/Renderer.cpp b/Engine/src/Rendering/Renderer.cpp index 13c56937..6ffb4e3c 100644 --- a/Engine/src/Rendering/Renderer.cpp +++ b/Engine/src/Rendering/Renderer.cpp @@ -52,11 +52,11 @@ bool Renderer::Create(RendererMode mode, GameWindow *window, bool failed) break; } - case RendererMode::DIRECTX11: + /*case RendererMode::DIRECTX11: { rendererName = "direct3d11"; break; - } + }*/ case RendererMode::DIRECTX12: { @@ -96,7 +96,7 @@ bool Renderer::Create(RendererMode mode, GameWindow *window, bool failed) } SDL_SetHint(SDL_HINT_RENDER_DRIVER, rendererName.c_str()); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "Linear"); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); } m_renderer = SDL_CreateRenderer(window->GetWindow(), -1, SDL_RENDERER_ACCELERATED /*| SDL_RENDERER_PRESENTVSYNC*/); diff --git a/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp b/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp index 85fb06d7..414790f8 100644 --- a/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp +++ b/Engine/src/Rendering/Vulkan/Texture2DVulkan.cpp @@ -79,6 +79,14 @@ void InternalLoad( size_t image_size = static_cast(tex_data->Width) * static_cast(tex_data->Height) * tex_data->Channels; + // Premultiply alpha + for (size_t i = 0; i < image_size; i += tex_data->Channels) { // Fix white line issue + float alpha = image_data[i + 3] / 255.0f; + image_data[i] = static_cast(image_data[i] * alpha); + image_data[i + 1] = static_cast(image_data[i + 1] * alpha); + image_data[i + 2] = static_cast(image_data[i + 2] * alpha); + } + VkResult err; { VkImageCreateInfo info = {}; diff --git a/Engine/src/Scenes/SceneManager.cpp b/Engine/src/Scenes/SceneManager.cpp index c0121a8b..ac651219 100644 --- a/Engine/src/Scenes/SceneManager.cpp +++ b/Engine/src/Scenes/SceneManager.cpp @@ -113,10 +113,9 @@ void SceneManager::Render(double delta) { if (m_currentScene) m_currentScene->Render(delta); - if (m_currentOverlay && !MsgBox::Any()) { ImguiUtil::NewFrame(); - auto& io = ImGui::GetIO(); + auto &io = ImGui::GetIO(); ImGui::SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGui::SetNextWindowSize(m_currentOverlay->GetSize(), ImGuiCond_Always); @@ -333,7 +332,7 @@ void SceneManager::DisplayFade(int transparency, std::function callback) } callback(); - }).detach(); + }).detach(); } void SceneManager::ExecuteAfter(int ms_time, std::function callback) @@ -358,19 +357,17 @@ void SceneManager::GameExecuteAfter(ExecuteThread thread, int ms_time, std::func game->GetMainThread()->QueueAction(callback); } else { switch (thread) { - case ExecuteThread::UPDATE: - { - game->GetRenderThread()->QueueAction(callback); - game->GetMainThread()->QueueAction(callback); // w - break; - } + case ExecuteThread::UPDATE: + { + game->GetRenderThread()->QueueAction(callback); + break; + } - case ExecuteThread::WINDOW: - { - game->GetRenderThread()->QueueAction(callback); // w - game->GetMainThread()->QueueAction(callback); - break; - } + case ExecuteThread::WINDOW: + { + game->GetMainThread()->QueueAction(callback); + break; + } } } } @@ -394,4 +391,4 @@ void SceneManager::Release() if (s_instance != nullptr) { delete s_instance; } -} +} \ No newline at end of file diff --git a/Engine/src/Texture/Sprite2D.cpp b/Engine/src/Texture/Sprite2D.cpp index c18e661e..1c793328 100644 --- a/Engine/src/Texture/Sprite2D.cpp +++ b/Engine/src/Texture/Sprite2D.cpp @@ -2,11 +2,11 @@ #include "Rendering/Window.h" #include "Texture/Texture2D.h" -Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::Sprite2D() +Sprite2D::Sprite2D(std::vector textures, double delay) : Sprite2D::Sprite2D() { m_textures = textures; m_spritespeed = delay; - m_currentTime = 0.0f; + m_currentTime = 0.0; m_currentIndex = 0; Size = UDim2::fromScale(1, 1); @@ -14,7 +14,7 @@ Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::S AnchorPoint = { 0, 0 }; } -Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::Sprite2D() +Sprite2D::Sprite2D(std::vector textures, double delay) : Sprite2D::Sprite2D() { m_spritespeed = delay; Size = UDim2::fromScale(1, 1); @@ -26,7 +26,7 @@ Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::S } } -Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::Sprite2D() +Sprite2D::Sprite2D(std::vector textures, double delay) : Sprite2D::Sprite2D() { m_spritespeed = delay; Size = UDim2::fromScale(1, 1); @@ -40,7 +40,7 @@ Sprite2D::Sprite2D(std::vector textures, float delay) : S } } -Sprite2D::Sprite2D(std::vector textures, float delay) : Sprite2D::Sprite2D() +Sprite2D::Sprite2D(std::vector textures, double delay) : Sprite2D::Sprite2D() { m_spritespeed = delay; Size = UDim2::fromScale(1, 1); @@ -64,38 +64,15 @@ void Sprite2D::Draw(double delta, bool manual) Draw(delta, nullptr, manual); } -void Sprite2D::Draw(double delta, Rect *rect, bool manual) // Original code, play image sprite loop +void Sprite2D::DrawInternal(double delta, bool playOnce, Rect* rect, bool manual) { - auto tex = m_textures[m_currentIndex]; - GameWindow *window = GameWindow::GetInstance(); + if (m_textures.empty()) return; // Safety check to ensure m_textures is not empty - double xPos = (window->GetBufferWidth() * Position.X.Scale) + (Position.X.Offset); - double yPos = (window->GetBufferHeight() * Position.Y.Scale) + (Position.Y.Offset); - - double xMPos = (window->GetBufferWidth() * Position2.X.Scale) + (Position2.X.Offset); - double yMPos = (window->GetBufferHeight() * Position2.Y.Scale) + (Position2.Y.Offset); - - xPos += xMPos; - yPos += yMPos; - - tex->Position = UDim2::fromOffset(xPos, yPos); - tex->AlphaBlend = AlphaBlend; - tex->Size = Size; - tex->AnchorPoint = AnchorPoint; - tex->Draw(rect, manual ? false : true); - - if (m_spritespeed > 0.0f) { - m_currentTime += static_cast(delta); - if (m_currentTime >= m_spritespeed) { - m_currentTime = 0.0f; - m_currentIndex = (m_currentIndex + 1) % m_textures.size(); - } - } -} - -void Sprite2D::DrawOnce(double delta, bool manual) { // Play whole image sprite once if (m_currentIndex >= m_textures.size()) { - return; + if (playOnce) { + return; // Stop if playing once and reached end + } + m_currentIndex = 0; // Reset index if looping } auto tex = m_textures[m_currentIndex]; @@ -114,66 +91,55 @@ void Sprite2D::DrawOnce(double delta, bool manual) { // Play whole image sprite tex->AlphaBlend = AlphaBlend; tex->Size = Size; tex->AnchorPoint = AnchorPoint; - tex->Draw(); + tex->Draw(rect, manual ? false : true); - if (m_spritespeed > 0.0f) { + if (m_spritespeed > 0.0) { m_currentTime += static_cast(delta); if (m_currentTime >= m_spritespeed) { - m_currentTime = 0.0f; + m_currentTime = 0.0; m_currentIndex++; - if (m_currentIndex == m_textures.size() && m_drawOnce) { - return; + if (m_currentIndex >= m_textures.size()) { + if (playOnce) { + m_currentIndex = m_textures.size() - 1; // Stop at the last frame if playing once + return; + } else { + m_currentIndex = 0; // Loop back to the first frame + } } } } } -void Sprite2D::DrawStop(double delta, bool manual) { // Play image sprite once and stop on last frame - if (m_currentIndex >= m_textures.size()) { - m_currentIndex = static_cast(m_textures.size()) - 1; - } - - auto tex = m_textures[m_currentIndex]; - GameWindow* window = GameWindow::GetInstance(); - - double xPos = (window->GetBufferWidth() * Position.X.Scale) + (Position.X.Offset); - double yPos = (window->GetBufferHeight() * Position.Y.Scale) + (Position.Y.Offset); - - double xMPos = (window->GetBufferWidth() * Position2.X.Scale) + (Position2.X.Offset); - double yMPos = (window->GetBufferHeight() * Position2.Y.Scale) + (Position2.Y.Offset); - - xPos += xMPos; - yPos += yMPos; +void Sprite2D::Draw(double delta, Rect* rect, bool manual) +{ + DrawInternal(delta, false, rect, manual); // Play loop +} - tex->Position = UDim2::fromOffset(xPos, yPos); - tex->AlphaBlend = AlphaBlend; - tex->Size = Size; - tex->AnchorPoint = AnchorPoint; - tex->Draw(); +void Sprite2D::DrawOnce(double delta, bool manual) +{ + DrawInternal(delta, true, nullptr, manual); // Play once +} - if (m_spritespeed > 0.0f) { - m_currentTime += static_cast(delta); - if (m_currentTime >= m_spritespeed) { - m_currentTime = 0.0f; - m_currentIndex++; +void Sprite2D::DrawStop(double delta, bool manual) +{ + DrawInternal(delta, true, nullptr, manual); - if (m_currentIndex == m_textures.size() && m_drawOnce) { - return; - } - } + if (m_currentIndex >= m_textures.size()) { // Play the stop on last frame + m_currentIndex = m_textures.size() - 1; } } - void Sprite2D::Reset() { m_currentIndex = 0; - m_currentTime = 0.0f; + m_currentTime = 0.0; } Texture2D *Sprite2D::GetTexture() { + if (m_textures.empty()) return nullptr; // Safety check to ensure m_textures is not empty + auto tex = m_textures[m_currentIndex]; tex->Position = Position; tex->Size = Size; @@ -182,7 +148,7 @@ Texture2D *Sprite2D::GetTexture() return tex; } -void Sprite2D::SetFPS(float fps) +void Sprite2D::SetFPS(double fps) { m_spritespeed = 1.0f / fps; -} \ No newline at end of file +} diff --git a/Engine/src/Texture/Texture2D.cpp b/Engine/src/Texture/Texture2D.cpp index ab682e18..90570193 100644 --- a/Engine/src/Texture/Texture2D.cpp +++ b/Engine/src/Texture/Texture2D.cpp @@ -3,6 +3,9 @@ #include #include #include +#include +#include +#include #include "../Data/Imgui/imgui_impl_vulkan.h" #include "../Rendering/Vulkan/Texture2DVulkan_Internal.h" @@ -15,6 +18,29 @@ #include #include +namespace { + // Premultiply alpha + SDL_Surface* PremultiplyAlpha(SDL_Surface* surface) { + if (surface->format->BytesPerPixel != 4) return surface; + + Uint32* pixels = (Uint32*)surface->pixels; + for (int y = 0; y < surface->h; ++y) { + for (int x = 0; x < surface->w; ++x) { + Uint32 pixel = pixels[y * surface->w + x]; + Uint8 r, g, b, a; + SDL_GetRGBA(pixel, surface->format, &r, &g, &b, &a); + + r = (r * a) / 255; + g = (g * a) / 255; + b = (b * a) / 255; + + pixels[y * surface->w + x] = SDL_MapRGBA(surface->format, r, g, b, a); + } + } + return surface; + } +} + Texture2D::Texture2D() { TintColor = { 1.0f, 1.0f, 1.0f }; @@ -35,91 +61,62 @@ Texture2D::Texture2D() Size = UDim2::fromScale(1, 1); } -Texture2D::Texture2D(std::string fileName) : Texture2D() +Texture2D::Texture2D(const std::string& fileName) : Texture2D() { - if (!std::filesystem::exists(fileName)) { - fileName = std::filesystem::current_path().string() + fileName; + std::string filePath = fileName; + if (!std::filesystem::exists(filePath)) { + filePath = std::filesystem::current_path().string() + fileName; } - if (!std::filesystem::exists(fileName)) { + if (!std::filesystem::exists(filePath)) { throw std::runtime_error(fileName + " not found!"); } - std::fstream fs(fileName, std::ios::binary | std::ios::in); - if (!fs.is_open()) { - throw std::runtime_error(fileName + " cannot opened!"); + std::ifstream file(filePath, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + throw std::runtime_error(fileName + " cannot be opened!"); } - fs.seekg(0, std::ios::end); - size_t size = fs.tellg(); - fs.seekg(0, std::ios::beg); + size_t size = file.tellg(); + file.seekg(0, std::ios::beg); - uint8_t *buffer = new uint8_t[size]; - fs.read((char *)buffer, size); - fs.close(); + std::vector buffer(size); + file.read(reinterpret_cast(buffer.data()), size); + file.close(); - Rotation = 0; - Transparency = 0.0f; - m_actualSize = { 0, 0, 0, 0 }; - m_bDisposeTexture = true; - TintColor = { 1.0f, 1.0f, 1.0f }; - - LoadImageResources(buffer, size); + LoadImageResources(buffer.data(), size); } -Texture2D::Texture2D(std::filesystem::path path) : Texture2D() -{ +Texture2D::Texture2D(const std::filesystem::path& path) : Texture2D() { if (!std::filesystem::exists(path)) { throw std::runtime_error(path.string() + " not found!"); } - std::fstream fs(path, std::ios::binary | std::ios::in); - if (!fs.is_open()) { - throw std::runtime_error(path.string() + " cannot opened!"); + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file.is_open()) { + throw std::runtime_error(path.string() + " cannot be opened!"); } - fs.seekg(0, std::ios::end); - size_t size = fs.tellg(); - fs.seekg(0, std::ios::beg); + size_t size = file.tellg(); + file.seekg(0, std::ios::beg); - uint8_t *buffer = new uint8_t[size]; - fs.read((char *)buffer, size); - fs.close(); - - Rotation = 0; - Transparency = 0.0f; - m_actualSize = { 0, 0, 0, 0 }; - m_bDisposeTexture = true; - TintColor = { 1.0f, 1.0f, 1.0f }; + std::vector buffer(size); + file.read(reinterpret_cast(buffer.data()), size); + file.close(); - LoadImageResources(buffer, size); + LoadImageResources(buffer.data(), size); } -// Do base constructor called before derived constructor? -// https://stackoverflow.com/questions/120547/what-are-the-rules-for-calling-the-superclass-constructor - -Texture2D::Texture2D(uint8_t *fileData, size_t size) : Texture2D() +Texture2D::Texture2D(const uint8_t* fileData, size_t size) : Texture2D() { - uint8_t *buffer = new uint8_t[size]; - memcpy(buffer, fileData, size); - - Rotation = 0; - Transparency = 0.0f; - m_actualSize = { 0, 0, 0, 0 }; - m_bDisposeTexture = true; - TintColor = { 1.0f, 1.0f, 1.0f }; - - m_sdl_tex = nullptr; - m_vk_tex = nullptr; - - LoadImageResources(buffer, size); + std::vector buffer(fileData, fileData + size); + LoadImageResources(buffer.data(), size); } Texture2D::Texture2D(SDL_Texture *texture) : Texture2D() { m_bDisposeTexture = false; m_sdl_tex = texture; - m_ready = true; } @@ -135,17 +132,13 @@ Texture2D::~Texture2D() { if (m_bDisposeTexture) { if (Renderer::GetInstance()->IsVulkan() && m_vk_tex) { - auto vk_tex = m_vk_tex; - - vkTexture::ReleaseTexture(vk_tex); - + vkTexture::ReleaseTexture(m_vk_tex); m_vk_tex = nullptr; } else { if (m_sdl_tex) { SDL_DestroyTexture(m_sdl_tex); m_sdl_tex = nullptr; } - if (m_sdl_surface) { SDL_FreeSurface(m_sdl_surface); m_sdl_surface = nullptr; @@ -169,11 +162,11 @@ void Texture2D::Draw(Rect *clipRect) Draw(clipRect, true); } -void Texture2D::Draw(Rect *clipRect, bool manualDraw) +void Texture2D::Draw(Rect* clipRect, bool manualDraw) { - Renderer *renderer = Renderer::GetInstance(); - auto window = GameWindow::GetInstance(); - bool scaleOutput = window->IsScaleOutput(); + Renderer* renderer = Renderer::GetInstance(); + auto window = GameWindow::GetInstance(); + bool scaleOutput = window->IsScaleOutput(); CalculateSize(); if (!m_ready) @@ -226,66 +219,41 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) ImVec2 uv3(1.0f, 1.0f); // Bottom-right UV coordinate ImVec2 uv4(0.0f, 1.0f); // Bottom-left UV coordinate - ImU32 color = IM_COL32((uint8_t)(TintColor.R * 255), (uint8_t)(TintColor.G * 255), (uint8_t)(TintColor.B * 255), 255); // Probably fix for Color3 - - std::array vertexData; - - for (int i = 0; i < 6; i++) { - ImDrawVert &vertex = vertexData[i]; - switch (i) { - case 0: - vertex.pos = ImVec2(x1, y1); - vertex.uv = uv1; - break; - case 1: - vertex.pos = ImVec2(x2, y1); - vertex.uv = uv2; - break; - case 2: - vertex.pos = ImVec2(x2, y2); - vertex.uv = uv3; - break; - case 3: - vertex.pos = ImVec2(x1, y1); - vertex.uv = uv1; - break; - case 4: - vertex.pos = ImVec2(x2, y2); - vertex.uv = uv3; - break; - case 5: - vertex.pos = ImVec2(x1, y2); - vertex.uv = uv4; - break; - } - vertex.col = color; - } + ImU32 color = IM_COL32((uint8_t)(TintColor.R * 255), (uint8_t)(TintColor.G * 255), (uint8_t)(TintColor.B * 255), 255); + + std::array vertexData = {{ + {ImVec2(x1, y1), uv1, color}, + {ImVec2(x2, y1), uv2, color}, + {ImVec2(x2, y2), uv3, color}, + {ImVec2(x1, y1), uv1, color}, + {ImVec2(x2, y2), uv3, color}, + {ImVec2(x1, y2), uv4, color} + }}; SubmitQueueInfo info = {}; info.AlphaBlend = AlphaBlend; info.descriptor = imageId; - info.vertices = std::vector(vertexData.begin(), vertexData.end()); - info.indices = { 0, 1, 2, 3, 4, 5 }; + info.vertices = {vertexData.begin(), vertexData.end()}; + info.indices = {0, 1, 2, 3, 4, 5}; info.scissor = scissor; - // submit to queue vulkan_driver->queue_submit(info); } else { - SDL_FRect destRect = { m_calculatedSizeF.left, m_calculatedSizeF.top, m_calculatedSizeF.right, m_calculatedSizeF.bottom }; + SDL_FRect destRect = {m_calculatedSizeF.left, m_calculatedSizeF.top, m_calculatedSizeF.right, m_calculatedSizeF.bottom}; if (scaleOutput) { - destRect.x = destRect.x * window->GetWidthScale(); - destRect.y = destRect.y * window->GetHeightScale(); - destRect.w = destRect.w * window->GetWidthScale(); - destRect.h = destRect.h * window->GetHeightScale(); + destRect.x *= window->GetWidthScale(); + destRect.y *= window->GetHeightScale(); + destRect.w *= window->GetWidthScale(); + destRect.h *= window->GetHeightScale(); } - SDL_Rect originClip = {}; + SDL_Rect originClip = {}; SDL_BlendMode oldBlendMode = SDL_BLENDMODE_NONE; if (clipRect) { SDL_RenderGetClipRect(renderer->GetSDLRenderer(), &originClip); - SDL_Rect testClip = { clipRect->left, clipRect->top, clipRect->right - clipRect->left, clipRect->bottom - clipRect->top }; + SDL_Rect testClip = {clipRect->left, clipRect->top, clipRect->right - clipRect->left, clipRect->bottom - clipRect->top}; if (scaleOutput) { testClip.x = static_cast(testClip.x * window->GetWidthScale()); testClip.y = static_cast(testClip.y * window->GetHeightScale()); @@ -301,23 +269,15 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) SDL_SetTextureBlendMode(m_sdl_tex, renderer->GetSDLBlendMode()); } - SDL_Color color = { (uint8_t)(TintColor.R * 255.0f), (uint8_t)(TintColor.G * 255.0f), (uint8_t)(TintColor.B * 255.0f), (uint8_t)255 }; + SDL_Color color = {(uint8_t)(TintColor.R * 255.0f), (uint8_t)(TintColor.G * 255.0f), (uint8_t)(TintColor.B * 255.0f), 255}; if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { - color.r = (uint8_t)(TintColor.B * 255.0f); - color.b = (uint8_t)(TintColor.R * 255.0f); + std::swap(color.r, color.b); } SDL_SetTextureColorMod(m_sdl_tex, color.r, color.g, color.b); SDL_SetTextureAlphaMod(m_sdl_tex, static_cast(255 - (Transparency / 100.0) * 255)); - int error = SDL_RenderCopyExF( - renderer->GetSDLRenderer(), - m_sdl_tex, - nullptr, - &destRect, - Rotation, - nullptr, - (SDL_RendererFlip)0); + int error = SDL_RenderCopyExF(renderer->GetSDLRenderer(), m_sdl_tex, nullptr, &destRect, Rotation, nullptr, SDL_FLIP_NONE); if (error != 0) { throw SDLException(); @@ -328,20 +288,16 @@ void Texture2D::Draw(Rect *clipRect, bool manualDraw) } if (clipRect) { - if (originClip.w == 0 || originClip.h == 0) { - SDL_RenderSetClipRect(renderer->GetSDLRenderer(), nullptr); - } else { - SDL_RenderSetClipRect(renderer->GetSDLRenderer(), &originClip); - } + SDL_RenderSetClipRect(renderer->GetSDLRenderer(), originClip.w == 0 || originClip.h == 0 ? nullptr : &originClip); } } } void Texture2D::CalculateSize() { - GameWindow *window = GameWindow::GetInstance(); - int wWidth = window->GetBufferWidth(); - int wHeight = window->GetBufferHeight(); + GameWindow* window = GameWindow::GetInstance(); + int wWidth = window->GetBufferWidth(); + int wHeight = window->GetBufferHeight(); float xPos = static_cast((wWidth * Position.X.Scale) + Position.X.Offset); float yPos = static_cast((wHeight * Position.Y.Scale) + Position.Y.Offset); @@ -349,8 +305,8 @@ void Texture2D::CalculateSize() float width = static_cast((m_actualSize.right * Size.X.Scale) + Size.X.Offset); float height = static_cast((m_actualSize.bottom * Size.Y.Scale) + Size.Y.Offset); - m_preAnchoredSize = { (LONG)xPos, (LONG)yPos, (LONG)width, (LONG)height }; - m_preAnchoredSizeF = { xPos, yPos, width, height }; + m_preAnchoredSize = {(LONG)xPos, (LONG)yPos, (LONG)width, (LONG)height}; + m_preAnchoredSizeF = {xPos, yPos, width, height}; float xAnchor = width * std::clamp((float)AnchorPoint.X, 0.0f, 1.0f); float yAnchor = height * std::clamp((float)AnchorPoint.Y, 0.0f, 1.0f); @@ -358,11 +314,11 @@ void Texture2D::CalculateSize() xPos -= xAnchor; yPos -= yAnchor; - m_calculatedSize = { (LONG)xPos, (LONG)yPos, (LONG)width, (LONG)height }; - m_calculatedSizeF = { xPos, yPos, width, height }; + m_calculatedSize = {(LONG)xPos, (LONG)yPos, (LONG)width, (LONG)height}; + m_calculatedSizeF = {xPos, yPos, width, height}; - AbsolutePosition = { xPos, yPos }; - AbsoluteSize = { width, height }; + AbsolutePosition = {xPos, yPos}; + AbsoluteSize = {width, height}; } Rect Texture2D::GetOriginalRECT() @@ -375,84 +331,37 @@ void Texture2D::SetOriginalRECT(Rect size) m_actualSize = size; } -Texture2D *Texture2D::FromTexture2D(Texture2D *tex) -{ - auto copy = new Texture2D(tex->m_sdl_tex); - copy->m_actualSize = tex->m_actualSize; - copy->Position = tex->Position; - copy->Size = tex->Size; - - return copy; -} - -Texture2D *Texture2D::FromBMP(uint8_t *fileData, size_t size) -{ - return nullptr; -} - -Texture2D *Texture2D::FromBMP(std::string fileName) -{ - return nullptr; -} - -Texture2D *Texture2D::FromJPEG(uint8_t *fileData, size_t size) -{ - return nullptr; -} - -Texture2D *Texture2D::FromJPEG(std::string fileName) -{ - return nullptr; -} - -Texture2D *Texture2D::FromPNG(uint8_t *fileData, size_t size) -{ - return nullptr; -} - -Texture2D *Texture2D::FromPNG(std::string fileName) -{ - return nullptr; -} - -void Texture2D::LoadImageResources(uint8_t *buffer, size_t size) +void Texture2D::LoadImageResources(uint8_t* buffer, size_t size) { if (Renderer::GetInstance()->IsVulkan()) { auto tex_data = vkTexture::TexLoadImage(buffer, size); - - m_actualSize = { 0, 0, tex_data->Width, tex_data->Height }; + m_actualSize = {0, 0, tex_data->Width, tex_data->Height}; m_vk_tex = tex_data; - m_bDisposeTexture = true; m_ready = true; } else { - SDL_RWops *rw = SDL_RWFromMem(buffer, (int)size); + SDL_RWops* rw = SDL_RWFromMem(buffer, static_cast(size)); + std::unique_ptr decompressed_surface(IMG_LoadTyped_RW(rw, 1, "PNG"), SDL_FreeSurface); - // check if buffer magic is BMP - if (buffer[0] == 0x42 && buffer[1] == 0x4D) { - m_sdl_surface = SDL_LoadBMP_RW(rw, 1); - } else { - m_sdl_surface = IMG_Load_RW(rw, 1); + if (!decompressed_surface) { + throw SDLException(); } - if (!m_sdl_surface) { + std::unique_ptr formatted_surface(SDL_ConvertSurfaceFormat(decompressed_surface.get(), SDL_PIXELFORMAT_ABGR8888, 0), SDL_FreeSurface); + + if (!formatted_surface) { throw SDLException(); } + m_sdl_surface = PremultiplyAlpha(formatted_surface.release()); // Fix white line issue m_sdl_tex = SDL_CreateTextureFromSurface(Renderer::GetInstance()->GetSDLRenderer(), m_sdl_surface); + if (!m_sdl_tex) { throw SDLException(); } - // sdl get texture resolution - int w, h; - SDL_QueryTexture(m_sdl_tex, nullptr, nullptr, &w, &h); - + m_actualSize = {0, 0, m_sdl_surface->w, m_sdl_surface->h}; m_bDisposeTexture = true; - m_actualSize = { 0, 0, w, h }; - m_ready = true; } - - delete[] buffer; -} +} \ No newline at end of file diff --git a/Game/CMakeLists.txt b/Game/CMakeLists.txt index 8d74a4b9..f76580ad 100644 --- a/Game/CMakeLists.txt +++ b/Game/CMakeLists.txt @@ -70,27 +70,59 @@ add_executable(Game target_include_directories(Game PRIVATE "../Engine/include") if (WIN32) - add_custom_command(TARGET Game POST_BUILD + add_custom_command(TARGET Game POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/third-party/bin/x64-windows/Debug - $) + $ + ) # Create directory $/Skins/Default then # copy from ${CMAKE_SOURCE_DIR}/GameResources/Resources to $/Skins/Default - add_custom_command(TARGET Game POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory $/Skins/Default COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/GameResources/Resources - $/Skins/Default) + $/Skins/Default + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Notes + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Notes + $/Resources/Notes + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Fonts + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Fonts + $/Resources/Fonts + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Notes/Scripts + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Scripts + $/Resources/Notes/Scripts + ) else () add_custom_command(TARGET Game POST_BUILD - COMMAND ${CMAKE_COMMAND} -E make_directory - $/Skins/Default - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/GameResources/Resources - $/Skins/Default) + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Skins/Default + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Resources + $/Skins/Default + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Notes + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Notes + $/Resources/Notes + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Fonts + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Fonts + $/Resources/Fonts + COMMAND ${CMAKE_COMMAND} -E make_directory + $/Resources/Notes/Scripts + COMMAND ${CMAKE_COMMAND} -E copy_directory + ${CMAKE_SOURCE_DIR}/GameResources/Scripts + $/Resources/Notes/Scripts + ) endif () if (MSVC) diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index b7c24283..c68fa0d8 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -8,6 +8,7 @@ #include #include #include +#include float float_floor(float value) { @@ -18,7 +19,20 @@ float float_floor(float value) #endif } -double TimingInfo::CalculateBeat(double offset) +namespace { + std::string getFileExtension(const std::string& filename) { + size_t dotPos = filename.find_last_of('.'); + if (dotPos != std::string::npos) { + std::string ext = filename.substr(dotPos + 1); + // Convert extension to lowercase + std::transform(ext.begin(), ext.end(), ext.begin(), [](unsigned char c) { return std::tolower(c); }); + return ext; + } + return ""; // No extension found + } +} + +double TimingInfo::CalculateBeat(double offset) const { if (Type == TimingType::SV) { return 0; @@ -33,7 +47,7 @@ Chart::Chart() m_keyCount = 7; } -Chart::Chart(Osu::Beatmap &beatmap) +Chart::Chart(Osu::Beatmap& beatmap) // Refactor { if (!beatmap.IsValid()) { throw std::invalid_argument("Invalid osu beatmap!"); @@ -44,69 +58,79 @@ Chart::Chart(Osu::Beatmap &beatmap) } if (beatmap.CircleSize < 1 || beatmap.CircleSize > 7) { - throw std::invalid_argument("osu beatmap's Mania key must be 7"); + throw std::invalid_argument("osu beatmap's Mania key must be between 1 and 7"); } - // m_audio = beatmap.AudioFilename; m_title = std::u8string(beatmap.Title.begin(), beatmap.Title.end()); m_keyCount = (int)beatmap.CircleSize; m_artist = std::u8string(beatmap.Artist.begin(), beatmap.Artist.end()); + m_difname = std::u8string(beatmap.Version.begin(), beatmap.Version.end()); m_beatmapDirectory = beatmap.CurrentDir; - for (auto &event : beatmap.Events) { - switch (event.Type) { - case Osu::OsuEventType::Background: - { - std::string fileName = event.params[0]; - fileName.erase(std::remove(fileName.begin(), fileName.end(), '\"'), fileName.end()); + for (auto& event : beatmap.Events) { + if (event.Type == Osu::OsuEventType::Background) { + std::string fileName = event.params[0]; + fileName.erase(std::remove(fileName.begin(), fileName.end(), '\"'), fileName.end()); + m_backgroundFile = fileName; + break; + } + } - m_backgroundFile = fileName; - break; + for (auto& event : beatmap.Events) { + if (event.Type == Osu::OsuEventType::Sample) { + std::string fileName = event.params[1]; + if (fileName.front() == '\"' && fileName.back() == '\"') { + fileName = fileName.substr(1, fileName.size() - 2); } - case Osu::OsuEventType::Sample: - { - std::string fileName = event.params[1]; - fileName.erase(std::remove(fileName.begin(), fileName.end(), '\"'), fileName.end()); - - auto path = beatmap.CurrentDir / fileName; - if (std::filesystem::exists(path)) { - AutoSample sample = {}; - sample.StartTime = event.StartTime; - sample.Index = beatmap.GetCustomSampleIndex(fileName); - sample.Volume = 1; - sample.Pan = 0; - - m_autoSamples.push_back(sample); + auto path = beatmap.CurrentDir / fileName; + if (!std::filesystem::exists(path)) { + std::string extension = getFileExtension(fileName); + if (!extension.empty()) { + std::vector extensionsToTry = { ".ogg", ".wav", ".mp3" }; + for (const auto& ext : extensionsToTry) { + std::string newFileName = fileName.substr(0, fileName.find_last_of('.')) + ext; + path = beatmap.CurrentDir / newFileName; + if (std::filesystem::exists(path)) { + fileName = newFileName; + break; + } + } } + } - break; + if (std::filesystem::exists(path)) { + AutoSample sample = {}; + sample.StartTime = event.StartTime; + sample.Index = beatmap.GetCustomSampleIndex(fileName); + sample.Volume = 1; + sample.Pan = 0; + m_autoSamples.push_back(sample); + } else { + Logs::Puts("[Chart] Custom sample file not found: %s", fileName.c_str()); } } } - { - AutoSample sample = {}; - if (beatmap.AudioLeadIn = 0) { - sample.StartTime = beatmap.AudioLeadIn - 1; // Handle if offset 0 that causing audio delay - } - else { - sample.StartTime = beatmap.AudioLeadIn; - } - sample.Index = beatmap.GetCustomSampleIndex(beatmap.AudioFilename); - sample.Volume = 1; - sample.Pan = 0; - - m_autoSamples.push_back(sample); + AutoSample autoSample = {}; + if (beatmap.AudioLeadIn = 0) { + autoSample.StartTime = beatmap.AudioLeadIn - 1; // Handle if offset 0 that causing audio delay } + else { + autoSample.StartTime = beatmap.AudioLeadIn; + } + autoSample.Index = beatmap.GetCustomSampleIndex(beatmap.AudioFilename); + autoSample.Volume = 1.0f; + autoSample.Pan = 0; + m_autoSamples.push_back(autoSample); - for (auto ¬e : beatmap.HitObjects) { + for (auto& note : beatmap.HitObjects) { NoteInfo info = {}; info.StartTime = note.StartTime; info.Type = NoteType::NORMAL; info.Keysound = note.KeysoundIndex; info.LaneIndex = static_cast(float_floor(note.X * static_cast(beatmap.CircleSize) / 512.0f)); - info.Volume = static_cast(note.Volume) / 100.0f; + info.Volume = note.Volume > 0 ? static_cast(note.Volume) / 100.0f : 1.0f; info.Pan = 0; if (note.Type == 128) { @@ -117,15 +141,12 @@ Chart::Chart(Osu::Beatmap &beatmap) m_notes.push_back(info); } - for (auto &timing : beatmap.TimingPoints) { - bool IsSV = timing.Inherited == 0 || timing.BeatLength < 0; - - if (IsSV) { + for (auto& timing : beatmap.TimingPoints) { + if (timing.Inherited == 0 || timing.BeatLength < 0) { TimingInfo info = {}; info.StartTime = timing.Offset; info.Value = std::clamp(-100.0f / timing.BeatLength, 0.1f, 10.0f); info.Type = TimingType::SV; - m_svs.push_back(info); } else { TimingInfo info = {}; @@ -133,50 +154,25 @@ Chart::Chart(Osu::Beatmap &beatmap) info.Value = 60000.0f / timing.BeatLength; info.TimeSignature = timing.TimeSignature; info.Type = TimingType::BPM; - m_bpms.push_back(info); } } for (int i = 0; i < beatmap.HitSamples.size(); i++) { - auto &keysound = beatmap.HitSamples[i]; - + auto& keysound = beatmap.HitSamples[i]; auto path = beatmap.CurrentDir / keysound; Sample sm = {}; sm.FileName = path; sm.Index = i; - m_samples.push_back(sm); } - for (auto ¬e : m_notes) { - switch (m_keyCount) { - case 4: - { - if (note.LaneIndex >= 2) { - note.LaneIndex += 3; - } - break; - } - - case 5: - { - if (note.LaneIndex == 3) { - note.LaneIndex += 1; - } else if (note.LaneIndex >= 4) { - note.LaneIndex += 2; - } - break; - } - } - } - CalculateBeat(); - SortTimings(); - NormalizeTimings(); + AdjustLaneIndex(); + ComputeKeyCount(); ComputeHash(); } @@ -206,7 +202,7 @@ Chart::Chart(BMS::BMSFile &file) info.Type = NoteType::NORMAL; info.LaneIndex = note.Lane; info.Keysound = note.SampleIndex; - info.Volume = 1; + info.Volume = 1.0f; info.Pan = 0; if (note.EndTime != -1) { @@ -222,7 +218,7 @@ Chart::Chart(BMS::BMSFile &file) AutoSample sm = {}; sm.StartTime = note.StartTime; sm.Index = note.SampleIndex; - sm.Volume = 1; + sm.Volume = 1.0f; sm.Pan = 0; m_autoSamples.push_back(sm); @@ -266,7 +262,7 @@ Chart::Chart(BMS::BMSFile &file) AutoSample sm = {}; sm.StartTime = autoSample.StartTime; sm.Index = autoSample.SampleIndex; - sm.Volume = 1; + sm.Volume = 1.0f; sm.Pan = 0; m_autoSamples.push_back(sm); @@ -379,7 +375,7 @@ Chart::Chart(O2::OJN &file, int diffIndex) -void Chart::CalculateBeat() +void Chart::CalculateBeat() { m_bpms[0].Beat = 0; for (size_t i = 1; i < m_bpms.size(); i++) { @@ -387,7 +383,7 @@ void Chart::CalculateBeat() } } -void Chart::SortTimings() +void Chart::SortTimings() { std::sort(m_autoSamples.begin(), m_autoSamples.end(), [](const AutoSample& a, const AutoSample& b) { return a.StartTime < b.StartTime; @@ -459,7 +455,7 @@ void Chart::ApplyMod(Mod mod, void *data) break; } - case Mod::PANIC: + case Mod::PANIC: // pler { std::vector lanes(m_keyCount); for (int i = 0; i < m_keyCount; i++) { @@ -478,6 +474,7 @@ void Chart::ApplyMod(Mod mod, void *data) measureBPM[measure] = bpm.Value; } + // Shuffle lanes per measure for (auto& note : m_notes) { int measure = -1; for (size_t i = 0; i < m_bpms.size(); i++) { @@ -491,12 +488,6 @@ void Chart::ApplyMod(Mod mod, void *data) measure = static_cast(m_bpms.back().CalculateBeat(note.StartTime) / m_bpms.back().TimeSignature); } - for (int i = measure; i > 0; i--) { - if (measureBPM.find(i) == measureBPM.end()) { - measureBPM[i] = measureBPM[i - 1]; - } - } - if (measureLane.find(measure) == measureLane.end()) { std::shuffle(std::begin(lanes), std::end(lanes), rng); measureLane[measure] = lanes; @@ -512,27 +503,10 @@ void Chart::ApplyMod(Mod mod, void *data) } } - // Log the randomization pattern for each measure - //int prevMeasure = -1; - //std::vector prevPattern; - //for (const auto& [measure, randomizedLane] : measureLane) { - // if (prevMeasure != -1 && prevPattern == randomizedLane) { - // continue; // Skip logging if the pattern is the same as the previous measure - // } - // std::stringstream pattern; - // for (int lane : randomizedLane) { - // pattern << lane; - // } - // int startMeasure = prevMeasure == -1 ? 0 : prevMeasure + 1; - // int endMeasure = measure; - // Logs::Puts("[Chart] Randomized Lane from Measure %d to %d with pattern: %s", startMeasure, endMeasure, pattern.str().c_str()); - // prevMeasure = measure; - // prevPattern = randomizedLane; - //} - break; } + case Mod::REARRANGE: { int *lanes = reinterpret_cast(data); @@ -722,6 +696,41 @@ void Chart::NormalizeTimings() m_svs = result; } +void Chart::AdjustLaneIndex() // Fix vector subscript out of range +{ + for (auto& note : m_notes) { + switch (m_keyCount) { // Fuck, this hard to figure out + case 4: + { + if (note.LaneIndex >= 2) { + note.LaneIndex += 3; + } + break; + } + case 5: + { + if (note.LaneIndex == 2) { + note.LaneIndex += 1; + } + else if (note.LaneIndex >= 3) { + note.LaneIndex += 2; + } + break; + } + case 6: + { + if (note.LaneIndex >= 3) { + note.LaneIndex += 1; + } + break; + } + default: + m_keyCount = 7; + break; + } + } +} + void Chart::ComputeKeyCount() { bool Lanes[7] = { false, false, false, false, false, false }; @@ -753,7 +762,6 @@ void Chart::ComputeKeyCount() else if (Lanes[0] && Lanes[1] && !Lanes[2] && !Lanes[3] && !Lanes[4] && Lanes[5] && Lanes[6]) { m_keyCount = 4; } - // Otherwise, the pattern does not match any of the known K values else { Logs::Puts("[Chart] Unknown lane pattern, fallback to 7K"); m_keyCount = 7; diff --git a/Game/src/Data/Chart.hpp b/Game/src/Data/Chart.hpp index 3515ce63..e069bfe0 100644 --- a/Game/src/Data/Chart.hpp +++ b/Game/src/Data/Chart.hpp @@ -52,7 +52,8 @@ struct TimingInfo float TimeSignature; TimingType Type; - double CalculateBeat(double offset); + //double CalculateBeat(double offset); + double CalculateBeat(double offset) const; }; struct Sample @@ -105,6 +106,7 @@ class Chart std::vector m_backgroundBuffer; std::u8string m_title; std::u8string m_artist; + std::u8string m_difname; std::string m_audio; std::filesystem::path m_beatmapDirectory; @@ -116,6 +118,8 @@ class Chart std::vector m_samples; std::vector m_autoSamples; + void AdjustLaneIndex(); + private: double PredefinedAudioLength = -1; diff --git a/Game/src/Data/OJM.cpp b/Game/src/Data/OJM.cpp index c6a38ced..1d8b654a 100644 --- a/Game/src/Data/OJM.cpp +++ b/Game/src/Data/OJM.cpp @@ -9,16 +9,20 @@ constexpr int kM30Signature = 0x0030334D; constexpr int kOMCSignature = 0x00434D4F; constexpr int kOJMSignature = 0x004D4A4F; +const char MASK_SCRAMBLE1[] = { 0x73, 0x63, 0x72, 0x61, 0x6D, 0x62, 0x6C, 0x65, 0x31 }; +const char MASK_SCRAMBLE2[] = { 0x73, 0x63, 0x72, 0x61, 0x6D, 0x62, 0x6C, 0x65, 0x32 }; +const char MASK_DECODE[] = { 0x64, 0x65, 0x63, 0x6F, 0x64, 0x65 }; +const char MASK_DECRYPT[] = { 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74 }; const char MASK_NAMI[] = { 0x6E, 0x61, 0x6D, 0x69 }; const char MASK_0412[] = { 0x30, 0x34, 0x31, 0x32 }; void M30Xor(char *data, size_t sz, const char *xorKey) { for (int i = 0; i + 3 < sz; i += 4) { - data[i] ^= xorKey[0]; - data[i + 1] ^= xorKey[1]; - data[i + 2] ^= xorKey[2]; - data[i + 3] ^= xorKey[3]; + data[i] ^= xorKey[i % 4]; + data[i + 1] ^= xorKey[(i + 1) % 4]; + data[i + 2] ^= xorKey[(i + 2) % 4]; + data[i + 3] ^= xorKey[(i + 3) % 4]; } } @@ -182,7 +186,7 @@ void OJM::LoadM30Data(std::fstream &fs) fs.read((char *)&Header, sizeof(M30Header)); - for (int i = 0; i < Header.sampleSize; i++) { + for (int i = 0; i < Header.sampleCount; i++) { // This fix no sound in few OJM struct M30SampleHeader { char sampleName[32]; @@ -204,18 +208,26 @@ void OJM::LoadM30Data(std::fstream &fs) fs.read((char *)buffer, SampleHeader.sampleSize); switch (Header.encryptionFlag) { - case 0: - break; - case 16: - { - M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_NAMI); - break; - } - case 32: - { - M30Xor((char *)buffer, SampleHeader.sampleSize, MASK_0412); - break; - } + case 0: + break; + case 1: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_SCRAMBLE1); + break; + case 2: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_SCRAMBLE2); + break; + case 4: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_DECODE); + break; + case 8: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_DECRYPT); + break; + case 16: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_NAMI); + break; + case 32: + M30Xor((char*)buffer, SampleHeader.sampleSize, MASK_0412); + break; } // OGG Sample diff --git a/Game/src/Data/Util/Util.cpp b/Game/src/Data/Util/Util.cpp index f4db3980..14dcc3a8 100644 --- a/Game/src/Data/Util/Util.cpp +++ b/Game/src/Data/Util/Util.cpp @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include std::vector splitString(std::string &input, char delimeter) { @@ -130,51 +133,46 @@ void flipArray(uint8_t *arr, size_t size) } } -std::u8string CodepageToUtf8(const char *string, size_t str_len, const char *encoding) -{ - std::u8string result; - iconv_t conv = iconv_open("UTF-8", encoding); +std::u8string CodepageToUtf8(const char* string, size_t str_len, const char* encoding) { // Refactor + // Open iconv conversion descriptor + iconv_t conv = iconv_open("UTF-8", encoding); if (conv == (iconv_t)-1) { return u8""; } - // size_t inbytesleft = str_len; - // size_t outbytesleft = str_len * 4; - // char* inbuf = (char*)string; - // char* outbuf = (char*)malloc(outbytesleft); - // char* outbufptr = outbuf; - - // if (iconv(conv, &inbuf, &inbytesleft, &outbufptr, &outbytesleft) == (size_t)-1) { - // free(outbuf); - // iconv_close(conv); - // return std::u8string((const char8_t*)strerror(errno)); - // } - - // result = std::u8string((char8_t*)outbuf, str_len * 4 - outbytesleft); - // free(outbuf); - // iconv_close(conv); - // return result; - - size_t inbytesleft = str_len; - size_t outbytesleft = str_len * 4; - char *inbuf = (char *)string; - std::vector outbuf; - outbuf.resize(outbytesleft, 0); - - char *outbufptr = outbuf.data(); - - if (iconv(conv, &inbuf, &inbytesleft, &outbufptr, &outbytesleft) == (size_t)-1) { - iconv_close(conv); - - // return whatever we have left, even if it's not valid - size_t len = strlen(outbuf.data()); - std::u8string remaining = std::u8string((const char8_t *)outbuf.data(), len); - - return remaining; + std::u8string result; + size_t inbytesleft = str_len; + const char* inbuf = string; + size_t outbufsize = str_len * 4; // Initial output buffer size + std::vector outbuf(outbufsize); + + while (true) { + char* outbufptr = outbuf.data(); + size_t outbytesleft = outbuf.size(); + + // Reset errno to check for errors after iconv call + errno = 0; + + size_t ret = iconv(conv, (char**)&inbuf, &inbytesleft, &outbufptr, &outbytesleft); + if (ret != (size_t)-1) { + // Successfully converted + result.append((const char8_t*)outbuf.data(), outbuf.size() - outbytesleft); + break; + } + else if (errno == E2BIG) { + // Resize buffer and retry if buffer was too small + size_t processed = outbuf.size() - outbytesleft; + result.append((const char8_t*)outbuf.data(), processed); + outbufsize *= 2; + outbuf.resize(outbufsize); + } + else { + // Return whatever we have left, even if it's not valid + result.append((const char8_t*)outbuf.data(), outbuf.size() - outbytesleft); + break; + } } - result = std::u8string((char8_t *)outbuf.data(), str_len * 4 - outbytesleft); iconv_close(conv); - return result; -} +} \ No newline at end of file diff --git a/Game/src/Engine/DrawableNote.cpp b/Game/src/Engine/DrawableNote.cpp index db4f9b1e..84562e1b 100644 --- a/Game/src/Engine/DrawableNote.cpp +++ b/Game/src/Engine/DrawableNote.cpp @@ -5,6 +5,7 @@ DrawableNote::DrawableNote(NoteImage* frame) : FrameTimer::FrameTimer() { + SetFPS(0.0); // HACK: Stop note glitching by force it to 0 FPS (idk why it still initialized by itself if i remove SETFPS) m_frames.reserve(frame->Texture.size()); // Reserve memory for frames vector if (Renderer::GetInstance()->IsVulkan()) { @@ -21,6 +22,4 @@ DrawableNote::DrawableNote(NoteImage* frame) : FrameTimer::FrameTimer() } AnchorPoint = { 0.0, 1.0 }; - - SetFPS(0); // slighly fix stupid glitch } diff --git a/Game/src/Engine/FrameTimer.cpp b/Game/src/Engine/FrameTimer.cpp index f015773e..1d938bc3 100644 --- a/Game/src/Engine/FrameTimer.cpp +++ b/Game/src/Engine/FrameTimer.cpp @@ -2,57 +2,53 @@ #include "Rendering/Renderer.h" #include "Texture/Texture2D.h" -FrameTimer::FrameTimer() +FrameTimer::FrameTimer() : + Repeat(false), + m_currentFrame(0), + m_frameTime(1.0 / 60.0), + m_currentTime(0), + AlphaBlend(false), + Size(UDim2::fromScale(1, 1)), + TintColor({ 1.0f, 1.0f, 1.0f }) { - Repeat = false; - m_currentFrame = 0; - m_frameTime = 1.0f / 60.0f; - m_currentTime = 0; - AlphaBlend = false; - Size = UDim2::fromScale(1, 1); - TintColor = { 1.0f, 1.0f, 1.0f }; } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = frames; + m_frames = std::move(frames); } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = std::vector(); - for (auto frame : frames) { + for (const auto& frame : frames) { m_frames.emplace_back(new Texture2D(frame)); } } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = std::vector(); - for (auto frame : frames) { + for (const auto& frame : frames) { m_frames.emplace_back(new Texture2D(frame)); } } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = std::vector(); - for (auto frame : frames) { + for (const auto& frame : frames) { m_frames.emplace_back(new Texture2D(frame)); } } -FrameTimer::FrameTimer(std::vector frames) : FrameTimer::FrameTimer() +FrameTimer::FrameTimer(std::vector frames) : FrameTimer() { - m_frames = std::vector(); - for (auto frame : frames) { + for (const auto& frame : frames) { m_frames.emplace_back(new Texture2D(frame)); } } FrameTimer::~FrameTimer() { - for (auto &f : m_frames) { + for (auto& f : m_frames) { delete f; } } @@ -62,13 +58,12 @@ void FrameTimer::Draw(double delta) Draw(delta, nullptr); } -void FrameTimer::Draw(double delta, Rect *clip) +void FrameTimer::Draw(double delta, Rect* clip) { m_currentTime += delta; if (m_currentTime >= m_frameTime) { m_currentTime -= m_frameTime; - m_currentFrame++; } @@ -79,21 +74,22 @@ void FrameTimer::Draw(double delta, Rect *clip) if (m_currentFrame < m_frames.size()) { CalculateSize(); - m_frames[m_currentFrame]->AlphaBlend = AlphaBlend; - m_frames[m_currentFrame]->TintColor = TintColor; + auto currentFrame = m_frames[m_currentFrame]; + currentFrame->AlphaBlend = AlphaBlend; + currentFrame->TintColor = TintColor; if (m_currentFrame != 0) { - m_frames[m_currentFrame]->Position = UDim2::fromOffset(AbsolutePosition.X, AbsolutePosition.Y); - m_frames[m_currentFrame]->Size = UDim2::fromOffset(AbsoluteSize.X, AbsoluteSize.Y); - m_frames[m_currentFrame]->AnchorPoint = { 0, 0 }; + currentFrame->Position = UDim2::fromOffset(AbsolutePosition.X, AbsolutePosition.Y); + currentFrame->Size = UDim2::fromOffset(AbsoluteSize.X, AbsoluteSize.Y); + currentFrame->AnchorPoint = { 0, 0 }; } - m_frames[m_currentFrame]->Draw(clip); + currentFrame->Draw(clip); } } -void FrameTimer::SetFPS(float fps) +void FrameTimer::SetFPS(double fps) { - m_frameTime = 1.0f / fps; + m_frameTime = 1.0 / fps; } void FrameTimer::ResetIndex() @@ -103,7 +99,7 @@ void FrameTimer::ResetIndex() void FrameTimer::LastIndex() { - m_currentFrame = (int)m_frames.size() - 1; + m_currentFrame = static_cast(m_frames.size()) - 1; } void FrameTimer::SetIndexAt(int idx) @@ -113,11 +109,12 @@ void FrameTimer::SetIndexAt(int idx) void FrameTimer::CalculateSize() { - m_frames[0]->AnchorPoint = AnchorPoint; - m_frames[0]->Size = Size; - m_frames[0]->Position = Position; - m_frames[0]->CalculateSize(); - - AbsoluteSize = m_frames[0]->AbsoluteSize; - AbsolutePosition = m_frames[0]->AbsolutePosition; + auto& firstFrame = *m_frames[0]; + firstFrame.AnchorPoint = AnchorPoint; + firstFrame.Size = Size; + firstFrame.Position = Position; + firstFrame.CalculateSize(); + + AbsoluteSize = firstFrame.AbsoluteSize; + AbsolutePosition = firstFrame.AbsolutePosition; } diff --git a/Game/src/Engine/FrameTimer.hpp b/Game/src/Engine/FrameTimer.hpp index b0d5efab..b8846be7 100644 --- a/Game/src/Engine/FrameTimer.hpp +++ b/Game/src/Engine/FrameTimer.hpp @@ -16,11 +16,11 @@ class FrameTimer { public: FrameTimer(); - FrameTimer(std::vector frames); + FrameTimer(std::vector frames); FrameTimer(std::vector frames); FrameTimer(std::vector frames); - FrameTimer(std::vector frames); - FrameTimer(std::vector frames); + FrameTimer(std::vector frames); + FrameTimer(std::vector frames); ~FrameTimer(); bool Repeat; @@ -35,8 +35,8 @@ class FrameTimer Vector2 AbsoluteSize; void Draw(double delta); - void Draw(double delta, Rect *clip); - void SetFPS(float fps); + void Draw(double delta, Rect* clip); + void SetFPS(double fps); void ResetIndex(); void LastIndex(); void SetIndexAt(int idx); diff --git a/Game/src/Engine/LuaScripting.cpp b/Game/src/Engine/LuaScripting.cpp index 949a2506..e34dac12 100644 --- a/Game/src/Engine/LuaScripting.cpp +++ b/Game/src/Engine/LuaScripting.cpp @@ -147,15 +147,30 @@ void GetLuaState(ScriptState &state, sol::table &table) state.init = table["init"]; } -void LuaScripting::TryLoadGroup(SkinGroup group) + +void LuaScripting::TryLoadGroup(SkinGroup group) // Not fully testes unless someone want make skin with lua script { - auto fullPath = m_lua_dir_path / m_expected_files[group]; + std::filesystem::path fullPath; + + if (group == SkinGroup::Notes && EnvironmentSetup::GetInt("NoteSkin") != 2) { + auto path = std::filesystem::current_path() / "Resources"; + if (EnvironmentSetup::GetInt("NoteSkin") == 1) { + fullPath = path / "Scripts" / "Notes.lua"; + } + else { + fullPath = path / "Scripts" / "Notes.lua"; + } + } + else { + fullPath = m_lua_dir_path / m_expected_files[group]; + } + if (!std::filesystem::exists(fullPath)) { throw std::runtime_error("Missing file: " + fullPath.string()); } m_states[group] = {}; - auto &state = m_states[group]; + auto& state = m_states[group]; state.state = sol::state(); if (state.state.lua_state() == nullptr) { diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 7c92c744..21f5e0c2 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -6,6 +6,7 @@ #include "GameAudioSampleCache.hpp" #include "NoteImageCacheManager.hpp" #include "RhythmEngine.hpp" +#include #define REMOVE_TIME 800 #define HOLD_COMBO_TICK 100 @@ -152,6 +153,7 @@ void Note::Load(NoteInfoDesc *desc) m_relPos = 0; m_lastScoreTime = -1; + GetNoteSize(); } void Note::Update(double delta) @@ -206,127 +208,153 @@ void Note::Update(double delta) } } } - bool pressed = IsPassed(); - if (pressed) { - m_state = NoteState::DO_REMOVE; +} + +// I ended refactor whole note code +void Note::DrawHead(double delta, double headPosY, int guideLineLength, Rect &playRect) { + m_head->Position = UDim2::fromOffset(m_laneOffset, headPosY); + m_head->SetIndexAt(m_engine->GetNoteImageIndex()); + m_head->Draw(delta, &playRect); + + if (guideLineLength > 0) { + m_trail_down->Position = m_head->Position; + m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_down->AnchorPoint = { 0, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); + m_trail_down->AnchorPoint = { 1, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_up->Position = m_head->Position + UDim2::fromOffset(0, -m_head->AbsoluteSize.Y); + m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_up->AnchorPoint = { 0, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + + m_trail_up->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, -m_head->AbsoluteSize.Y); + m_trail_up->AnchorPoint = { 1, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + } +} + +void Note::DrawBody(double delta, double bodyPosY, double bodyHeight, Rect &playRect) { + m_body->Position = UDim2::fromOffset(m_laneOffset, bodyPosY - (m_head->AbsoluteSize.Y / 2.0)); + m_body->Size = { 1, 0, 0, bodyHeight }; + m_body->SetIndexAt(m_engine->GetNoteImageIndex()); + m_body->Draw(delta, &playRect); +} + +void Note::DrawTail(double delta, double tailPosY, int guideLineLength, Rect &playRect) { + m_tail->Position = UDim2::fromOffset(m_laneOffset, tailPosY); + m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); + m_tail->Draw(delta, &playRect); + + if (guideLineLength > 0) { + m_trail_down->Position = m_tail->Position; + m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_down->AnchorPoint = { 0, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_down->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, 0); + m_trail_down->AnchorPoint = { 1, 0 }; + m_trail_down->AlphaBlend = true; + m_trail_down->Draw(delta, &playRect); + + m_trail_up->Position = m_tail->Position + UDim2::fromOffset(0, -m_tail->AbsoluteSize.Y); + m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); + m_trail_up->AnchorPoint = { 0, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); + + m_trail_up->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, -m_tail->AbsoluteSize.Y); + m_trail_up->AnchorPoint = { 1, 1 }; + m_trail_up->AlphaBlend = true; + m_trail_up->Draw(delta, &playRect); } } +void Note::SetTransparency() { + float transparency = 0.9f; + if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { + transparency = 1.0f; + } + else if (m_hitResult >= NoteResult::MISS && m_state == NoteState::HOLD_MISSED_ACTIVE) { + transparency = 0.7f; + } + m_head->TintColor = { transparency, transparency, transparency }; + m_body->TintColor = { transparency, transparency, transparency }; + m_tail->TintColor = { transparency, transparency, transparency }; +} + void Note::Render(double delta) { - if (IsRemoveable()) + if (IsRemoveable()) { return; - if (!m_drawAble) + } + if (!m_drawAble) { return; + } - auto resolution = m_engine->GetResolution(); - auto hitPos = m_engine->GetHitPosition(); + auto resolution = m_engine->GetResolution(); + auto hitPos = m_engine->GetHitPosition(); double trackPosition = m_engine->GetTrackPosition(); - int min = -100, max = hitPos + 25; + int min = -100, max = GameWindow::GetInstance()->GetBufferHeight(); auto playRect = m_engine->GetPlayRectangle(); int guideLineIndex = m_engine->GetGuideLineIndex(); - int guideLineLength = 24 * length_multiplier[guideLineIndex]; + double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; + double headPosY = lerp(0.0, static_cast(hitPos), static_cast(y1)); + bool isHeadVisible = isWithinRange(headPosY, min, max); + if (m_type == NoteType::HOLD) { - double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; double y2 = CalculateNotePosition(trackPosition, m_endTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; + double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); + bool isTailVisible = isWithinRange(tailPosY, min, max); - m_head->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y1)); - m_tail->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y2)); - - float Transparency = 0.9f; - - if (m_hitResult >= NoteResult::GOOD && m_state == NoteState::HOLD_ON_HOLDING) { - // m_head->Position.Y.Offset = hitPos; - Transparency = 1.0f; + if (EnvironmentSetup::GetInt("NoPercy") == 1) { + tailPosY += m_tail->AbsoluteSize.Y; } - m_head->CalculateSize(); - m_tail->CalculateSize(); - - double headPos = m_head->AbsolutePosition.Y + (m_head->AbsoluteSize.Y / 2.0); - double tailPos = m_tail->AbsolutePosition.Y + (m_tail->AbsoluteSize.Y / 2.0); - - double height = headPos - tailPos; - double position = (height / 2.0) + tailPos; - - m_body->Position = UDim2::fromOffset(m_laneOffset, position); - m_body->Size = { 1, 0, 0, height }; - - m_body->TintColor = { Transparency, Transparency, Transparency }; - - bool b1 = isWithinRange(m_head->Position.Y.Offset, min, max); - bool b2 = isWithinRange(m_tail->Position.Y.Offset, min, max); - - if (isCollision(m_tail->Position.Y.Offset, m_head->Position.Y.Offset, min, max)) { - m_body->SetIndexAt(m_engine->GetNoteImageIndex()); - m_body->Draw(delta, &playRect); - } + double bodyPosY = (headPosY + tailPosY) / 2.0; + double bodyHeight = std::abs(headPosY - (m_head->AbsoluteSize.Y / 2.0)) - (tailPosY - (m_head->AbsoluteSize.Y / 2.0)); - if (b1) { - if (guideLineLength > 0) { - m_trail_down->Position = m_head->Position; - m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_down->AnchorPoint = { 0, 0 }; - m_trail_down->Draw(delta, &playRect); + if (EnvironmentSetup::GetInt("LNBodyOnTop") == 1) { + if (isHeadVisible) { + DrawHead(delta, headPosY, guideLineLength, playRect); + } - m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); - m_trail_down->AnchorPoint = { 1, 0 }; - m_trail_down->Draw(delta, &playRect); + if (isTailVisible) { + DrawTail(delta, tailPosY, guideLineLength, playRect); } - m_head->SetIndexAt(m_engine->GetNoteImageIndex()); - m_head->Draw(delta, &playRect); + SetTransparency(); + DrawBody(delta, bodyPosY, bodyHeight, playRect); } + else { + SetTransparency(); + DrawBody(delta, bodyPosY, bodyHeight, playRect); - if (b2) { - if (guideLineLength > 0) { - m_trail_up->Position = m_tail->Position + UDim2::fromOffset(0, -m_tail->AbsoluteSize.Y); - m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_up->AnchorPoint = { 0, 1 }; - m_trail_up->Draw(delta, &playRect); - - m_trail_up->Position = m_tail->Position + UDim2::fromOffset(m_tail->AbsoluteSize.X, -m_tail->AbsoluteSize.Y); - m_trail_up->AnchorPoint = { 1, 1 }; - m_trail_up->Draw(delta, &playRect); + if (isTailVisible) { + DrawTail(delta, tailPosY, guideLineLength, playRect); } - m_tail->SetIndexAt(m_engine->GetNoteImageIndex()); - m_tail->Draw(delta, &playRect); - } - } else { - double y1 = CalculateNotePosition(trackPosition, m_initialTrackPosition, 1000.0, m_engine->GetNotespeed(), false) / 1000.0; - m_head->Position = UDim2::fromOffset(m_laneOffset, lerp(0.0, (double)hitPos, (float)y1)); - m_head->CalculateSize(); - - bool b1 = isWithinRange(m_head->Position.Y.Offset, min, max); - - if (b1) { - if (guideLineLength > 0) { - m_trail_down->Position = m_head->Position; - m_trail_down->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_down->AnchorPoint = { 0, 0 }; - m_trail_down->Draw(delta, &playRect); - - m_trail_down->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, 0); - m_trail_down->AnchorPoint = { 1, 0 }; - m_trail_down->Draw(delta, &playRect); - - m_trail_up->Position = m_head->Position + UDim2::fromOffset(0, -m_head->AbsoluteSize.Y); - m_trail_up->Size = UDim2::fromOffset(1, guideLineLength); - m_trail_up->AnchorPoint = { 0, 1 }; - m_trail_up->Draw(delta, &playRect); - - m_trail_up->Position = m_head->Position + UDim2::fromOffset(m_head->AbsoluteSize.X, -m_head->AbsoluteSize.Y); - m_trail_up->AnchorPoint = { 1, 1 }; - m_trail_up->Draw(delta, &playRect); + if (isHeadVisible) { + DrawHead(delta, headPosY, guideLineLength, playRect); } + } + } + else { - m_head->SetIndexAt(m_engine->GetNoteImageIndex()); - m_head->Draw(delta, &playRect); + if (isHeadVisible) { + DrawHead(delta, headPosY, guideLineLength, playRect); } } } @@ -393,27 +421,38 @@ std::tuple Note::CheckHit() if (m_type == NoteType::NORMAL) { double time_to_end = m_engine->GetGameAudioPosition() - m_startTime; - auto result = judge->CalculateResult(this); + auto result = judge->CalculateResult(this); if (std::get(result)) { m_ignore = false; } + else if (time_to_end) { + m_ignore = true; + } return result; - } else { + } + else { if (m_state == NoteState::HOLD_PRE) { double time_to_end = m_engine->GetGameAudioPosition() - m_startTime; - auto result = judge->CalculateResult(this); + auto result = judge->CalculateResult(this); if (std::get(result)) { m_ignore = false; } + else if (time_to_end) { + m_ignore = true; + } return result; - } else if (m_state == NoteState::HOLD_MISSED_ACTIVE) { + } + else if (m_state == NoteState::HOLD_MISSED_ACTIVE) { double time_to_end = m_engine->GetGameAudioPosition() - m_endTime; - auto result = judge->CalculateResult(this); + auto result = judge->CalculateResult(this); if (std::get(result)) { m_ignore = false; } + else if (time_to_end) { + m_ignore = true; + } return result; } @@ -425,7 +464,7 @@ std::tuple Note::CheckHit() std::tuple Note::CheckRelease() { if (m_type == NoteType::HOLD) { - double time_to_end = m_engine->GetGameAudioPosition() - m_endTime; + double time_to_end = m_engine->GetGameAudioPosition() - m_endTime; JudgeBase *judge = m_engine->GetJudge(); if (m_state == NoteState::HOLD_ON_HOLDING || m_state == NoteState::HOLD_MISSED_ACTIVE) { @@ -433,6 +472,7 @@ std::tuple Note::CheckRelease() if (std::get(result)) { if (m_state == NoteState::HOLD_MISSED_ACTIVE) { + m_ignore = false; return { true, NoteResult::BAD }; } @@ -440,8 +480,15 @@ std::tuple Note::CheckRelease() } if (m_state == NoteState::HOLD_ON_HOLDING) { + if (time_to_end) { + m_ignore = true; + } return { true, NoteResult::MISS }; - } else { + } + else { + if (time_to_end) { + m_ignore = true; + } return { false, NoteResult::MISS }; } } @@ -494,7 +541,7 @@ void Note::OnRelease(NoteResult result) if (result == NoteResult::MISS) { //GameAudioSampleCache::Stop(m_keysoundIndex); - m_state = NoteState::DO_REMOVE; + m_state = NoteState::HOLD_MISSED_ACTIVE; m_track->HandleHoldScore(HoldResult::HoldBreak); m_track->HandleScore({ result, @@ -525,12 +572,17 @@ void Note::SetDrawable(bool drawable) m_drawAble = drawable; } -bool Note::IsHoldEffectDrawable() +void Note::GetNoteSize() +{ + EnvironmentSetup::SetInt("NoteSize", static_cast(m_head->AbsoluteSize.Y)); +} + +bool Note::IsHoldEffectDrawable() const { return m_shouldDrawHoldEffect; } -bool Note::IsDrawable() +bool Note::IsDrawable() const { if (m_removeAble) return false; @@ -538,22 +590,22 @@ bool Note::IsDrawable() return m_drawAble; } -bool Note::IsRemoveable() +bool Note::IsRemoveable() const { return m_state == NoteState::DO_REMOVE; } -bool Note::IsPassed() +bool Note::IsPassed() const { return m_state == NoteState::NORMAL_NOTE_PASSED || m_state == NoteState::HOLD_PASSED || IsRemoveable(); } -bool Note::IsHeadHit() +bool Note::IsHeadHit() const { return m_didHitHead; } -bool Note::IsTailHit() +bool Note::IsTailHit() const { return m_didHitTail; } diff --git a/Game/src/Engine/Note.hpp b/Game/src/Engine/Note.hpp index 8061113a..4fdd8510 100644 --- a/Game/src/Engine/Note.hpp +++ b/Game/src/Engine/Note.hpp @@ -52,6 +52,10 @@ class Note { void Load(NoteInfoDesc* desc); void Update(double delta); + void DrawHead(double delta, double headPosY, int guideLineLength, Rect& playRect); + void DrawBody(double delta, double bodyPosY, double bodyHeight, Rect& playRect); + void DrawTail(double delta, double tailPosY, int guideLineLength, Rect& playRect); + void SetTransparency(); void Render(double delta); double GetInitialTrackPosition() const; @@ -71,14 +75,16 @@ class Note { void SetXPosition(int x); void SetDrawable(bool drawable); - - bool IsHoldEffectDrawable(); - bool IsDrawable(); - bool IsRemoveable(); - bool IsPassed(); - bool IsHeadHit(); - bool IsTailHit(); + void GetNoteSize(); + + bool IsHoldEffectDrawable() const; + bool IsDrawable() const; + bool IsRemoveable() const; + bool IsPassed() const; + + bool IsHeadHit() const; + bool IsTailHit() const; void Release(); diff --git a/Game/src/Engine/NoteImageCacheManager.cpp b/Game/src/Engine/NoteImageCacheManager.cpp index b148740c..a5debe85 100644 --- a/Game/src/Engine/NoteImageCacheManager.cpp +++ b/Game/src/Engine/NoteImageCacheManager.cpp @@ -4,10 +4,6 @@ constexpr int MAX_OBJECTS = 64; NoteImageCacheManager::NoteImageCacheManager() { - m_totalCount = 0; - m_totalNoteCount = 0; - m_totalHoldCount = 0; - m_totalTrailCount = 0; } NoteImageCacheManager::~NoteImageCacheManager() { @@ -59,7 +55,6 @@ void NoteImageCacheManager::Repool(DrawableNote* image, NoteImageType noteType) return; m_noteTextures[noteType].push_back(image); - m_totalNoteCount++; } void NoteImageCacheManager::RepoolHold(DrawableNote* image, NoteImageType noteType) { @@ -67,7 +62,6 @@ void NoteImageCacheManager::RepoolHold(DrawableNote* image, NoteImageType noteTy return; m_holdTextures[noteType].push_back(image); - m_totalHoldCount++; } void NoteImageCacheManager::RepoolTrail(DrawableNote* image, NoteImageType noteType) { @@ -75,7 +69,6 @@ void NoteImageCacheManager::RepoolTrail(DrawableNote* image, NoteImageType noteT return; m_trailTextures[noteType].push_back(image); - m_totalTrailCount++; } DrawableNote* NoteImageCacheManager::Depool(NoteImageType noteType) { diff --git a/Game/src/Engine/NoteImageCacheManager.hpp b/Game/src/Engine/NoteImageCacheManager.hpp index 37957fa7..3850a41b 100644 --- a/Game/src/Engine/NoteImageCacheManager.hpp +++ b/Game/src/Engine/NoteImageCacheManager.hpp @@ -25,11 +25,6 @@ class NoteImageCacheManager static void Release(); private: - size_t m_totalCount; - size_t m_totalNoteCount; - size_t m_totalHoldCount; - size_t m_totalTrailCount; - static NoteImageCacheManager* s_instance; std::unordered_map> m_noteTextures; diff --git a/Game/src/Engine/RhythmEngine.cpp b/Game/src/Engine/RhythmEngine.cpp index 3c8351dd..fc2327fc 100644 --- a/Game/src/Engine/RhythmEngine.cpp +++ b/Game/src/Engine/RhythmEngine.cpp @@ -1,8 +1,9 @@ -#include "RhythmEngine.hpp" +#include "RhythmEngine.hpp" #include #include #include #include +#include #include "../EnvironmentSetup.hpp" #include "Configuration.h" @@ -17,9 +18,6 @@ #include "Judgements/BeatBasedJudge.h" #include "Judgements/MsBasedJudge.h" -//#include -//#include - #define MAX_BUFFER_TXT_SIZE 256 struct ManiaKeyState @@ -224,14 +222,30 @@ bool RhythmEngine::Load(Chart *chart) m_rate = std::clamp(m_rate, 0.5, 2.0); } - m_title = chart->m_title; char buffer[MAX_BUFFER_TXT_SIZE]; - sprintf(buffer, "Lv.%d %s", chart->m_level, (const char *)chart->m_title.c_str()); - m_title = std::u8string(buffer, buffer + strlen(buffer)); + if (EnvironmentSetup::GetInt("SongType") == 1) { + m_title = chart->m_title; + std::string titleStr = std::string(chart->m_title.begin(), chart->m_title.end()); + std::snprintf(buffer, MAX_BUFFER_TXT_SIZE, "Lv.%d %s", chart->m_level, titleStr.c_str()); + } + else if (EnvironmentSetup::GetInt("SongType") == 2) { + m_title = chart->m_title; + std::string difnameStr = std::string(chart->m_difname.begin(), chart->m_difname.end()); + std::string titleStr = std::string(chart->m_title.begin(), chart->m_title.end()); + std::snprintf(buffer, MAX_BUFFER_TXT_SIZE, "[%s] %s", difnameStr.c_str(), titleStr.c_str()); + } + else { + m_title = chart->m_title; + std::string titleStr = std::string(chart->m_title.begin(), chart->m_title.end()); + std::snprintf(buffer, MAX_BUFFER_TXT_SIZE, "%d %s", chart->m_level, titleStr.c_str()); + } + + // Reset the u8string with the result of snprintf + m_title = std::u8string(buffer, buffer + std::strlen(buffer)); if (m_rate != 1.0) { memset(buffer, 0, MAX_BUFFER_TXT_SIZE); - sprintf(buffer, "[%.2fx] %s", m_rate, (const char *)m_title.c_str()); + sprintf(buffer, "[%.2fx] %s", m_rate, (const char*)m_title.c_str()); m_title = std::u8string(buffer, buffer + strlen(buffer)); } @@ -318,7 +332,8 @@ void RhythmEngine::SetKeys(Keys *keys) bool RhythmEngine::Start() { // no, use update event instead - m_currentAudioPosition -= 3000; + EnvironmentSetup::SetInt("NowPlaying", 1); + m_currentAudioPosition -= 5000; m_state = GameState::Playing; //m_startClock = std::chrono::system_clock::now(); return true; @@ -329,7 +344,14 @@ bool RhythmEngine::Stop() m_state = GameState::PosGame; GameAudioSampleCache::StopAll(); return true; - m_PlayTime = 0.0; +} + + +bool RhythmEngine::Fail() +{ + m_state = GameState::Fail; + GameAudioSampleCache::StopAll(); + return true; } bool RhythmEngine::Ready() @@ -345,6 +367,7 @@ void RhythmEngine::Update(double delta) // Since I'm coming from Roblox, and I had no idea how to Real-Time sync the audio // I decided to use this method again from Roblox project I did in past. double last = m_currentAudioPosition; + m_PlayTime += delta; m_currentAudioPosition += (delta * m_rate) * 1000; // check difference between last and current audio position @@ -354,13 +377,18 @@ void RhythmEngine::Update(double delta) // assert(false); // TODO: Handle this } - if (m_currentAudioPosition > m_audioLength + 2000) { // Avoid game ended too early - m_state = GameState::PosGame; + if (m_currentAudioPosition > m_audioLength + 3000) { // Avoid game ended too early GameAudioSampleCache::StopAll(); + m_state = GameState::PosGame; } - if (static_cast(m_currentAudioPosition) % 1000 == 0) { + static std::chrono::steady_clock::time_point lastUpdateTime = std::chrono::steady_clock::now(); + auto currentTime = std::chrono::steady_clock::now(); + auto lastUpdate = std::chrono::duration_cast(currentTime - lastUpdateTime); + + if (lastUpdate.count() >= 100) { m_noteImageIndex = (m_noteImageIndex + 1) % m_noteMaxImageIndex; + lastUpdateTime = currentTime; } UpdateVirtualResolution(); @@ -402,7 +430,6 @@ void RhythmEngine::Update(double delta) //auto currentTime = std::chrono::system_clock::now(); //auto elapsedTime = std::chrono::duration_cast(currentTime - m_startClock); //m_PlayTime = static_cast(elapsedTime.count() - 4); - m_PlayTime += delta; } void RhythmEngine::Render(double delta) @@ -410,7 +437,11 @@ void RhythmEngine::Render(double delta) if (m_state == GameState::NotGame || m_state == GameState::PosGame) return; - m_timingLineManager->Render(delta); + bool MeasureLine = EnvironmentSetup::GetInt("MeasureLine") == 1; + + if (MeasureLine) { + m_timingLineManager->Render(delta); + } for (auto &it : m_tracks) { it->Render(delta); @@ -419,13 +450,13 @@ void RhythmEngine::Render(double delta) void RhythmEngine::Input(double delta) { - if (m_state == GameState::NotGame || m_state == GameState::PosGame) + if (m_state == GameState::NotGame) return; } void RhythmEngine::OnKeyDown(const KeyState &state) { - if (m_state == GameState::NotGame || m_state == GameState::PosGame) + if (m_state == GameState::NotGame) return; if (state.key == Keys::F3) { @@ -449,7 +480,7 @@ void RhythmEngine::OnKeyDown(const KeyState &state) void RhythmEngine::OnKeyUp(const KeyState &state) { - if (m_state == GameState::NotGame || m_state == GameState::PosGame) + if (m_state == GameState::NotGame) return; if (!m_is_autoplay) { @@ -579,7 +610,7 @@ double RhythmEngine::GetGameFrame() const int RhythmEngine::GetPlayTime() const { - return static_cast(m_PlayTime - 3); + return static_cast(m_PlayTime - 5); } int RhythmEngine::GetNoteImageIndex() diff --git a/Game/src/Engine/RhythmEngine.hpp b/Game/src/Engine/RhythmEngine.hpp index c3f0e9ab..6a3e6783 100644 --- a/Game/src/Engine/RhythmEngine.hpp +++ b/Game/src/Engine/RhythmEngine.hpp @@ -16,6 +16,7 @@ enum class GameState { NotGame, PreGame, Playing, + Fail, PosGame }; @@ -36,6 +37,7 @@ class RhythmEngine bool Start(); bool Stop(); + bool Fail(); bool Ready(); void Update(double delta); diff --git a/Game/src/Engine/ScoreManager.cpp b/Game/src/Engine/ScoreManager.cpp index f63cac49..2f7a181b 100644 --- a/Game/src/Engine/ScoreManager.cpp +++ b/Game/src/Engine/ScoreManager.cpp @@ -3,6 +3,11 @@ #include #include "../EnvironmentSetup.hpp" +// Cool, Good, Bad, Miss (Divide by 10 from O2Jam) +const HealthDifficulty easy = {0.3f, 0.2f, -1.0f, -5.0f}; +const HealthDifficulty normal = {0.2f, 0.1f, -0.7f, -4.0f}; +const HealthDifficulty hard = {0.1f, 0.0f, -0.5f, -3.0f}; + ScoreManager::ScoreManager() { m_cool = 0; @@ -32,111 +37,92 @@ ScoreManager::~ScoreManager() { } -void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 and divided that by 10 +void ScoreManager::OnHit(NoteHitInfo info) { + bool isPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; + bool isFail = EnvironmentSetup::GetInt("Failed") == 1; + + if (!isPlaying) { + return; + } + + HealthDifficulty health; int difficulty = EnvironmentSetup::GetInt("Difficulty"); switch (difficulty) { - case 0: // Easy - switch (info.Result) { - case NoteResult::COOL: - AddLife(0.3f); - m_jamGauge += 4.0f; - m_score += 200 + (10 * m_jamCombo); - m_cool++; + case 0: + health = easy; break; - case NoteResult::GOOD: - AddLife(0.2f); - m_jamGauge += 2.0f; - m_score += 100 + (5 * m_jamCombo); - m_good++; + case 1: + health = normal; break; - case NoteResult::BAD: // IDK if this correct or not (from old code) - if (m_numOfPills > 0) { - m_numOfPills = std::clamp(m_numOfPills - 1, 0, 5); - m_score += 200 + (10 * m_jamCombo); - m_cool++; - info.Result = NoteResult::COOL; - } - else { - AddLife(-1.0f); - m_jamGauge = 0.0f; - m_coolCombo = 0; - m_score += 4; - m_combo = 0; - m_bad++; - } + case 2: + health = hard; break; - default: - AddLife(-5.0f); - m_combo = 0; - m_jamCombo = 0; - m_jamGauge = 0.0f; - if (m_life > 0) { - m_score -= 10; - } - m_miss++; - break; - } - break; + } - case 1: // Normal - switch (info.Result) { - case NoteResult::COOL: - AddLife(0.2f); - m_jamGauge += 4.0f; - m_score += 200 + (10 * m_jamCombo); - m_cool++; - break; - case NoteResult::GOOD: - AddLife(0.1f); - m_jamGauge += 2.0f; - m_score += 100 + (5 * m_jamCombo); - m_good++; - break; - case NoteResult::BAD: // IDK if this correct or not (from old code) - if (m_numOfPills > 0) { - m_numOfPills = std::clamp(m_numOfPills - 1, 0, 5); - m_score += 200 + (10 * m_jamCombo); - m_cool++; - info.Result = NoteResult::COOL; - } - else { - AddLife(-0.7f); - m_jamGauge = 0.0f; + HandleHit(info, health); + + m_combo = std::clamp(m_combo, 0, INT_MAX); + if (!isFail) { + m_jamCombo = std::clamp(m_jamCombo, 0, INT_MAX); + m_jamGauge = std::clamp(m_jamGauge, 0.0f, 100.0f); + } + m_score = std::clamp(m_score, 0, INT_MAX); + + if (info.Result == NoteResult::COOL) { + m_coolCombo += 1; + if (!isFail) { + if (m_coolCombo > 15) { m_coolCombo = 0; - m_score += 4; - m_combo = 0; - m_bad++; + m_numOfPills = std::clamp(m_numOfPills + 1, 0, 5); } - break; - default: - AddLife(-4.0f); - m_combo = 0; - m_jamCombo = 0; - m_jamGauge = 0.0f; - if (m_life > 0) { - m_score -= 10; + } + } else { + m_coolCombo = 0; + } + + if (info.Result != NoteResult::BAD && info.Result != NoteResult::MISS) { + m_combo += 1; + m_maxCombo = std::max(m_maxCombo, m_combo); + } + + if (!isFail) { + if (m_jamGauge >= kMaxJamGauge) { + m_jamGauge = 0; + m_jamCombo += 1; + m_maxJamCombo = std::max(m_maxJamCombo, m_jamCombo); + + if (m_jamCallback) { + m_jamCallback(m_jamCombo); } - m_miss++; - break; } - break; + } + + if (m_callback) { + if (info.Result == NoteResult::MISS && m_life == 0) { + return; + } + + m_callback(info); + } +} - case 2: // Hard - switch (info.Result) { +void ScoreManager::HandleHit(NoteHitInfo& info, const HealthDifficulty& health) +{ + switch (info.Result) { case NoteResult::COOL: - AddLife(0.1f); + AddLife(health.cool); m_jamGauge += 4.0f; m_score += 200 + (10 * m_jamCombo); m_cool++; break; case NoteResult::GOOD: - AddLife(0.0f); + AddLife(health.good); m_jamGauge += 2.0f; m_score += 100 + (5 * m_jamCombo); m_good++; break; - case NoteResult::BAD: // IDK if this correct or not (from old code) + case NoteResult::BAD: if (m_numOfPills > 0) { m_numOfPills = std::clamp(m_numOfPills - 1, 0, 5); m_score += 200 + (10 * m_jamCombo); @@ -144,7 +130,7 @@ void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 a info.Result = NoteResult::COOL; } else { - AddLife(-0.5f); + AddLife(health.bad); m_jamGauge = 0.0f; m_coolCombo = 0; m_score += 4; @@ -153,7 +139,7 @@ void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 a } break; default: - AddLife(-3.0f); + AddLife(health.miss); m_combo = 0; m_jamCombo = 0; m_jamGauge = 0.0f; @@ -162,52 +148,22 @@ void ScoreManager::OnHit(NoteHitInfo info) // Fuck it just leave it max HP 100 a } m_miss++; break; - } - break; - } - - m_combo = std::clamp(m_combo, 0, INT_MAX); - m_jamCombo = std::clamp(m_jamCombo, 0, INT_MAX); - m_jamGauge = std::clamp(m_jamGauge, 0.0f, 100.0f); - m_score = std::clamp(m_score, 0, INT_MAX); - - if (info.Result == NoteResult::COOL) { - m_coolCombo += 1; - - if (m_coolCombo > 15) { - m_coolCombo = 0; - m_numOfPills = std::clamp(m_numOfPills + 1, 0, 5); - } - } else { - m_coolCombo = 0; - } - - if (info.Result != NoteResult::BAD && info.Result != NoteResult::MISS) { - m_combo += 1; - m_maxCombo = std::max(m_maxCombo, m_combo); } +} - if (m_jamGauge >= kMaxJamGauge) { - m_jamGauge = 0; - m_jamCombo += 1; - m_maxJamCombo = std::max(m_maxJamCombo, m_jamCombo); +void ScoreManager::OnLongNoteHold(HoldResult result) +{ + bool isPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; + bool isFail = EnvironmentSetup::GetInt("Failed") == 1; - if (m_jamCallback) { - m_jamCallback(m_jamCombo); - } + if (!isPlaying) { + return; } - if (m_callback) { - if (info.Result == NoteResult::MISS && m_life == 0) { - return; - } - - m_callback(info); + if (isFail) { + return; } -} -void ScoreManager::OnLongNoteHold(HoldResult result) -{ switch (result) { case HoldResult::HoldBreak: { @@ -266,8 +222,11 @@ std::tuple ScoreManager:: void ScoreManager::AddLife(float sz) { - if (m_life > 0) { - m_life += sz; - m_life = std::clamp(m_life, 0.0f, 100.0f); + bool isFail = EnvironmentSetup::GetInt("Failed") == 1; + if (!isFail) { + if (m_life > 0) { + m_life += sz; + m_life = std::clamp(m_life, 0.0f, 100.0f); + } } } diff --git a/Game/src/Engine/ScoreManager.hpp b/Game/src/Engine/ScoreManager.hpp index d15c37d4..9c29e053 100644 --- a/Game/src/Engine/ScoreManager.hpp +++ b/Game/src/Engine/ScoreManager.hpp @@ -5,6 +5,13 @@ constexpr float kMaxJamGauge = 100; constexpr float kMaxLife = 100; +struct HealthDifficulty { + float cool; + float good; + float bad; + float miss; +}; + struct NoteHitInfo { NoteResult Result; @@ -21,6 +28,7 @@ class ScoreManager ~ScoreManager(); void OnHit(NoteHitInfo info); + void HandleHit(NoteHitInfo& info, const HealthDifficulty& health); void OnLongNoteHold(HoldResult result); void ListenHit(std::function); void ListenJam(std::function); diff --git a/Game/src/Engine/SkinManager.cpp b/Game/src/Engine/SkinManager.cpp index c1d49b60..4eb8750b 100644 --- a/Game/src/Engine/SkinManager.cpp +++ b/Game/src/Engine/SkinManager.cpp @@ -1,4 +1,5 @@ #include "SkinManager.hpp" +#include "../EnvironmentSetup.hpp" SkinManager *SkinManager::m_instance = nullptr; @@ -225,8 +226,20 @@ SkinManager::~SkinManager() void SkinManager::TryLoadGroup(SkinGroup group) { - m_skinConfigs[group] = std::make_unique( - GetPath() / m_expected_directory[group] / m_expected_skin_config[group], m_keyCount); + std::filesystem::path configPath; + + if (group == SkinGroup::Notes && EnvironmentSetup::GetInt("NoteSkin") != 2) { + auto path = std::filesystem::current_path() / "Resources"; + if (EnvironmentSetup::GetInt("NoteSkin") == 1) { + configPath = path / "Notes" / "Circle" / "Notes.ini"; + } else { + configPath = path / "Notes" / "Square" / "Notes.ini"; + } + } else { + configPath = GetPath() / m_expected_directory[group] / m_expected_skin_config[group]; + } + + m_skinConfigs[group] = std::make_unique(configPath, m_keyCount); } void SkinManager::Update(double delta) diff --git a/Game/src/Engine/TimingLine.cpp b/Game/src/Engine/TimingLine.cpp index 1a8894ba..866975c2 100644 --- a/Game/src/Engine/TimingLine.cpp +++ b/Game/src/Engine/TimingLine.cpp @@ -1,6 +1,7 @@ #include "TimingLine.hpp" #include "RhythmEngine.hpp" #include "Texture/ResizableImage.h" +#include "../EnvironmentSetup.hpp" namespace { double CalculateLinePosition(double trackOffset, double offset, double noteSpeed, bool upscroll = false) @@ -62,15 +63,26 @@ void TimingLine::Render(double delta) double min = 0, max = hitPos; double pos_y = min + (max - min) * alpha; + int halfNoteSize; + + if (EnvironmentSetup::GetInt("MeasureLineType") == 1) { + halfNoteSize = static_cast(EnvironmentSetup::GetInt("NoteSize") / 2); + } + else { + halfNoteSize = 0; + } + m_line->Size = UDim2::fromOffset(m_imageSize, 1); - m_line->Position = UDim2::fromOffset(m_imagePos, pos_y); //+ start.Lerp(end, alpha); + m_line->Position = UDim2::fromOffset(m_imagePos, pos_y - halfNoteSize); //+ start.Lerp(end, alpha); if (m_line->Position.Y.Offset >= 0 && m_line->Position.Y.Offset < hitPos + 10) { + m_line->TintColor = { 0.7f, 0.7f, 0.7f }; m_line->Draw(&playRect); } } void TimingLine::Release() { + EnvironmentSetup::SetInt("HalfNoteSize", 0); delete m_line; } diff --git a/Game/src/EnvironmentSetup.cpp b/Game/src/EnvironmentSetup.cpp index 421ac62b..7aa320d5 100644 --- a/Game/src/EnvironmentSetup.cpp +++ b/Game/src/EnvironmentSetup.cpp @@ -1,15 +1,18 @@ #include "EnvironmentSetup.hpp" #include +#include namespace { std::unordered_map m_stores; - std::unordered_map m_storesPtr; + std::unordered_map m_storesPtr; std::unordered_map m_paths; std::unordered_map m_ints; + std::mutex m_mutex; } // namespace void EnvironmentSetup::OnExitCheck() { + std::lock_guard lock(m_mutex); m_stores.clear(); m_paths.clear(); m_ints.clear(); @@ -17,11 +20,13 @@ void EnvironmentSetup::OnExitCheck() void EnvironmentSetup::Set(std::string key, std::string value) { + std::lock_guard lock(m_mutex); m_stores[key] = std::move(value); } std::string EnvironmentSetup::Get(std::string key) { + std::lock_guard lock(m_mutex); auto it = m_stores.find(key); if (it != m_stores.end()) { return it->second; @@ -31,11 +36,13 @@ std::string EnvironmentSetup::Get(std::string key) void EnvironmentSetup::SetObj(std::string key, void* ptr) { + std::lock_guard lock(m_mutex); m_storesPtr[key] = ptr; } void* EnvironmentSetup::GetObj(std::string key) { + std::lock_guard lock(m_mutex); auto it = m_storesPtr.find(key); if (it != m_storesPtr.end()) { return it->second; @@ -45,11 +52,13 @@ void* EnvironmentSetup::GetObj(std::string key) void EnvironmentSetup::SetPath(std::string key, std::filesystem::path path) { + std::lock_guard lock(m_mutex); m_paths[key] = std::move(path); } std::filesystem::path EnvironmentSetup::GetPath(std::string key) { + std::lock_guard lock(m_mutex); auto it = m_paths.find(key); if (it != m_paths.end()) { return it->second; @@ -59,14 +68,16 @@ std::filesystem::path EnvironmentSetup::GetPath(std::string key) void EnvironmentSetup::SetInt(std::string key, int value) { + std::lock_guard lock(m_mutex); m_ints[key] = value; } int EnvironmentSetup::GetInt(std::string key) { + std::lock_guard lock(m_mutex); auto it = m_ints.find(key); if (it != m_ints.end()) { return it->second; } return 0; -} \ No newline at end of file +} diff --git a/Game/src/Resources/DefaultConfiguration.h b/Game/src/Resources/DefaultConfiguration.h index 0fbd3b2c..260f7500 100644 --- a/Game/src/Resources/DefaultConfiguration.h +++ b/Game/src/Resources/DefaultConfiguration.h @@ -7,10 +7,14 @@ std::string defaultConfiguration = "[game]\n" "framelimit = 240\n" // Default 144 but i set this for more reasonable "audiooffset = 0\n" "audiovolume = 100\n" - "autosound = 1\n" + "autosound = 0\n" "resolution = 1280x720\n" // Fix for most monitor "renderer = 0\n" - "guideline = 1\n\n" + "guideline = 1\n" + "background = 0\n" + "measureline = 1\n" + "measurelinetype = 0\n" + "lnbodyontop = 0\n\n" "[keymapping]\n" "lane1 = A\n" @@ -42,4 +46,8 @@ std::string defaultConfiguration = "[game]\n" "folder =\n" "[gameplay]\n" - "notespeed = 225\n"; \ No newline at end of file + "notespeed = 250\n" + "difficulty = \n" + "modifiers =\n" + "arena =\n"; + diff --git a/Game/src/Resources/GameResources.cpp b/Game/src/Resources/GameResources.cpp index 01c043b9..a9b4f0b0 100644 --- a/Game/src/Resources/GameResources.cpp +++ b/Game/src/Resources/GameResources.cpp @@ -23,6 +23,7 @@ #endif #include "../Engine/SkinConfig.hpp" +#include "../EnvironmentSetup.hpp" #pragma warning(disable : 26451) @@ -393,9 +394,20 @@ namespace GameNoteResource { } bool IsVulkan = Renderer::GetInstance()->IsVulkan(); + std::filesystem::path skinNotePath; - auto skinPath = SkinManager::GetInstance()->GetPath(); - auto skinNotePath = skinPath / "Notes"; + if (EnvironmentSetup::GetInt("NoteSkin") == 1) { + auto path = std::filesystem::current_path() / "Resources"; + skinNotePath = path / "Notes" / "Circle"; + } + else if (EnvironmentSetup::GetInt("NoteSkin") == 2) { + auto skinPath = SkinManager::GetInstance()->GetPath(); + skinNotePath = skinPath / "Notes"; + } + else { + auto path = std::filesystem::current_path() / "Resources"; + skinNotePath = path / "Notes" / "Square"; + } auto manager = SkinManager::GetInstance(); diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 3a3b4604..e5b79ff4 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -27,6 +27,7 @@ #include "../GameScenes.h" #define AUTOPLAY_TEXT u8"Game currently on autoplay!" +#define GAMEINFO_TEXT u8"O2Clone Build Date: " __DATE__ " " __TIME__ struct MissInfo { @@ -48,6 +49,8 @@ GameplayScene::GameplayScene() : Scene::Scene() m_keyState = {}; m_game = nullptr; m_drawJam = false; + m_counter = 0.0; + lifeFillDuration = 0.0; } void GameplayScene::Update(double delta) @@ -77,30 +80,43 @@ void GameplayScene::Update(double delta) if (m_game->GetState() == GameState::PosGame && !m_ended) { m_counter += delta; - m_minuteNum->DrawNumber(0); - m_secondNum->DrawNumber(0); - - if (m_counter > 10.0) { + m_drawExitButton = false; + m_doExit = false; + if (m_counter > 5.0) { m_ended = true; + m_counter = 0.0; // Reset SceneManager::DisplayFade(100, [] { SceneManager::ChangeScene(GameScene::RESULT); }); } } + if (m_game->GetState() == GameState::Fail && !m_ended) { + m_ended = true; + m_counter = 0.0; // Reset + SceneManager::DisplayFade(100, [] { + SceneManager::ChangeScene(GameScene::RESULT); + }); + } + int difficulty = EnvironmentSetup::GetInt("Difficulty"); + float health = m_game->GetScoreManager()->GetLife(); if (difficulty >= 1 && m_starting) { - float health = m_game->GetScoreManager()->GetLife(); - if (health <= 0) { - m_game->Stop(); + m_game->Fail(); + EnvironmentSetup::SetInt("NowPlaying", 0); + EnvironmentSetup::SetInt("Failed", 1); + } + } + else { + if (health <= 0) { EnvironmentSetup::SetInt("Failed", 1); - } + } } if (m_doExit && !m_ended) { m_ended = true; - + auto scores = m_game->GetScoreManager()->GetScore(); if (std::get<1>(scores) != 0 || std::get<2>(scores) != 0 || std::get<3>(scores) != 0 || std::get<4>(scores) != 0) { @@ -135,17 +151,14 @@ void GameplayScene::Render(double delta) int arena = EnvironmentSetup::GetInt("Arena"); - bool useSongBG = EnvironmentSetup::GetInt("Song BG") == 1; - bool blackBG = EnvironmentSetup::GetInt("Black BG") == 1; - - if (useSongBG) { + if (EnvironmentSetup::GetInt("Background") == 1) { auto songBG = (Texture2D*)EnvironmentSetup::GetObj("SongBackground"); if (songBG) { songBG->TintColor = Color3::FromRGB(128, 128, 128); songBG->Draw(); } } - else if (blackBG) { + else if (EnvironmentSetup::GetInt("Background") == 2) { // Do nothing } else { @@ -273,10 +286,22 @@ void GameplayScene::Render(double delta) if (m_drawCombo && std::get<7>(scores) > 0) { // This should be O2Jam Replication const double positionStart = 30.0; - const double decrement = 6.0; - double animationSpeed = 60.0; + const double step = 6.0; + double animationSpeed = 90.0; + double maxSpeed = animationSpeed; + + if (m_comboTimer > 0.5) { + animationSpeed += 15.0 * delta; + } + else { + animationSpeed -= 15.0 * delta; + } - double targetposition = positionStart - decrement * m_comboTimer * animationSpeed; + if (animationSpeed > 90.0) { + animationSpeed = maxSpeed; + } + + double targetposition = positionStart - step * m_comboTimer * animationSpeed; double currentposition = (targetposition > 0.0) ? targetposition : 0.0; m_comboLogo->Position2 = UDim2::fromOffset(0, currentposition / 3.0); @@ -297,13 +322,13 @@ void GameplayScene::Render(double delta) const double positionStart = 5.0; double animationSpeed = 60.0; - double targetposition = positionStart - m_lnTimer * animationSpeed; - double currentposition = (targetposition > 0.0) ? targetposition : 0.0; + double targetPosition = positionStart - m_lnTimer * animationSpeed; + double currentPosition = (targetPosition > 0.0) ? targetPosition : 0.0; - m_lnLogo->Position2 = UDim2::fromOffset(0, currentposition); + m_lnLogo->Position2 = UDim2::fromOffset(0, currentPosition); m_lnLogo->Draw(delta); - m_lnComboNum->Position2 = UDim2::fromOffset(0, currentposition); + m_lnComboNum->Position2 = UDim2::fromOffset(0, currentPosition); m_lnComboNum->DrawNumber(std::get<9>(scores)); m_lnTimer += delta; @@ -314,7 +339,6 @@ void GameplayScene::Render(double delta) } } - float gaugeVal = (float)m_game->GetScoreManager()->GetJamGauge() / kMaxJamGauge; if (gaugeVal > 0) { m_jamGauge->CalculateSize(); @@ -363,18 +387,41 @@ void GameplayScene::Render(double delta) m_waveGage->Draw(&rc); } - int PlayTime = std::clamp(m_game->GetPlayTime(), 0, INT_MAX); - int currentMinutes = PlayTime / 60; - int currentSeconds = PlayTime % 60; + // Fix if playtime sometimes slighly double draw + int PlayTime = 0; + int currentMinutes = 0 / 60; + int currentSeconds = 0 % 60; + + bool isPlaying = EnvironmentSetup::GetInt("NowPlaying") == 1; + if (isPlaying) // get timer if on play state + { + PlayTime = std::clamp(m_game->GetPlayTime(), 0, INT_MAX); + currentMinutes = PlayTime / 60; + currentSeconds = PlayTime % 60; + } + else { // get timer but this while game ended or failed + int lastPlayTime = PlayTime; + currentMinutes = lastPlayTime / 60; + currentSeconds = lastPlayTime % 60; + } m_minuteNum->DrawNumber(currentMinutes); m_secondNum->DrawNumber(currentSeconds); for (int i = 0; i < 7; i++) { - m_hitEffect[i]->Draw(delta); + if (EnvironmentSetup::GetInt("NowPlaying") == 1) { + m_hitEffect[i]->Draw(delta); - if (m_drawHold[i]) { - m_holdEffect[i]->Draw(delta); + if (m_drawHold[i]) { + m_holdEffect[i]->Draw(delta); + } + } + else { + m_hitEffect[i]->LastIndex(); + + if (m_drawHold[i]) { + m_holdEffect[i]->LastIndex(); + } } } @@ -384,6 +431,9 @@ void GameplayScene::Render(double delta) m_title->Draw(m_game->GetTitle()); + m_gameInfo->Position = m_gameInfoPos; + m_gameInfo->Draw(GAMEINFO_TEXT); + if (m_autoPlay) { m_autoText->Position = m_autoTextPos; m_autoText->Draw(AUTOPLAY_TEXT); @@ -498,9 +548,12 @@ bool GameplayScene::Attach() m_autoText = std::make_unique(13); m_autoTextSize = m_autoText->CalculateSize(AUTOPLAY_TEXT); - m_autoTextPos = UDim2::fromOffset(GameWindow::GetInstance()->GetBufferWidth(), 50); + m_gameInfo = std::make_unique(8); + m_gameInfoSize = m_gameInfo->CalculateSize(GAMEINFO_TEXT); + m_gameInfoPos = UDim2::fromOffset(/*GameWindow::GetInstance()->GetBufferWidth()*/ 0, GameWindow::GetInstance()->GetBufferHeight() - 10); + m_PlayBG = std::make_unique(arenaPath / ("PlayingBG.png")); auto PlayBGPos = manager->Arena_GetPosition("PlayingBG"); // arena_conf.GetPosition("PlayingBG"); m_PlayBG->Position = UDim2::fromOffset(PlayBGPos[0].X, PlayBGPos[0].Y); diff --git a/Game/src/Scenes/GameplayScene.h b/Game/src/Scenes/GameplayScene.h index d4d20bb3..077de1af 100644 --- a/Game/src/Scenes/GameplayScene.h +++ b/Game/src/Scenes/GameplayScene.h @@ -72,6 +72,7 @@ class GameplayScene : public Scene std::unique_ptr m_title; std::unique_ptr m_autoText; + std::unique_ptr m_gameInfo; std::unique_ptr m_laneHideImage; @@ -114,4 +115,8 @@ class GameplayScene : public Scene bool m_autoPlay; int m_autoTextSize; UDim2 m_autoTextPos; + + /* game info */ + int m_gameInfoSize; + UDim2 m_gameInfoPos; }; \ No newline at end of file diff --git a/Game/src/Scenes/LoadingScene.cpp b/Game/src/Scenes/LoadingScene.cpp index 217fc103..96cfda81 100644 --- a/Game/src/Scenes/LoadingScene.cpp +++ b/Game/src/Scenes/LoadingScene.cpp @@ -18,7 +18,6 @@ #include "../GameScenes.h" #include "../Resources/GameDatabase.h" -// I don't know if this new changes causing memleak or not because i can't tell due my hardware limit LoadingScene::LoadingScene() { m_background = nullptr; @@ -56,8 +55,13 @@ void LoadingScene::Update(double delta) EnvironmentSetup::SetInt("Autoplay", autoplay); EnvironmentSetup::Set("SongRate", rate); - EnvironmentSetup::SetInt("Song BG", 1); - EnvironmentSetup::SetInt("Difficulty", 2); // Hard difficulty it's fun (fucked) + + if (EnvironmentSetup::GetInt("FileOpen") == 1) { + LoadModifiers(); + } + else { + EnvironmentSetup::SetInt("Song BG", 1); + } } const char *bmsfile[] = { ".bms", ".bme", ".bml", ".bmsc" }; @@ -74,6 +78,7 @@ void LoadingScene::Update(double delta) } chart = new Chart(beatmap); + EnvironmentSetup::SetInt("SongType", 0); } else if (file.extension() == ojnfile) { O2::OJN o2jamFile; o2jamFile.Load(file); @@ -87,8 +92,9 @@ void LoadingScene::Update(double delta) } chart = new Chart(o2jamFile, diffIndex); - + EnvironmentSetup::SetInt("SongType", 1); IsO2Jam = true; + } else { Osu::Beatmap beatmap(file); @@ -99,6 +105,7 @@ void LoadingScene::Update(double delta) } chart = new Chart(beatmap); + EnvironmentSetup::SetInt("SongType", 2); } EnvironmentSetup::SetObj("SONG", chart); @@ -173,6 +180,33 @@ void LoadingScene::Update(double delta) } } +void LoadingScene::LoadModifiers() // For File Opened +{ + std::string difficultyValue = Configuration::Load("Gameplay", "Difficulty"); + int setDifficulty = std::stoi(difficultyValue); + switch (setDifficulty) { + case 0: // EZ + EnvironmentSetup::SetInt("Difficulty", 0); + break; + case 1: // NM + EnvironmentSetup::SetInt("Difficulty", 1); + break; + case 2: // HD + EnvironmentSetup::SetInt("Difficulty", 2); + break; + } + + std::string selectedMods = Configuration::Load("Gameplay", "Modifiers"); + std::istringstream iss(selectedMods); + std::string mod; + while (std::getline(iss, mod, ',')) { + EnvironmentSetup::SetInt(mod, 1); + } + + std::string arenaValue = Configuration::Load("Gameplay", "Arena"); + EnvironmentSetup::SetInt("Arena", std::stoi(arenaValue)); +} + void LoadingScene::Render(double delta) { if (m_background && is_ready) { diff --git a/Game/src/Scenes/LoadingScene.h b/Game/src/Scenes/LoadingScene.h index c3ad174c..4fd27efd 100644 --- a/Game/src/Scenes/LoadingScene.h +++ b/Game/src/Scenes/LoadingScene.h @@ -10,6 +10,7 @@ class LoadingScene : public Scene ~LoadingScene(); void Update(double delta) override; + void LoadModifiers(); void Render(double delta) override; bool Attach() override; diff --git a/Game/src/Scenes/MainMenu.cpp b/Game/src/Scenes/MainMenu.cpp index 5d618869..823f8cdd 100644 --- a/Game/src/Scenes/MainMenu.cpp +++ b/Game/src/Scenes/MainMenu.cpp @@ -21,138 +21,137 @@ void MainMenu::Update(double delta) { } -//void MainMenu::Render(double delta) -//{ -// ImguiUtil::NewFrame(); -// -// auto window = GameWindow::GetInstance(); -// ImGui::SetNextWindowPos(ImVec2(0, 0)); -// -// auto windowNextSz = ImVec2((float)window->GetBufferWidth(), (float)window->GetBufferHeight()); -// ImGui::SetNextWindowSize(MathUtil::ScaleVec2(windowNextSz)); -// ImGui::SetWindowPos(ImVec2(0, 0)); -// -// if (m_background) { -// m_background->Draw(); -// } -// -// auto flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBringToFrontOnFocus; -// -// int nextScene = -1; -// if (ImGui::Begin("###BEGIN", nullptr, flags)) { -// if (ImGui::BeginMenuBar()) { -// std::string title = std::string(O2GAME_TITLE) + " " + std::string(O2GAME_VERSION); -// ImGui::Text("%s", title.c_str()); -// -// std::string text = "No Account!"; -// auto textWidth = ImGui::CalcTextSize(text.c_str()).x; -// -// ImGui::SameLine(MathUtil::ScaleVec2(ImVec2(windowNextSz.x, 0)).x - textWidth - 15); -// ImGui::Text(text.c_str()); -// -// ImGui::EndMenuBar(); -// } -// -// { -// ImFont *font = FontResources::GetButtonFont(); -// ImGui::PushFont(font); -// ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); -// auto ButtonColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); -// ButtonColor.w = 0.25f; -// ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ButtonColor); -// ButtonColor.w = 0.15f; -// ImGui::PushStyleColor(ImGuiCol_ButtonActive, ButtonColor); -// ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); -// -// auto ButtonSize = MathUtil::ScaleVec2(window->GetBufferWidth(), 40); -// -// for (int i = 0; i < 5; i++) { -// ImGui::NewLine(); -// } -// -// ImGui::Spacing(); -// if (ImGui::Button("Single player", ButtonSize)) { -// nextScene = 0; -// } -// -// if (ImGui::Button("Play", ButtonSize)) { -// nextScene = 0; -// } -// -// ImGui::Spacing(); -// if (ImGui::Button("Multi player", ButtonSize)) { -// MsgBox::Show("Multiplayer", "Error", "Multiplayer is not implemented yet!"); -// } -// -// ImGui::NewLine(); -// ImGui::Spacing(); -// if (ImGui::Button("Editor", ButtonSize)) { -// nextScene = 2; -// } -// -// ImGui::NewLine(); -// ImGui::Spacing(); -// if (ImGui::Button("Options", ButtonSize)) { -// nextScene = 3; -// } -// -// ImGui::Spacing(); -// if (ImGui::Button("Quit", ButtonSize)) { -// nextScene = 4; -// } -// -// ImGui::PopStyleVar(); -// ImGui::PopStyleColor(3); -// ImGui::PopFont(); -// } -// -// ImGui::End(); -// } -// -// if (nextScene != -1) { -// switch (nextScene) { -// case 0: -// { -// SceneManager::DisplayFade(100, [this]() { -// SceneManager::ChangeScene(GameScene::SONGSELECT); -// }); -// break; -// } -// -// case 1: -// { -// break; -// } -// -// case 2: -// { -// SceneManager::DisplayFade(100, [this]() { -// SceneManager::ChangeScene(GameScene::EDITOR); -// }); -// break; -// } -// -// case 3: -// { -// SceneManager::OverlayShow(GameOverlay::SETTINGS); -// break; -// } -// -// case 4: -// { -// SDL_Event e = {}; -// e.type = SDL_QUIT; -// -// SDL_PushEvent(&e); -// break; -// } -// } -// } -//} - void MainMenu::Render(double delta) { - SceneManager::ChangeScene(GameScene::SONGSELECT); + ImguiUtil::NewFrame(); + + auto window = GameWindow::GetInstance(); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + + auto windowNextSz = ImVec2((float)window->GetBufferWidth(), (float)window->GetBufferHeight()); + ImGui::SetNextWindowSize(MathUtil::ScaleVec2(windowNextSz)); + ImGui::SetWindowPos(ImVec2(0, 0)); + + if (m_background) { + m_background->Draw(); + } + + auto flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBringToFrontOnFocus; + + int nextScene = -1; + if (ImGui::Begin("###BEGIN", nullptr, flags)) { + if (ImGui::BeginMenuBar()) { + std::string title = std::string(O2GAME_TITLE) + " " + std::string(O2GAME_VERSION); + ImGui::Text("%s", title.c_str()); + + std::string text = "Main Menu"; + auto textWidth = ImGui::CalcTextSize(text.c_str()).x; + + ImGui::SameLine(MathUtil::ScaleVec2(ImVec2(windowNextSz.x, 0)).x - textWidth - 15); + ImGui::Text(text.c_str()); + + ImGui::EndMenuBar(); + } + + { + ImFont* font = FontResources::GetButtonFont(); + ImGui::PushFont(font); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f)); + auto ButtonColor = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); + ButtonColor.w = 0.25f; + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ButtonColor); + ButtonColor.w = 0.15f; + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ButtonColor); + ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 0.5f)); + + auto ButtonSize = MathUtil::ScaleVec2(window->GetBufferWidth(), 40); + + for (int i = 0; i < 5; i++) { + ImGui::NewLine(); + } + + ImGui::NewLine(); + ImGui::Spacing(); + //if (ImGui::Button("Single player", ButtonSize)) { + // nextScene = 0; + //} + + ImGui::NewLine(); + ImGui::Spacing(); + + if (ImGui::Button("Play", ButtonSize)) { + nextScene = 0; + } + + // ImGui::Spacing(); + // if (ImGui::Button("Multi player", ButtonSize)) { + // MsgBox::Show("Multiplayer", "Error", "Multiplayer is not implemented yet!"); + //} + + //ImGui::NewLine(); + //ImGui::Spacing(); + //if (ImGui::Button("Editor", ButtonSize)) { + // nextScene = 2; + //} + + ImGui::NewLine(); + ImGui::Spacing(); + if (ImGui::Button("Options", ButtonSize)) { + nextScene = 3; + } + + ImGui::Spacing(); + if (ImGui::Button("Quit", ButtonSize)) { + nextScene = 4; + } + + ImGui::PopStyleVar(); + ImGui::PopStyleColor(3); + ImGui::PopFont(); + } + + ImGui::End(); + } + + if (nextScene != -1) { + switch (nextScene) { + case 0: + { + SceneManager::DisplayFade(100, [this]() { + SceneManager::ChangeScene(GameScene::SONGSELECT); + }); + break; + } + + case 1: + { + break; + } + + case 2: + { + SceneManager::DisplayFade(100, [this]() { + SceneManager::ChangeScene(GameScene::EDITOR); + }); + break; + } + + case 3: + { + SceneManager::OverlayShow(GameOverlay::SETTINGS); + break; + } + + case 4: + { + SDL_Event e = {}; + e.type = SDL_QUIT; + + SDL_PushEvent(&e); + break; + } + } + } } bool MainMenu::Attach() diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index cc501e8f..15d7ba8b 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -1,4 +1,4 @@ -#include "Settings.h" +#include "Settings.h" #include #include #include @@ -35,19 +35,54 @@ static std::map Graphics = { { 1, "Vulkan" }, #if _WIN32 { 2, "DirectX-9" }, - { 3, "DirectX-11" }, - { 4, "DirectX-12" }, + { 3, "DirectX-12" }, #endif #if __APPLE__ - { 5, "Metal" }, + { 4, "Metal" }, #endif }; -static std::array LongNote = { "None", "Short", "Normal", "Long" }; -static std::array m_fps = { "30", "60", "75", "120", "144", "165", "180", "240", "360", "480", "600", "800", "1000", "Unlimited" }; +//#if _WIN32 +//{ 2, "DirectX-9" }, +//{ 3, "DirectX-11" }, +//{ 4, "DirectX-12" }, +//#endif +//#if __APPLE__ +//{ 5, "Metal" }, +//#endif +//}; +static std::array LongNote = { "None", "Short", "Normal", "Long" }; +//static std::array m_fps = { "30", "60", "75", "120", "144", "165", "180", "240", "360", "480", "600", "800", "1000", "Unlimited" }; +static std::array SelectedBackground = { "Arena", "Song", "Disable" }; +static std::array NoteSkin = { "Square", "Circle", "Custom" }; static std::vector m_resolutions = {}; +int currentFPSIndex = 0; +int customFPS = 0; + +namespace { + int GetScreenRefreshRate() { + SDL_DisplayMode displayMode; + if (SDL_GetCurrentDisplayMode(0, &displayMode) != 0) { + return 60; // Default to 60 if SDL can't catch refresh rate (pc issues) + } + return displayMode.refresh_rate; + } + + std::vector GetFpsOptions() { + int refreshRate = GetScreenRefreshRate(); + std::vector multipliers = { 1, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 20 }; + std::vector fpsOptions; + + for (int multiplier : multipliers) { + fpsOptions.push_back(std::to_string(refreshRate * multiplier)); + } + fpsOptions.push_back("Unlimited"); + return fpsOptions; + } +} + void SettingsOverlay::Render(double delta) { auto &io = ImGui::GetIO(); @@ -187,7 +222,8 @@ void SettingsOverlay::Render(double delta) int nextGraphicsIndex = -1; try { GraphicsIndex = std::stoi(Configuration::Load("Game", "Renderer").c_str()); - } catch (const std::invalid_argument &) { + } + catch (const std::invalid_argument&) { } ImGui::Text("Graphics"); @@ -243,25 +279,34 @@ void SettingsOverlay::Render(double delta) ImGui::NewLine(); + std::vector fpsOptions = GetFpsOptions(); ImGui::Text("FPS"); - ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Warning: setting unlimited FPS can cause PC to unstable!"); - if (ImGui::BeginCombo("###ComboBox2", m_fps[currentFPSIndex].c_str())) { - for (int i = 0; i < m_fps.size(); i++) { + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Warning: setting unlimited FPS can cause PC to become unstable!"); + if (ImGui::BeginCombo("###ComboBox2", fpsOptions[currentFPSIndex].c_str())) { + for (int i = 0; i < fpsOptions.size(); i++) { bool isSelected = (currentFPSIndex == i); - if (ImGui::Selectable(m_fps[i].c_str(), &isSelected)) { + if (ImGui::Selectable(fpsOptions[i].c_str(), &isSelected)) { currentFPSIndex = i; + if (fpsOptions[i] == "Unlimited") { + customFPS = 9999; + Configuration::Set("Game", "FrameLimit", std::to_string(customFPS)); + } + else { + customFPS = 0; + Configuration::Set("Game", "FrameLimit", fpsOptions[i]); + } } if (isSelected) { ImGui::SetItemDefaultFocus(); } } - ImGui::EndCombo(); } ImGui::EndTabItem(); + } if (ImGui::BeginTabItem("Audio")) { @@ -285,10 +330,10 @@ void SettingsOverlay::Render(double delta) ImGui::Text("Guide Line Length"); for (int i = (int)LongNote.size() - 1; i >= 0; i--) { - bool is_combo_selected = currentGuideLineIndex == i; + bool selected = currentGuideLineIndex == i; ImGui::PushItemWidth(50); - if (ImGui::Checkbox(("###ComboCheck" + std::to_string(i)).c_str(), &is_combo_selected)) { + if (ImGui::Checkbox(("###ComboCheck" + std::to_string(i)).c_str(), &selected)) { currentGuideLineIndex = i; } @@ -303,18 +348,40 @@ void SettingsOverlay::Render(double delta) } } + ImGui::NewLine(); ImGui::NewLine(); ImGui::NewLine(); ImGui::Text("Gameplay-Related Configuration"); - ImGui::Checkbox("Long Note Lighting###SetCheckbox1", &LongNoteLighting); + + ImGui::Checkbox("Use New Measure Line###SetCheckbox1", &MeasureLineType); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("When Long note on hold, change the lighting brightness to 100%% else 90%% brightness"); + ImGui::SetTooltip("Measure line position in the middle of the note; otherwise, it will be at the bottom of the note"); + } + if (MeasureLineType) { + EnvironmentSetup::SetInt("MeasureLineType", 1); + } + else { + EnvironmentSetup::SetInt("MeasureLineType", 0); + } + + ImGui::Checkbox("Disable Measure Line###SetCheckbox2", &MeasureLine); + if (MeasureLine) { + EnvironmentSetup::SetInt("MeasureLine", 0); + } + else { + EnvironmentSetup::SetInt("MeasureLine", 1); } - ImGui::Checkbox("Long Note Head Position at HitPos###SetCheckbox2", &LongNoteOnHitPos); + ImGui::Checkbox("Long Note Body On Top###SetCheckbox3", &LNBodyOnTop); if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("When Long note on hold, make the head position at hit position else keep going to bottom"); + ImGui::SetTooltip("If your note skin has issues, enable this option!"); + } + if (LNBodyOnTop) { + EnvironmentSetup::SetInt("LNBodyOnTop", 1); + } + else { + EnvironmentSetup::SetInt("LNBodyOnTop", 0); } ImGui::EndTabItem(); @@ -322,7 +389,7 @@ void SettingsOverlay::Render(double delta) if (ImGui::BeginTabItem("Skins")) { ImGui::Text("Current selected skin: "); - if (ImGui::BeginCombo("#SkinsComboBox", currentSkin.c_str())) { + if (ImGui::BeginCombo("##SkinsComboBox", currentSkin.c_str())) { for (int i = 0; i < skins.size(); i++) { bool isSelected = (currentSkin == skins[i]); @@ -338,6 +405,83 @@ void SettingsOverlay::Render(double delta) ImGui::EndCombo(); } + ImGui::NewLine(); + + ImGui::Text("Note Skin"); + for (int i = 0; i < NoteSkin.size(); ++i) { + bool selected = (NoteIndex == i); + + std::string tooltipText; + if (i == 0) { + //tooltipText = ""; + } + else if (i == 1) { + //tooltipText = ""; + } + else if (i == 2) { + tooltipText = "Using custom note image from skin folder"; + } + + if (ImGui::Checkbox(NoteSkin[i].c_str(), &selected)) { + NoteIndex = i; + } + + if (!tooltipText.empty() && ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", tooltipText.c_str()); + } + + ImGui::SameLine(); + } + + if (NoteIndex == 0) { + EnvironmentSetup::SetInt("NoteSkin", 0); + } + else if (NoteIndex == 1) { + EnvironmentSetup::SetInt("NoteSkin", 1); + } + else if (NoteIndex == 2) { + EnvironmentSetup::SetInt("NoteSkin", 2); + } + + ImGui::NewLine(); + ImGui::NewLine(); + + ImGui::Text("Background"); + for (int i = 0; i < SelectedBackground.size(); ++i) { + bool selected = (BackgroundIndex == i); + + std::string tooltipText; + if (i == 0) { + tooltipText = "Using arena image background inside Skin folder"; + } + else if (i == 1) { + tooltipText = "Using song image background inside O2Jam file / BMS folder / osu!mania beatmap folder"; + } + else if (i == 2) { + tooltipText = "Not using any background"; + } + + if (ImGui::Checkbox(SelectedBackground[i].c_str(), &selected)) { + BackgroundIndex = i; + } + + if (!tooltipText.empty() && ImGui::IsItemHovered()) { + ImGui::SetTooltip("%s", tooltipText.c_str()); + } + + ImGui::SameLine(); + } + + if (BackgroundIndex == 1) { + EnvironmentSetup::SetInt("Background", 1); + } + else if (BackgroundIndex == 2) { + EnvironmentSetup::SetInt("Background", 2); + } + else { + EnvironmentSetup::SetInt("Background", 0); + } + ImGui::EndTabItem(); } @@ -434,29 +578,108 @@ void SettingsOverlay::LoadConfiguration() } try { - auto value = Configuration::Load("Game", "FrameLimit"); - auto it = std::find(m_fps.begin(), m_fps.end(), value); - if (it == m_fps.end()) { - currentFPSIndex = 4; - } else { - currentFPSIndex = (int)(it - m_fps.begin()); + std::string frameLimit = Configuration::Load("Game", "FrameLimit"); + auto fpsOptions = GetFpsOptions(); + auto it = std::find(fpsOptions.begin(), fpsOptions.end(), frameLimit); + if (it != fpsOptions.end()) { + currentFPSIndex = static_cast(std::distance(fpsOptions.begin(), it)); + customFPS = 0; } - } catch (const std::invalid_argument &) { - currentFPSIndex = 4; + else { + currentFPSIndex = static_cast(fpsOptions.size()) - 1; + customFPS = 9999; + } + } + catch (const std::invalid_argument&) { + customFPS = 9999; } + SceneManager::GetInstance()->SetFrameLimit(std::atof(Configuration::Load("Game", "FrameLimit").c_str())); + try { currentGuideLineIndex = std::stoi(Configuration::Load("Game", "GuideLine").c_str()); } catch (const std::invalid_argument &) { currentGuideLineIndex = 2; } - auto fps = m_fps[currentFPSIndex]; - if (fps == *(m_fps.end() - 1)) { - fps = "-1";// Unlimited + try { + BackgroundIndex = std::stoi(Configuration::Load("Game", "Background").c_str()); + } catch (const std::invalid_argument&) { + BackgroundIndex = 0; + } + + if (BackgroundIndex == 1) { + EnvironmentSetup::SetInt("Background", 1); + } + else if (BackgroundIndex == 2) { + EnvironmentSetup::SetInt("Background", 2); + } + else { + EnvironmentSetup::SetInt("Background", 0); + } + + try { + NoteIndex = std::stoi(Configuration::Load("Game", "NoteSkin").c_str()); + } + catch (const std::invalid_argument&) { + NoteIndex = 2; + } + + if (NoteIndex == 0) { + EnvironmentSetup::SetInt("NoteSkin", 0); + } + else if (NoteIndex == 1) { + EnvironmentSetup::SetInt("NoteSkin", 1); + } + else if (NoteIndex == 2) { + EnvironmentSetup::SetInt("NoteSkin", 2); + } + + try { + int MeasureLineTypeValue = std::stoi(Configuration::Load("Game", "MeasureLineType")); + MeasureLineType = (MeasureLineTypeValue == 1); + } + catch (const std::invalid_argument&) { + MeasureLineType = false; + } + + if (MeasureLineType) { + EnvironmentSetup::SetInt("MeasureLineType", 1); + } + else { + EnvironmentSetup::SetInt("MeasureLineType", 0); + } + + try { + int measureLineValue = std::stoi(Configuration::Load("Game", "MeasureLine")); + MeasureLine = (measureLineValue == 1); + } + catch (const std::invalid_argument&) { + MeasureLine = true; + } + + if (MeasureLine) { + EnvironmentSetup::SetInt("MeasureLine", 0); + } + else { + EnvironmentSetup::SetInt("MeasureLine", 1); + } + + try { + int LNBodyOnTopValue = std::stoi(Configuration::Load("Game", "LNBodyOnTop")); + LNBodyOnTop = (LNBodyOnTopValue == 1); + } + catch (const std::invalid_argument&) { + LNBodyOnTop = true; + } + + if (LNBodyOnTop) { + EnvironmentSetup::SetInt("LNBodyOnTop", 1); + } + else { + EnvironmentSetup::SetInt("LNBodyOnTop", 0); } - SceneManager::GetInstance()->SetFrameLimit(std::atof(fps.c_str())); currentSkin = Configuration::Load("Game", "Skin"); PreloadSkin(); } @@ -466,15 +689,21 @@ void SettingsOverlay::SaveConfiguration() Configuration::Set("Game", "AudioOffset", std::to_string(currentOffset)); Configuration::Set("Game", "AudioVolume", std::to_string(currentVolume)); Configuration::Set("Game", "AutoSound", std::to_string(convertAutoSound ? 1 : 0)); - Configuration::Set("Game", "FrameLimit", m_fps[currentFPSIndex]); Configuration::Set("Game", "GuideLine", std::to_string(currentGuideLineIndex)); - - auto frame = m_fps[currentFPSIndex]; - if (frame == m_fps[13]) { - frame = "9999"; + Configuration::Set("Game", "NoteSkin", std::to_string(NoteIndex)); + Configuration::Set("Game", "Background", std::to_string(BackgroundIndex)); + Configuration::Set("Game", "MeasureLine", std::to_string(MeasureLine ? 1 : 0)); + Configuration::Set("Game", "MeasureLineType", std::to_string(MeasureLineType ? 1 : 0)); + Configuration::Set("Game", "LNBodyOnTop", std::to_string(LNBodyOnTop ? 1 : 0)); + + if (currentFPSIndex == GetFpsOptions().size() - 1 && customFPS > 0) { + Configuration::Set("Game", "FrameLimit", std::to_string(customFPS)); + } + else { + Configuration::Set("Game", "FrameLimit", GetFpsOptions()[currentFPSIndex]); } - SceneManager::GetInstance()->SetFrameLimit(std::atof(frame.c_str())); + SceneManager::GetInstance()->SetFrameLimit(std::atof(Configuration::Load("Game", "FrameLimit").c_str())); if (currentSkin.empty()) { throw std::runtime_error("SKIN_NAME Undefined!"); diff --git a/Game/src/Scenes/Overlays/Settings.h b/Game/src/Scenes/Overlays/Settings.h index 16798421..65732c29 100644 --- a/Game/src/Scenes/Overlays/Settings.h +++ b/Game/src/Scenes/Overlays/Settings.h @@ -24,8 +24,11 @@ class SettingsOverlay : public Overlay int currentOffset = 0; int currentResolutionIndex = 0; int currentGuideLineIndex = 0; - bool LongNoteLighting = false; - bool LongNoteOnHitPos = false; + bool MeasureLine = false; + bool LNBodyOnTop = false; + bool MeasureLineType = false; + int BackgroundIndex = 0; + int NoteIndex = 0; bool convertAutoSound = false; std::string currentSkin = ""; diff --git a/Game/src/Scenes/ResultScene.cpp b/Game/src/Scenes/ResultScene.cpp index 83146054..00cbcac9 100644 --- a/Game/src/Scenes/ResultScene.cpp +++ b/Game/src/Scenes/ResultScene.cpp @@ -132,13 +132,9 @@ void ResultScene::Render(double delta) } if (m_backButton) { - if (EnvironmentSetup::GetPath("FILE").empty()) { - SceneManager::DisplayFade(100, [] { - SceneManager::ChangeScene(GameScene::SONGSELECT); - }); - } else { - SceneManager::GetInstance()->StopGame(); - } + SceneManager::DisplayFade(100, [] { + SceneManager::ChangeScene(GameScene::SONGSELECT); + }); } if (m_retryButton) { diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index 68e8776a..987ca7c9 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -47,7 +47,7 @@ static std::wstring OpenFilePrompt() { } } -static std::array Mods = { "Mirror", "Random", "Panic", "Rearrange", "Autoplay", "Hidden", "Flashlight", "Sudden", "Song BG", "Black BG"}; +static std::array Mods = { "Mirror", "Random", "Panic", "Rearrange", "Autoplay", "Hidden", "Flashlight", "Sudden"}; static std::array Arena = { "Random", "Arena 1", "Arena 2", "Arena 3", "Arena 4", "Arena 5", "Arena 6", "Arena 7", "Arena 8", "Arena 9", "Arena 10", "Arena 11", "Arena 12" }; @@ -115,11 +115,11 @@ void SongSelectScene::Render(double delta) bQuit = true; } - /*if (ImGui::Button("Open File", MathUtil::ScaleVec2(ImVec2(50, 0)))) { + if (ImGui::Button("Open File", MathUtil::ScaleVec2(ImVec2(50, 0)))) { bOpenFile = true; - }*/ // FIXME: Plz Fix This + } - if (ImGui::Button("Options", MathUtil::ScaleVec2(ImVec2(50, 0)))) { + if (ImGui::Button("Settings", MathUtil::ScaleVec2(ImVec2(50, 0)))) { bOptionPopup = true; } @@ -352,20 +352,15 @@ void SongSelectScene::Render(double delta) } if (bOpenFile) { + SaveModifiers(); + SaveConfiguration(); std::wstring songfile = OpenFilePrompt(); if (!songfile.empty()) { - EnvironmentSetup::SetPath("FILE", songfile); is_departing = true; - SaveConfiguration(); - - if (m_songBackground) { - EnvironmentSetup::SetObj("SongBackground", m_songBackground.get()); - } + EnvironmentSetup::SetPath("FILE", songfile); - nextAlpha = 0; - SceneManager::ExecuteAfter(600, [this]() { - SceneManager::ChangeScene(GameScene::LOADING); - }); + // Restart the game + RestartGame(); } else { MsgBox::Show("MustSelectFile", "Error", "You must select a file!", MsgBoxType::OK); @@ -430,10 +425,11 @@ void SongSelectScene::OnGameSelectMusic(double delta) auto music = GameDatabase::GetInstance(); auto window = GameWindow::GetInstance(); auto windowNextSz = ImVec2((float)window->GetBufferWidth(), (float)window->GetBufferHeight()); - int currentDifficulty = EnvironmentSetup::GetInt("Difficulty"); + currentDifficulty = EnvironmentSetup::GetInt("Difficulty"); // create child window if (ImGui::BeginChild("#Container1", MathUtil::ScaleVec2(ImVec2(200, 500)))) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 3)); if (ImGui::BeginChild("#SongSelectChild2", MathUtil::ScaleVec2(ImVec2(200, 200)), true)) { ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0, 0)); @@ -454,15 +450,15 @@ void SongSelectScene::OnGameSelectMusic(double delta) ImGui::Text("Title\r"); imgui_extends::TextBackground(color, MathUtil::ScaleVec2(340, 0), "%s", (const char *)item.Title); - ImGui::Text("Artist\r"); + ImGui::Text("Artist / Composer\r"); imgui_extends::TextBackground(color, MathUtil::ScaleVec2(340, 0), "%s", (const char *)item.Artist); ImGui::Text("Notecharter\r"); imgui_extends::TextBackground(color, MathUtil::ScaleVec2(340, 0), "%s", (const char *)item.Noter); - ImGui::Text("Note count\r"); + ImGui::Text("Total Notes\r"); - int difficulty = EnvironmentSetup::GetInt("Difficulty"); + difficulty = EnvironmentSetup::GetInt("Difficulty"); int count = item.Id == -1 ? 0 : item.MaxNotes[difficulty]; imgui_extends::TextBackground(color, MathUtil::ScaleVec2(340, 0), "%d", count); @@ -477,6 +473,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) } if (ImGui::BeginChild("#test2", MathUtil::ScaleVec2(ImVec2(200, 290)), true)) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 2)); std::vector difficulty = { "EZ", "NM", "HD" }; ImGui::Text("Note difficulty"); @@ -519,16 +516,16 @@ void SongSelectScene::OnGameSelectMusic(double delta) ImGui::PopItemWidth(); + ImGui::Text("Modifier"); for (int i = 0; i < Mods.size(); i++) { - auto &mod = Mods[i]; + auto& mod = Mods[i]; int value = EnvironmentSetup::GetInt(mod); if (value == 1) { ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.9f); ImVec4 color = ImGui::GetStyleColorVec4(ImGuiCol_Button); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(color.x * 1.2f, color.y * 1.2f, color.z * 1.2f, 1.0f)); } @@ -569,12 +566,6 @@ void SongSelectScene::OnGameSelectMusic(double delta) EnvironmentSetup::SetInt(Mods[5], 0); // Hidden EnvironmentSetup::SetInt(Mods[6], 0); // Flashlight break; - case 8: // Song Background - EnvironmentSetup::SetInt(Mods[9], 0); // Black Background - break; - case 9: // Black Background - EnvironmentSetup::SetInt(Mods[8], 0); // Song Background - break; } } @@ -589,8 +580,6 @@ void SongSelectScene::OnGameSelectMusic(double delta) } } - ImGui::NewLine(); - ImGui::PushItemWidth(ImGui::GetCurrentWindow()->Size.x - 15); ImGui::Text("Arena"); @@ -606,11 +595,16 @@ void SongSelectScene::OnGameSelectMusic(double delta) ImGui::EndCombo(); } + + ImGui::PopStyleVar(); + ImGui::PopItemWidth(); ImGui::EndChild(); } + ImGui::PopStyleVar(); + ImGui::EndChild(); } @@ -912,6 +906,23 @@ bool SongSelectScene::Attach() return true; } +void SongSelectScene::RestartGame() { // HACK: This is the only way to use Open File function by restart the game to use the file opened without path issues + wchar_t moduleFileName[MAX_PATH]; + GetModuleFileNameW(NULL, moduleFileName, MAX_PATH); + + std::wstring filePath = EnvironmentSetup::GetPath("FILE"); + + std::wstring commandLine = std::wstring(moduleFileName) + L" \"" + filePath + L"\""; + STARTUPINFOW si = { sizeof(si) }; + PROCESS_INFORMATION pi; + + if (CreateProcessW(NULL, const_cast(commandLine.c_str()), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { // Fix antivirus false detection + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + ExitProcess(0); + } +} + bool SongSelectScene::Detach() { if (m_bgm) { @@ -936,6 +947,25 @@ void SongSelectScene::SaveConfiguration() Configuration::Set("Gameplay", "Notespeed", std::to_string(static_cast(::round(currentSpeed * 100.0)))); } +void SongSelectScene::SaveModifiers() +{ + Configuration::Set("Gameplay", "Difficulty", std::to_string(currentDifficulty)); + + std::string selectedMods; + for (int i = 0; i < Mods.size(); i++) { + std::string mod = Mods[i]; + int value = EnvironmentSetup::GetInt(mod); + if (value == 1) { + if (!selectedMods.empty()) selectedMods += ","; + selectedMods += mod; + } + } + Configuration::Set("Gameplay", "Modifiers", selectedMods); + + int arenaValue = EnvironmentSetup::GetInt("Arena"); + Configuration::Set("Gameplay", "Arena", std::to_string(arenaValue)); +} + void SongSelectScene::LoadChartImage() { std::lock_guard lock(m_imageLock); diff --git a/Game/src/Scenes/SongSelectScene.h b/Game/src/Scenes/SongSelectScene.h index e3c95560..ab5d4ce4 100644 --- a/Game/src/Scenes/SongSelectScene.h +++ b/Game/src/Scenes/SongSelectScene.h @@ -24,6 +24,7 @@ class SongSelectScene : public Scene void OnMouseDown(const MouseState &state) override; bool Attach() override; + void RestartGame(); bool Detach() override; protected: @@ -32,6 +33,7 @@ class SongSelectScene : public Scene private: void SaveConfiguration(); + void SaveModifiers(); void LoadChartImage(); int scene_index = 0; @@ -42,6 +44,9 @@ class SongSelectScene : public Scene bool isScrolled = false; float waitTime = 0; + int currentDifficulty; + int difficulty; + float currentSpeed = 2.25; float currentRate = 1.0; diff --git a/Game/src/main.cpp b/Game/src/main.cpp index 6d501ab9..c6c1e982 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -22,8 +22,9 @@ #if _WIN32 extern "C" { -__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; -__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; + __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; + __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; + __declspec(dllexport) DWORD IntelGpuPowerPreference = 0x00000002; } #endif @@ -71,7 +72,7 @@ int Run(int argc, wchar_t **argv) if (std::filesystem::exists(argv[i]) && EnvironmentSetup::GetPath("FILE").empty()) { std::filesystem::path path = argv[i]; - + EnvironmentSetup::SetInt("FileOpen", 1); EnvironmentSetup::SetPath("FILE", path); } } @@ -177,4 +178,4 @@ int main(int argc, char *argv[]) // auto val = lua.GetSprite(SkinGroup::Playing, "JamLogo"); // return 0; -// } \ No newline at end of file +// } From ad95640e596867e66cb7702f659fe41fb9314cbf Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Tue, 9 Jul 2024 11:52:14 +0700 Subject: [PATCH 77/83] refactor(gameplayscene): added code --- Game/src/Scenes/GameplayScene.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 8552a889..800636c3 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -267,7 +267,7 @@ void GameplayScene::Render(double delta) m_judgement[m_judgeIndex]->AnchorPoint = { 0.5, 0.5 }; m_judgement[m_judgeIndex]->Draw(); - m_judgeSize = std::clamp(m_judgeSize + (delta * 6), 0.6, 1.0); // Nice + m_judgeSize = std::clamp(m_judgeSize + (delta * 6), 0.5, 1.0); // Nice if ((m_judgeTimer += delta) > 0.60) { m_drawJudge = false; } @@ -286,21 +286,29 @@ void GameplayScene::Render(double delta) if (m_drawCombo && std::get<7>(scores) > 0) { // This should be O2Jam Replication const double positionStart = 30.0; - const double step = 6.0; + double step = 6.0; double animationSpeed = 90.0; + double maxStep = step; double maxSpeed = animationSpeed; if (m_comboTimer > 0.5) { - animationSpeed += 15.0 * delta; + animationSpeed += 10.0 * delta; + step += 1.0 * delta; + } else { - animationSpeed -= 15.0 * delta; + animationSpeed -= 10.0 * delta; + step -= 1.0 * delta; } - if (animationSpeed > 90.0) { + if (animationSpeed > maxSpeed) { animationSpeed = maxSpeed; } + if (step > maxStep) { + step = maxStep; + } + double targetposition = positionStart - step * m_comboTimer * animationSpeed; double currentposition = (targetposition > 0.0) ? targetposition : 0.0; From 210509023be224154d68d100edcd8cc26ec04a79 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:28:37 +0700 Subject: [PATCH 78/83] refactor(gameplayscene): o2jam combo animation should be like this --- Game/src/Scenes/GameplayScene.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 800636c3..ef8dbeab 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -267,7 +267,7 @@ void GameplayScene::Render(double delta) m_judgement[m_judgeIndex]->AnchorPoint = { 0.5, 0.5 }; m_judgement[m_judgeIndex]->Draw(); - m_judgeSize = std::clamp(m_judgeSize + (delta * 6), 0.5, 1.0); // Nice + m_judgeSize = std::clamp(m_judgeSize + (delta * 6), 0.4, 1.0); // Nice if ((m_judgeTimer += delta) > 0.60) { m_drawJudge = false; } @@ -284,14 +284,14 @@ void GameplayScene::Render(double delta) } } - if (m_drawCombo && std::get<7>(scores) > 0) { // This should be O2Jam Replication + if (m_drawCombo && std::get<7>(scores) > 0) { // O2Jam Replication by Albert Frengki! const double positionStart = 30.0; double step = 6.0; double animationSpeed = 90.0; double maxStep = step; double maxSpeed = animationSpeed; - if (m_comboTimer > 0.5) { + if (m_comboTimer > 1.0) { animationSpeed += 10.0 * delta; step += 1.0 * delta; From 292f2eb4de1572034fcabe641ebce6f1726c769b Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Sun, 14 Jul 2024 15:13:57 +0700 Subject: [PATCH 79/83] --- Game/src/Scenes/GameplayScene.cpp | 33 +++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index ef8dbeab..05cc2472 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -309,11 +309,11 @@ void GameplayScene::Render(double delta) step = maxStep; } - double targetposition = positionStart - step * m_comboTimer * animationSpeed; - double currentposition = (targetposition > 0.0) ? targetposition : 0.0; + double targetPosition = positionStart - step * m_comboTimer * animationSpeed; + double currentPosition = (targetPosition > 0.0) ? targetPosition : 0.0; - m_comboLogo->Position2 = UDim2::fromOffset(0, currentposition / 3.0); - m_comboNum->Position2 = UDim2::fromOffset(0, currentposition); + m_comboLogo->Position2 = UDim2::fromOffset(0, currentPosition / 3.0); + m_comboNum->Position2 = UDim2::fromOffset(0, currentPosition); m_comboLogo->Draw(delta); m_comboNum->DrawNumber(std::get<7>(scores)); @@ -328,9 +328,30 @@ void GameplayScene::Render(double delta) if (m_drawLN && std::get<9>(scores) > 0) { const double positionStart = 5.0; - double animationSpeed = 60.0; + double step = 1.0; + double animationSpeed = 90.0; + double maxStep = step; + double maxSpeed = animationSpeed; + + if (m_comboTimer > 1.0) { + animationSpeed += 10.0 * delta; + step += 0.1 * delta; + + } + else { + animationSpeed -= 10.0 * delta; + step -= 0.1 * delta; + } + + if (animationSpeed > maxSpeed) { + animationSpeed = maxSpeed; + } + + if (step > maxStep) { + step = maxStep; + } - double targetPosition = positionStart - m_lnTimer * animationSpeed; + double targetPosition = positionStart - step * m_lnTimer * animationSpeed; double currentPosition = (targetPosition > 0.0) ? targetPosition : 0.0; m_lnLogo->Position2 = UDim2::fromOffset(0, currentPosition); From dde950eee9e7a8818ae209ed8f5abb179ba7b1df Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:42:05 +0700 Subject: [PATCH 80/83] remove problematic feature - other keymode than 7 = crash - panic mod --- Game/src/Data/Chart.cpp | 44 ++++++++--------------------- Game/src/Data/Chart.hpp | 2 +- Game/src/Scenes/LoadingScene.cpp | 14 +++++++-- Game/src/Scenes/SongSelectScene.cpp | 37 ++++++++++-------------- 4 files changed, 39 insertions(+), 58 deletions(-) diff --git a/Game/src/Data/Chart.cpp b/Game/src/Data/Chart.cpp index c68fa0d8..ee382ce9 100644 --- a/Game/src/Data/Chart.cpp +++ b/Game/src/Data/Chart.cpp @@ -9,6 +9,10 @@ #include #include #include +#include +#include +#include "../GameScenes.h" +#include "../EnvironmentSetup.hpp" float float_floor(float value) { @@ -171,7 +175,7 @@ Chart::Chart(Osu::Beatmap& beatmap) // Refactor CalculateBeat(); SortTimings(); NormalizeTimings(); - AdjustLaneIndex(); + CheckFor7K(); ComputeKeyCount(); ComputeHash(); } @@ -590,6 +594,7 @@ float Chart::GetCommonBPM() void Chart::NormalizeTimings() { + EnvironmentSetup::SetInt("KeyCount", m_keyCount); std::vector result; float baseBPM = GetCommonBPM(); @@ -696,38 +701,13 @@ void Chart::NormalizeTimings() m_svs = result; } -void Chart::AdjustLaneIndex() // Fix vector subscript out of range +void Chart::CheckFor7K() { - for (auto& note : m_notes) { - switch (m_keyCount) { // Fuck, this hard to figure out - case 4: - { - if (note.LaneIndex >= 2) { - note.LaneIndex += 3; - } - break; - } - case 5: - { - if (note.LaneIndex == 2) { - note.LaneIndex += 1; - } - else if (note.LaneIndex >= 3) { - note.LaneIndex += 2; - } - break; - } - case 6: - { - if (note.LaneIndex >= 3) { - note.LaneIndex += 1; - } - break; - } - default: - m_keyCount = 7; - break; - } + bool is7K = EnvironmentSetup::GetInt("KeyCount") == 7; + if (!is7K) + { + MsgBox::Show("Only7K", "Error", "Only 7K Mode Allowed!", MsgBoxType::OK); + SceneManager::ChangeScene(GameScene::SONGSELECT); } } diff --git a/Game/src/Data/Chart.hpp b/Game/src/Data/Chart.hpp index e069bfe0..14724cf4 100644 --- a/Game/src/Data/Chart.hpp +++ b/Game/src/Data/Chart.hpp @@ -118,7 +118,7 @@ class Chart std::vector m_samples; std::vector m_autoSamples; - void AdjustLaneIndex(); + void CheckFor7K(); private: double PredefinedAudioLength = -1; diff --git a/Game/src/Scenes/LoadingScene.cpp b/Game/src/Scenes/LoadingScene.cpp index 96cfda81..153e0405 100644 --- a/Game/src/Scenes/LoadingScene.cpp +++ b/Game/src/Scenes/LoadingScene.cpp @@ -162,14 +162,22 @@ void LoadingScene::Update(double delta) if (IsFile) { EnvironmentSetup::SetObj("SongBackground", m_background); } - SceneManager::ChangeScene(GameScene::GAMEPLAY); - EnvironmentSetup::SetInt("FillStart", 1); + bool is7K = EnvironmentSetup::GetInt("KeyCount") == 7; + if (!is7K) + { + MsgBox::Show("Only7K", "Error", "Only 7K Mode Allowed!", MsgBoxType::OK); + SceneManager::ChangeScene(GameScene::SONGSELECT); + } + else { + SceneManager::ChangeScene(GameScene::GAMEPLAY); + EnvironmentSetup::SetInt("FillStart", 1); + } } else { if (fucked) { std::string songId = EnvironmentSetup::Get("Key"); if (songId.size() > 0) { if (m_counter > 1) { - SceneManager::ChangeScene(GameScene::MAINMENU); + SceneManager::ChangeScene(GameScene::SONGSELECT); } } else { if (MsgBox::GetResult("FailChart") == 4) { diff --git a/Game/src/Scenes/SongSelectScene.cpp b/Game/src/Scenes/SongSelectScene.cpp index 987ca7c9..391a0185 100644 --- a/Game/src/Scenes/SongSelectScene.cpp +++ b/Game/src/Scenes/SongSelectScene.cpp @@ -47,7 +47,7 @@ static std::wstring OpenFilePrompt() { } } -static std::array Mods = { "Mirror", "Random", "Panic", "Rearrange", "Autoplay", "Hidden", "Flashlight", "Sudden"}; +static std::array Mods = { "Mirror", "Random", "Rearrange", "Autoplay", "Hidden", "Flashlight", "Sudden" }; static std::array Arena = { "Random", "Arena 1", "Arena 2", "Arena 3", "Arena 4", "Arena 5", "Arena 6", "Arena 7", "Arena 8", "Arena 9", "Arena 10", "Arena 11", "Arena 12" }; @@ -532,39 +532,31 @@ void SongSelectScene::OnGameSelectMusic(double delta) if (ImGui::Button(mod.c_str(), MathUtil::ScaleVec2(ImVec2(80, 0)))) { EnvironmentSetup::SetInt(mod, value == 1 ? 0 : 1); - switch (i) { // New Modifier + switch (i) { case 0: // Mirror EnvironmentSetup::SetInt(Mods[1], 0); // Random - EnvironmentSetup::SetInt(Mods[2], 0); // Panic - EnvironmentSetup::SetInt(Mods[3], 0); // Rearrange + EnvironmentSetup::SetInt(Mods[2], 0); // Rearrange break; case 1: // Random EnvironmentSetup::SetInt(Mods[0], 0); // Mirror - EnvironmentSetup::SetInt(Mods[2], 0); // Panic - EnvironmentSetup::SetInt(Mods[3], 0); // Rearrange + EnvironmentSetup::SetInt(Mods[2], 0); // Rearrange break; - case 2: // Panic + case 2: // Rearrange EnvironmentSetup::SetInt(Mods[0], 0); // Mirror EnvironmentSetup::SetInt(Mods[1], 0); // Random - EnvironmentSetup::SetInt(Mods[3], 0); // Rearrange - break; - case 3: // Rearrange - EnvironmentSetup::SetInt(Mods[0], 0); // Mirror - EnvironmentSetup::SetInt(Mods[1], 0); // Random - EnvironmentSetup::SetInt(Mods[2], 0); // Panic bOpenRearrange = true; // Open Rearrange Window break; - case 5: // Hidden - EnvironmentSetup::SetInt(Mods[6], 0); // Flashlight - EnvironmentSetup::SetInt(Mods[7], 0); // Sudden + case 4: // Hidden + EnvironmentSetup::SetInt(Mods[5], 0); // Flashlight + EnvironmentSetup::SetInt(Mods[6], 0); // Sudden break; - case 6: // Flashlight - EnvironmentSetup::SetInt(Mods[5], 0); // Hidden - EnvironmentSetup::SetInt(Mods[7], 0); // Sudden + case 5: // Flashlight + EnvironmentSetup::SetInt(Mods[4], 0); // Hidden + EnvironmentSetup::SetInt(Mods[6], 0); // Sudden break; - case 7: // Sudden - EnvironmentSetup::SetInt(Mods[5], 0); // Hidden - EnvironmentSetup::SetInt(Mods[6], 0); // Flashlight + case 6: // Sudden + EnvironmentSetup::SetInt(Mods[4], 0); // Hidden + EnvironmentSetup::SetInt(Mods[5], 0); // Flashlight break; } } @@ -580,6 +572,7 @@ void SongSelectScene::OnGameSelectMusic(double delta) } } + ImGui::NewLine(); ImGui::PushItemWidth(ImGui::GetCurrentWindow()->Size.x - 15); ImGui::Text("Arena"); From d95baac734d41294af560a5c7581c67b9c81328d Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:42:22 +0700 Subject: [PATCH 81/83] improve game experience --- Game/src/Engine/Note.cpp | 2 +- Game/src/Resources/DefaultConfiguration.h | 1 + Game/src/Scenes/GameplayScene.cpp | 15 ++++------- Game/src/Scenes/Overlays/Settings.cpp | 33 ++++++++++++++++++++--- Game/src/Scenes/Overlays/Settings.h | 1 + 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/Game/src/Engine/Note.cpp b/Game/src/Engine/Note.cpp index 21f5e0c2..40f6561b 100644 --- a/Game/src/Engine/Note.cpp +++ b/Game/src/Engine/Note.cpp @@ -319,7 +319,7 @@ void Note::Render(double delta) double tailPosY = lerp(0.0, static_cast(hitPos), static_cast(y2)); bool isTailVisible = isWithinRange(tailPosY, min, max); - if (EnvironmentSetup::GetInt("NoPercy") == 1) { + if (EnvironmentSetup::GetInt("NewLN") == 1) { tailPosY += m_tail->AbsoluteSize.Y; } diff --git a/Game/src/Resources/DefaultConfiguration.h b/Game/src/Resources/DefaultConfiguration.h index 260f7500..951ea0f8 100644 --- a/Game/src/Resources/DefaultConfiguration.h +++ b/Game/src/Resources/DefaultConfiguration.h @@ -14,6 +14,7 @@ std::string defaultConfiguration = "[game]\n" "background = 0\n" "measureline = 1\n" "measurelinetype = 0\n" + "newlongnote = 0\n" "lnbodyontop = 0\n\n" "[keymapping]\n" diff --git a/Game/src/Scenes/GameplayScene.cpp b/Game/src/Scenes/GameplayScene.cpp index 05cc2472..83fe8c11 100644 --- a/Game/src/Scenes/GameplayScene.cpp +++ b/Game/src/Scenes/GameplayScene.cpp @@ -35,7 +35,7 @@ struct MissInfo float beat; float hit_beat; float time; -}; +}; bool CheckSkinComponent(std::filesystem::path x) { @@ -1055,11 +1055,6 @@ bool GameplayScene::Attach() if (IsHD) { segments = { - //{ 0.00f, 0.00f, { 0, 0, 0, 255 }, { 0, 0, 0, 255 } }, - //{ 0.00f, 0.00f, { 0, 0, 0, 255 }, { 0, 0, 0, 0 } }, - //{ 0.00f, 0.45f, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, - //{ 0.45f, 0.50f, { 0, 0, 0, 0 }, { 0, 0, 0, 255 } }, - //{ 0.50f, 1.00f, { 0, 0, 0, 255 }, { 0, 0, 0, 255 } } { 0.00f, 0.45f, { 0, 0, 0, 0 }, { 0, 0, 0, 0 } }, { 0.45f, 0.50f, { 0, 0, 0, 0 }, { 0, 0, 0, 255 } }, { 0.50f, 1.00f, { 0, 0, 0, 255 }, { 0, 0, 0, 255 } } @@ -1091,10 +1086,10 @@ bool GameplayScene::Attach() m_laneHideImage->Size = UDim2::fromOffset(imageWidth, imageHeight); } - bool areVisualModsActive = IsHD || IsFL || IsSD; // Check if any of the VisualMods are active (Hidden or Flashlight) - bool areNoteModsActive = IsMR || IsRD || IsPC; // Check if any of the NoteMods are active (Mirror or Random) + bool VisualModEnabled = IsHD || IsFL || IsSD; // Check if any of the VisualMods are active (Hidden or Flashlight) + bool NoteModEnabled = IsMR || IsRD || IsPC; // Check if any of the NoteMods are active (Mirror or Random) - if (areVisualModsActive) { // Draw VisualMods (Hidden, Flashlight, and Sudden) + if (VisualModEnabled) { // Draw VisualMods (Hidden, Flashlight, and Sudden) if (IsHD) { std::string VisualModImage = "ModHidden.png"; auto VisualModfilename = playingPath / VisualModImage; @@ -1125,7 +1120,7 @@ bool GameplayScene::Attach() } } - if (areNoteModsActive) { // Draw NoteMods (Mirror, Random, and Panic) + if (NoteModEnabled) { // Draw NoteMods (Mirror, Random, and Panic) if (IsMR) { std::string NoteModImage = "ModMirror.png"; auto NoteModfilename = playingPath / NoteModImage; diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index 15d7ba8b..89e04654 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -317,7 +317,7 @@ void SettingsOverlay::Render(double delta) ImGui::Text("Audio Offset"); ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.0f, 1.0f), "Warning: this will make keysounded sample as auto sample!"); - ImGui::SliderInt("###Slider1", ¤tOffset, -500, 500); + ImGui::SliderInt("###Slider1", ¤tOffset, -1000, 1000); ImGui::NewLine(); ImGui::Checkbox("Convert Sample to Auto Sample###Checkbox1", &convertAutoSound); @@ -348,13 +348,12 @@ void SettingsOverlay::Render(double delta) } } - ImGui::NewLine(); ImGui::NewLine(); ImGui::NewLine(); ImGui::Text("Gameplay-Related Configuration"); - ImGui::Checkbox("Use New Measure Line###SetCheckbox1", &MeasureLineType); + ImGui::Checkbox("New Measure Line###SetCheckbox1", &MeasureLineType); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Measure line position in the middle of the note; otherwise, it will be at the bottom of the note"); } @@ -365,6 +364,16 @@ void SettingsOverlay::Render(double delta) EnvironmentSetup::SetInt("MeasureLineType", 0); } + ImGui::SameLine(); + + ImGui::Checkbox("New Long Note###SetCheckbox3", &NewLongNote); + if (NewLongNote) { // Leave everything untouched since no reason to make whole changes + EnvironmentSetup::SetInt("NewLN", 1); + } + else { + EnvironmentSetup::SetInt("NewLN", 0); + } + ImGui::Checkbox("Disable Measure Line###SetCheckbox2", &MeasureLine); if (MeasureLine) { EnvironmentSetup::SetInt("MeasureLine", 0); @@ -373,6 +382,8 @@ void SettingsOverlay::Render(double delta) EnvironmentSetup::SetInt("MeasureLine", 1); } + ImGui::SameLine(); + ImGui::Checkbox("Long Note Body On Top###SetCheckbox3", &LNBodyOnTop); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("If your note skin has issues, enable this option!"); @@ -635,6 +646,21 @@ void SettingsOverlay::LoadConfiguration() EnvironmentSetup::SetInt("NoteSkin", 2); } + try { + int NewLNValue = std::stoi(Configuration::Load("Game", "NewLongNote")); + NewLongNote = (NewLNValue == 1); + } + catch (const std::invalid_argument&) { + NewLongNote = false; + } + + if (NewLongNote) { + EnvironmentSetup::SetInt("NewLN", 1); + } + else { + EnvironmentSetup::SetInt("NewLN", 0); + } + try { int MeasureLineTypeValue = std::stoi(Configuration::Load("Game", "MeasureLineType")); MeasureLineType = (MeasureLineTypeValue == 1); @@ -695,6 +721,7 @@ void SettingsOverlay::SaveConfiguration() Configuration::Set("Game", "MeasureLine", std::to_string(MeasureLine ? 1 : 0)); Configuration::Set("Game", "MeasureLineType", std::to_string(MeasureLineType ? 1 : 0)); Configuration::Set("Game", "LNBodyOnTop", std::to_string(LNBodyOnTop ? 1 : 0)); + Configuration::Set("Game", "NewLongNote", std::to_string(NewLongNote ? 1 : 0)); if (currentFPSIndex == GetFpsOptions().size() - 1 && customFPS > 0) { Configuration::Set("Game", "FrameLimit", std::to_string(customFPS)); diff --git a/Game/src/Scenes/Overlays/Settings.h b/Game/src/Scenes/Overlays/Settings.h index 65732c29..70c1a4a1 100644 --- a/Game/src/Scenes/Overlays/Settings.h +++ b/Game/src/Scenes/Overlays/Settings.h @@ -29,6 +29,7 @@ class SettingsOverlay : public Overlay bool MeasureLineType = false; int BackgroundIndex = 0; int NoteIndex = 0; + bool NewLongNote = false; bool convertAutoSound = false; std::string currentSkin = ""; From 8a20b88df36e88f707561a619bebd170997a485d Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Tue, 27 Aug 2024 12:43:22 +0700 Subject: [PATCH 82/83] remove option other than 7K --- Game/src/Scenes/Overlays/Settings.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Game/src/Scenes/Overlays/Settings.cpp b/Game/src/Scenes/Overlays/Settings.cpp index 89e04654..d4a07a7e 100644 --- a/Game/src/Scenes/Overlays/Settings.cpp +++ b/Game/src/Scenes/Overlays/Settings.cpp @@ -152,7 +152,7 @@ void SettingsOverlay::Render(double delta) if (ImGui::BeginChild("###ChildSettingWnd", MathUtil::ScaleVec2(ImVec2(400, 250)))) { if (ImGui::BeginTabBar("OptionTabBar")) { if (ImGui::BeginTabItem("Inputs")) { - ImGui::Text("7 Keys Configuration"); + ImGui::Text("Keys Configuration"); for (int i = 0; i < 7; i++) { if (i != 0) { ImGui::SameLine(); @@ -168,7 +168,7 @@ void SettingsOverlay::Render(double delta) ImGui::NewLine(); - ImGui::Text("6 Keys Configuration"); + /*ImGui::Text("6 Keys Configuration"); for (int i = 0; i < 6; i++) { if (i != 0) { ImGui::SameLine(); @@ -212,7 +212,7 @@ void SettingsOverlay::Render(double delta) EnvironmentSetup::Set("Scene_KbLaneCount", "4_"); EnvironmentSetup::Set("Scene_KbKey", std::to_string(i + 1)); } - } + }*/ ImGui::EndTabItem(); } From 0e2f06ffa8f58f41979448686df2b8d2df11fd18 Mon Sep 17 00:00:00 2001 From: Albert Frengki <75172149+AlberttFrgk@users.noreply.github.com> Date: Tue, 27 Aug 2024 13:05:04 +0700 Subject: [PATCH 83/83] --- Game/src/main.cpp | 86 +++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 51 deletions(-) diff --git a/Game/src/main.cpp b/Game/src/main.cpp index c6c1e982..77d9452c 100644 --- a/Game/src/main.cpp +++ b/Game/src/main.cpp @@ -4,11 +4,8 @@ // STD Headers #include #include -#include - -#if __linux__ -#include -#endif +#include +#include // Game Headers #include "./Data/Util/Util.hpp" @@ -20,6 +17,9 @@ #include "Configuration.h" #include "MsgBox.h" +// SDL Headers +#include + #if _WIN32 extern "C" { __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; @@ -28,7 +28,7 @@ extern "C" { } #endif -int Run(int argc, wchar_t **argv) +int Run(int argc, wchar_t** argv) { try { Configuration::SetDefaultConfiguration(defaultConfiguration); @@ -40,8 +40,6 @@ int Run(int argc, wchar_t **argv) #if _WIN32 if (SetCurrentDirectoryW((LPWSTR)parentPath.wstring().c_str()) == FALSE) { - std::cout << "GetLastError(): " << GetLastError() << ", with path: " << parentPath.string(); - MessageBoxA(NULL, "Failed to set directory!", "EstGame Error", MB_ICONERROR); return -1; } @@ -83,7 +81,8 @@ int Run(int argc, wchar_t **argv) } return 0; - } catch (std::exception &e) { + } + catch (std::exception& e) { MsgBox::ShowOut("EstGame Error", e.what(), MsgBoxType::OK, MsgBoxFlags::BTN_ERROR); return -1; } @@ -95,42 +94,37 @@ int HandleStructualException(int code) MessageBoxA(NULL, ("Uncaught exception: " + std::to_string(code)).c_str(), "FATAL ERROR", MB_ICONERROR); return EXCEPTION_EXECUTE_HANDLER; } -#endif - -// // if not DEBUG -// #if !defined(_DEBUG) && _WIN32 -// int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { -// const char* retVal = setlocale(LC_ALL, "en_US.UTF-8"); -// if (retVal == nullptr) { -// MessageBoxA(NULL, "setlocale(): Failed to set locale!", "EstGame Error", MB_ICONERROR); -// return -1; -// } - -// int argc = 0; -// wchar_t** argv = CommandLineToArgvW(GetCommandLineW(), &argc); -// int ret = 0; - -// __try { -// ret = Run(argc, argv); -// } - -// __except (HandleStructualException(GetExceptionCode())) { -// ret = -1; -// } +// SDL expects an SDL_main function as the entry point +int SDL_main(int argc, char* argv[]) +{ + const char* retVal = setlocale(LC_ALL, "en_US.UTF-8"); + if (retVal == nullptr) { + MessageBoxA(NULL, "setlocale(): Failed to set locale!", "EstGame Error", MB_ICONERROR); + return -1; + } -// LocalFree(argv); + // Convert command line arguments + int wargc = 0; + wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &wargc); -// return ret; -// } + int ret = 0; -// #else + __try { + ret = Run(wargc, wargv); + } + __except (HandleStructualException(GetExceptionCode())) { + ret = -1; + } -// #endif + LocalFree(wargv); -int main(int argc, char *argv[]) + return ret; +} +#else +int main(int argc, char* argv[]) { - const char *retVal = setlocale(LC_ALL, "en_US.UTF-8"); + const char* retVal = setlocale(LC_ALL, "en_US.UTF-8"); if (retVal == nullptr) { #if _WIN32 MessageBoxA(NULL, "setlocale(): Failed to set locale!", "EstGame Error", MB_ICONERROR); @@ -140,7 +134,7 @@ int main(int argc, char *argv[]) return -1; } - wchar_t **wargv = new wchar_t *[argc]; + wchar_t** wargv = new wchar_t* [argc]; for (int i = 0; i < argc; i++) { size_t len = mbstowcs(NULL, argv[i], 0) + 1; wargv[i] = new wchar_t[len]; @@ -149,11 +143,10 @@ int main(int argc, char *argv[]) int ret = 0; -#if _WIN32 & _MSC_VER & NDEBUG +#if _MSC_VER && !defined(NDEBUG) __try { ret = Run(argc, wargv); } - __except (HandleStructualException(GetExceptionCode())) { ret = -1; } @@ -169,13 +162,4 @@ int main(int argc, char *argv[]) return ret; } - -// #include "./Engine/LuaScripting.h" - -// int main() { -// LuaScripting lua = { std::filesystem::current_path() / "Skins" / "Default" / "Scripts" }; -// lua.Update(0.0); - -// auto val = lua.GetSprite(SkinGroup::Playing, "JamLogo"); -// return 0; -// } +#endif