Skip to content

Commit

Permalink
feat: V2 save format
Browse files Browse the repository at this point in the history
  Implement new SQLite-based save format. New worlds can be configured
  to use V2. Existing worlds can be converted from the main menu.

  Existing V1 worlds should load exactly the same as before until
  converted.

Signed-off-by: David Li <[email protected]>
  • Loading branch information
randombk committed Dec 10, 2024
1 parent 062461f commit a8e32d0
Show file tree
Hide file tree
Showing 13 changed files with 618 additions and 32 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/clang-tidy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ jobs:
sudo apt-get install \
cmake gettext ninja-build mold ccache jq \
clang-18 libclang-18-dev llvm-18 llvm-18-dev clang-tidy-18 \
libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev libsdl2-mixer-dev libpulse-dev libflac-dev
libsdl2-dev libsdl2-ttf-dev libsdl2-image-dev libsdl2-mixer-dev libpulse-dev libflac-dev \
sqlite3 libsqlite3-dev zlib1g-dev
- name: ensure clang 18 is installed
run: |
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/msys2-cmake.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ jobs:
mingw-w64-x86_64-SDL2_ttf
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-cmake
mingw-w64-x86_64-sqlite3
mingw-w64-x86_64-zstd
- name: Create build directory
run: mkdir build
Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ include(CheckCXXCompilerFlag)
#SET(CMAKE_SHARED_LIBRARY_CXX_FLAGS "${CMAKE_SHARED_LIBRARY_CXX_FLAGS} -m32")

find_package(PkgConfig)
find_package(SQLite3)
find_package(ZLIB)
if (NOT DYNAMIC_LINKING)
if(NOT MSVC)
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a;.dll.a")
Expand Down
7 changes: 7 additions & 0 deletions data/raw/keybindings/keybindings.json
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,13 @@
"name": "Pick random world name",
"bindings": [ { "input_method": "keyboard", "key": "*" } ]
},
{
"type": "keybinding",
"id": "TOGGLE_V2_SAVE_FORMAT",
"category": "WORLDGEN_CONFIRM_DIALOG",
"name": "Toggle new world save format",
"bindings": [ { "input_method": "keyboard", "key": "=" } ]
},
{
"type": "keybinding",
"id": "QUIT",
Expand Down
4 changes: 3 additions & 1 deletion msvc-full-features/vcpkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"name": "sdl2-mixer",
"features": [ "libflac", "mpg123", "libmodplug" ]
},
"sdl2-ttf"
"sdl2-ttf",
"sqlite3",
"zlib"
],
"builtin-baseline": "c9aba300923c8ec0ab190e2bff23085209925c97",
"vcpkg-configuration": {
Expand Down
5 changes: 5 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ if (TILES)

add_dependencies(cataclysm-bn-tiles-common get_version)

target_link_libraries(cataclysm-bn-tiles-common PUBLIC ZLIB::ZLIB)
target_link_libraries(cataclysm-bn-tiles-common PUBLIC SQLite::SQLite3)
target_link_libraries(cataclysm-bn-tiles PRIVATE cataclysm-bn-tiles-common)
target_compile_definitions(cataclysm-bn-tiles-common PUBLIC TILES )

Expand Down Expand Up @@ -176,9 +178,12 @@ if (CURSES)
endif ()

add_dependencies(cataclysm-bn-common get_version)

target_link_libraries(cataclysm-bn PRIVATE cataclysm-bn-common)

target_include_directories(cataclysm-bn-common PUBLIC ${CURSES_INCLUDE_DIR})
target_link_libraries(cataclysm-bn-common PUBLIC ZLIB::ZLIB)
target_link_libraries(cataclysm-bn-common PUBLIC SQLite::SQLite3)
target_link_libraries(cataclysm-bn-common PUBLIC ${CURSES_LIBRARIES})

if (CMAKE_USE_PTHREADS_INIT)
Expand Down
53 changes: 53 additions & 0 deletions src/compress.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include "compress.h"

#include <zlib.h>
#include <vector>
#include <string>
#include <stdexcept>
#include <cstddef>

void zlib_compress( const std::string &input, std::vector<std::byte> &output )
{
uLongf compressedSize = compressBound( input.size() );
output.resize( compressedSize );

int result = compress2(
reinterpret_cast<Bytef *>( output.data() ),
&compressedSize,
reinterpret_cast<const Bytef *>( input.data() ),
input.size(),
Z_BEST_SPEED
);

if( result != Z_OK ) {
throw std::runtime_error( "Zlib compression error" );
}

output.resize( compressedSize );
}

void zlib_decompress( const void *compressed_data, int compressed_size, std::string &output )
{
// We need to guess at the decompressed size - we expect things to compress fairly well.
uLongf decompressedSize = compressed_size * 8;

Check warning on line 32 in src/compress.cpp

View workflow job for this annotation

GitHub Actions / build

performing an implicit widening conversion to type 'uLongf' (aka 'unsigned long') of a multiplication performed in type 'int' [bugprone-implicit-widening-of-multiplication-result]
output.resize( decompressedSize );

int result;
do {
result = uncompress(
reinterpret_cast<Bytef *>( &output[0] ),

Check warning on line 38 in src/compress.cpp

View workflow job for this annotation

GitHub Actions / build

'data' should be used for accessing the data pointer instead of taking the address of the 0-th element [readability-container-data-pointer]
&decompressedSize,
reinterpret_cast<const Bytef *>( compressed_data ),
compressed_size
);

if( result == Z_BUF_ERROR ) {
decompressedSize *= 2; // Double the buffer size and retry
output.resize( decompressedSize );
} else if( result != Z_OK ) {
throw std::runtime_error( "Zlib decompression failed" );
}
} while( result == Z_BUF_ERROR );

output.resize( decompressedSize );
}
12 changes: 12 additions & 0 deletions src/compress.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once
#ifndef CATA_SRC_COMPRESS_H
#define CATA_SRC_COMPRESS_H

#include <string>

#include "fstream_utils.h"

void zlib_compress( const std::string &input, std::vector<std::byte> &output );
void zlib_decompress( const void *compressed_data, int compressed_size, std::string &output );

#endif // CATA_SRC_COMPRESS_H
15 changes: 15 additions & 0 deletions src/main_menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ void main_menu::init_strings()
vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "Character to Template" ) );
vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "Reset World" ) );
vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "Delete World" ) );
vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "Convert to V2 Save Format" ) );
vWorldSubItems.emplace_back( pgettext( "Main Menu|World", "<= Return" ) );

vWorldHotkeys = { 'm', 'e', 's', 't', 'r', 'd', 'q' };
Expand Down Expand Up @@ -1061,7 +1062,21 @@ void main_menu::world_tab( const std::string &worldname )
}
};

auto convert_v2 = [this, &worldname]() {
world_generator->set_active_world( nullptr );
savegames.clear();
MAPBUFFER.clear();
overmap_buffer.clear();
world_generator->convert_to_v2( worldname );
};

switch( opt_val ) {
case 6: // Convert to V2 Save Format
if( query_yn(
_( "Convert to V2 Save Format? A backup will be created. Conversion may take several minutes." ) ) ) {
convert_v2();
}
break;
case 5: // Delete World
if( query_yn( _( "Delete the world and all saves within?" ) ) ) {
clear_world( true );
Expand Down
Loading

0 comments on commit a8e32d0

Please sign in to comment.