Skip to content

improve: refactor storages in PlayerStorage component and optimized save#3664

Merged
dudantas merged 14 commits intomainfrom
dudantas/improve-storage
Sep 3, 2025
Merged

improve: refactor storages in PlayerStorage component and optimized save#3664
dudantas merged 14 commits intomainfrom
dudantas/improve-storage

Conversation

@dudantas
Copy link
Copy Markdown
Member

@dudantas dudantas commented Aug 28, 2025

The storage system was previously managed in Player through a raw storageMap, with direct insertions, deletions, and range generation (genReservedStorageRange). This change caused unnecessary complete rewrites on save and spread logic across Player, IOLoginData, and related components.

Changes

  • Introduced a new PlayerStorage component to encapsulate all storage-related logic
  • Removed the legacy storageMap from Player, centralizing load/save and manipulation in the new component
  • Implemented incremental persistence: only modified or removed keys are saved to the database, avoiding complete rewrites
  • Added support for reserved key ranges (outfits, familiars) within PlayerStorage::getReservedRange
  • Updated IOLoginDataLoad and IOLoginDataSave to delegate load/save to PlayerStorage
  • Added missing benchmark.cpp implementation and updated build files accordingly
  • Removed storage name in favor of KV.

This change refactor improves code organization, maintainability, and performance. By persisting only modified keys instead of the full storage set, save operations are faster and reduce unnecessary database load.

@dudantas dudantas force-pushed the dudantas/improve-storage branch 6 times, most recently from 899e5e2 to 3720289 Compare August 30, 2025 09:09
@dudantas dudantas changed the title improve: refactor player storage into PlayerStorage component and optimized save improve: refactor storages in PlayerStorage component and optimized save Aug 30, 2025
@sonarqubecloud
Copy link
Copy Markdown

Please retry analysis of this Pull-Request directly on SonarQube Cloud

@dudantas dudantas force-pushed the dudantas/improve-storage branch 3 times, most recently from 8be7a8f to be3794d Compare September 1, 2025 13:32
Copy link
Copy Markdown
Contributor

@luan luan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small comments if you want to address.
My main concern here is that we still have two storage systems for schemaless data. I wonder if we should come up with a way to unify this at some point. KV probably needs an easier interface if folks are still gravitating towards storage because if feels simpler. But a lot of the benefits you are gaining here KV already has (cached values, optimized & isolated db access, testability, etc)

@dudantas dudantas force-pushed the dudantas/improve-storage branch from cbf1135 to a5147fc Compare September 1, 2025 21:25
@dudantas
Copy link
Copy Markdown
Member Author

dudantas commented Sep 2, 2025

Small comments if you want to address. My main concern here is that we still have two storage systems for schemaless data. I wonder if we should come up with a way to unify this at some point. KV probably needs an easier interface if folks are still gravitating towards storage because if feels simpler. But a lot of the benefits you are gaining here KV already has (cached values, optimized & isolated db access, testability, etc)

Well, the biggest problem with this is that people have been using storage for a decade or so. It's tough to "remove" the system; there are thousands of scripts in the community that use this. Of course, it would be possible to create some abstraction in the future, but I'm not sure if it's necessary at this time.

My refactoring is mainly because, with approximately 200 active players in one year, it's possible to save 5 million storage easily. A player can have thousands or hundreds of thousands of them. So, this pull request only saves what is actually modified, which, honestly, in a "high-load" scenario, is even more performant than kv as it is today. However, we could consider creating an abstraction that maintains storage usage and, under the hood, utilizes KV, but we need to think carefully about this approach. It would be a good topic for another thread.

dudantas and others added 10 commits September 2, 2025 13:48
Moved player storage logic from Player to a new PlayerStorage component for better encapsulation and maintainability. Updated all relevant code to use the new component, including storage loading, saving, and access methods. Deprecated direct access to storageMap in Player and replaced macro IS_IN_KEYRANGE with constexpr isStorageKeyInRange function.

Added a comprehensive README.md for PlayerStorage, detailing its design, usage, reserved ranges, and performance optimizations. Enhanced player_storage.hpp with detailed Doxygen-style comments for all public methods and members, improving code readability and maintainability.
Introduces a new test suite for the PlayerStorage component under tests/unit/players/components. The tests cover adding, retrieving, and removing storage values, as well as handling reserved keys. Updates CMakeLists.txt files to include the new test directories and sources.

Add const accessors for outfits and familiars to Player

Introduced const getter methods getOutfits() and getFamiliars() in Player to provide read-only access to the respective collections. Updated unit tests to use these new accessors, improving encapsulation and ensuring side-effects are verified via the public API.

Fix missing std:: qualifier for log function

Replaced unqualified call to log with std::log in step speed calculation to ensure correct function resolution and avoid potential compilation issues.

Update test runner options in build_and_run.sh

Changed the test runner command to use the 'console' reporter, enable verbose output, show test durations, and run tests in lexicographical order for improved test diagnostics.

Refactor Player initialization and storage handling

Added a default Player constructor for unit testing and introduced explicit init() methods for PlayerWheel and AnimusMastery to separate construction from configuration. Updated PlayerStorage to log errors for unknown reserved keys only outside of unit tests. Adjusted logger formatting for consistency. Refactored unit tests to use shared_ptr<Player> and updated test logic to match new initialization patterns.

Code format - (Clang-format)

Add unit test constructor to Player class

Introduced a dedicated Player() constructor for unit testing, initializing core components and marking the instance as a unit test mock. Added detailed documentation and usage notes to clarify its purpose and restrictions.

Code format - (Clang-format)

Set m_isUnitTestMock to true in Player constructor

Moved initialization of m_isUnitTestMock to the member initializer list in the Player default constructor for consistency and clarity.

Code format - (Clang-format)

Update CMakePresets.json

Merge branch 'dudantas/improve-storage' of https://github.com/opentibiabr/canary into dudantas/improve-storage
Eliminates support for get/set storage values by name in C++ and Lua, including removal of Player::getStorageValueByName, PlayerStorage::get/add by name, and their Lua bindings. Updates migration scripts and talkaction to avoid using these deprecated methods, encouraging use of the KV system instead.

Remove unused upsertKey lambda from getReservedRange

Deleted the upsertKey lambda function from PlayerStorage::getReservedRange as it was not used in the function.

Refactor player storage for clarity and efficiency

Removed unnecessary 'static' from kPassThroughRanges and replaced map find with contains in has() for improved readability and efficiency.

Code format - (Clang-format)

Refactor PlayerStorage and add upsertKey method

Moved pass-through range logic into an internal namespace function for reuse and clarity. Added the upsertKey method to insert or update storage keys and mark them as modified. Improved logging and minor code cleanups in save and load methods.

Code format - (Clang-format)
Each test case in player_storage_test.cpp is now encapsulated in its own static function for improved readability and maintainability. The main test suite calls these functions to register the tests.
Changed the onAddTileItem method in the Creature class to be a const member function, ensuring it does not modify the object state.
Updated the logger warning in IOLoginDataSave::savePlayerStorage to remove redundant text and improve clarity when player is nullptr.
Replaces direct database access in PlayerStorage with a repository interface and implementation. Adds PlayerStorageRow and PlayerStorageDelta types, refactors load/save logic to ingest/delta/prepareForPersist/clearDirty methods, and updates IOLoginDataLoad/Save to use the new repository. Improves test coverage and decouples storage logic from database details.
Deleted obsolete Lua migration scripts for storage key migration. Refactored player storage to remove m_isUnitTestMock checks and updated related unit tests to use dependency injection for logging.
@dudantas dudantas force-pushed the dudantas/improve-storage branch from 91c5b6d to 17dce72 Compare September 2, 2025 16:50
Extracted common test environment setup into test_env.hpp and updated account_repository_db_it.cpp to use it. Added new integration tests for DbPlayerStorageRepository with supporting CMakeLists.txt. This improves test code reuse and adds coverage for player storage repository database operations.
Extracted row search logic in player storage repository integration tests into a helper function for clarity. Refactored TestEnv to separate initialization logic, improve encapsulation, and provide a global instance for easier access.
Simplified the hasRow function by replacing the manual loop with std::ranges::any_of for improved readability and modern C++ usage.
Reordered m_playerVIP initialization in Player constructors for consistency. Removed unused m_isUnitTestMock member from Player. Renamed variable 'd' to 'delta' in savePlayerStorage for clarity.
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Sep 3, 2025

@dudantas dudantas merged commit 3c7b7de into main Sep 3, 2025
46 checks passed
@dudantas dudantas deleted the dudantas/improve-storage branch September 3, 2025 04:01
un000000 added a commit to vaigu-com/otserver that referenced this pull request Sep 21, 2025
* fix: pvp zone no loss (opentibiabr#3353)

This change will prevent players from losing skills or dropping items
when dieing in pvp zone, currently theres nothing involving pvp zone
besides the old pvp arena which hopefully will be updated to tibia drome
so this fix its something to have in mind.

* fix: djinn freequest (opentibiabr#3471)

To speak with djiins, you need to complete a few quests. Namely: "The
Djinn War - Efreet Faction" and "The Djinn War - Marid Faction".

Even though they show up as "completed" when freequests runs, you are
still unable to talk to them using their special word "Djanni'hah". They
laugh, saying it's ALMOST correct, then stop talking to you.

Changing the storageValue for the start quests to 0 fixes the issue.

* fix: loot factor generate random value (opentibiabr#3181)

Currently, the factor is not really random, this corrects this problem.

* fix: incorrect NPC interaction handling in The Djinn War Quest (opentibiabr#3508)

Revert the system check modified in PR opentibiabr#3471 that incorrectly identified whether the player followed the Efreet or Marid path, preventing proper NPC interaction. Ensure players aligned with Efreet cannot talk to Marid NPCs and vice-versa.

Also, fix an issue where players, even after completing the quest, could only greet NPCs using "DJANNI'HAH". Add a quest completion check before the existing greeting checks, allowing greetings like "hi" or "hello" after finishing the quest.

* fix: remove duplicated buy house command (opentibiabr#3476)

* fix: server startup loop on "Running with x threads" step (opentibiabr#3509)

Add dispatcher start validation and loading monitoring
This fixes a loop in the server start (breaks on "Running with 16
threads." step)

Dispatcher:
• Added promise/future in init() to ensure dispatcher thread is fully
started before proceeding.
• Added 5s timeout when waiting for dispatcher initialization.

CanaryServer
• Replaced blocking wait() on LoaderStatus with an active wait loop.
• Added soft warning logs every 2 minutes during startup.
• Added a 10 minutes startup timeout with graceful shutdown on failure.
• Minor cleanup in load order and improved robustness of server start
sequence.

Overall: server startup is now safer, with better feedback if the
process is slow or stuck.

* fix: teleport effect when using rope's and shovel's (opentibiabr#3514)

Remove teleport visual effect when using rope or shovel
After PR opentibiabr#3066, using rope or shovel on any hole triggered a teleport effect, which doesn't happen on Global. This commit fixes that behavior by preventing the effect specifically for these items.

* fix: crash when target is null or removed (opentibiabr#3516)

Fix opentibiabr#3491

* fix/perf: clone items using inbox and market (opentibiabr#3504)

Fix item duplication in inbox and add maxInboxItems limit

• Add maxInboxItems config to limit inbox size
• Add Player::addItemBatchToPaginedContainer for safe, paginated insertion
• Add Game::processItemInsertion to centralize insertion logic
• Prevent item cloning when accepting or canceling market offers
• Handle stackable and non-stackable item edge cases properly

* fix: null target crash in Game::combatChangeHealth (opentibiabr#3522)

Resolves opentibiabr#3520

* fix: crash when player login with wrong vocation (opentibiabr#3523)

* fix: no-pvp only first on the stack can use area spell/rune (opentibiabr#3409)

* new: killer list (opentibiabr#3517)

This way the killer list will show who gave the final hit, who did the
most damage and all other participants, whether monsters or players.

PR Complement: opentibiabr/myaac#134

* fix: spawns npc by time (opentibiabr#3484)

This is a fix where the NPCs were duplicating, they were not adding or
removing them correctly, now there is also no need for the NPC to exist
in the XML because the creation is done when the server starts
everything within the script.

* feat: new release version and fix threadpool shutdown (opentibiabr#3527)

* feat: support to protocol 14.05 (opentibiabr#3164)

Support Tibia 14.05: https://github.com/dudantas/tibia-client/releases/tag/14.05.70ce66

* fix: possible nill value (opentibiabr#3530)

Fixed attempt to compare nil with number.

* fix: ebb and flow memory leak (opentibiabr#3528)

Fix memory leak in Ebb and Flow system causing server crashes

• Fixed critical memory leak related to Ebb and Flow map transitions
• Tracked and cleaned up event callbacks to prevent accumulation
• Managed addEvent timers through a centralized pendingEvents table
• Implemented clearPendingEvents() and unregisterEventCallbacks()
• Ensured proper cleanup before each map change and on server save
• Resolved lingering tile and scope references in anonymous functions
• Maintains default 25 packet/s without lag or instability

Fixes opentibiabr#3373

* fix: correctly ignore irrelevant info for offline players on save (opentibiabr#3538)

This commit fixes a critical issue where partially loaded offline players, loaded using `disableIrrelevantInfo()`, had incomplete data saved back to disk, causing loss of information such as Wheel of Destiny configuration and boosted boss prices.

The solution ensures that player save operations respect the loading context and do not overwrite fields that were not previously loaded. This prevents valid gameplay data from being replaced with empty or default values during background saves.

Fixes opentibiabr#3289.

* fix: items description (opentibiabr#3539)

Fixes opentibiabr#3536

* fix: prevent bug console Creature.checkCreatureInsideDoor (opentibiabr#3535)

* fix: update supply items on supply analyzer (opentibiabr#3544)

* fix: critical damage in single target (opentibiabr#3545)


This change fixes a bug where spells (especially AoE) would occasionally
not apply any damage when the caster and the target were the only
entities on screen. This occurred due to missing critical damage
propagation when only one target was present in the area.

* perf: avoid unnecessary getThis in writeToOutputBuffer (opentibiabr#3548)

This PR optimizes the ProtocolGame::writeToOutputBuffer method by
avoiding the unnecessary creation of shared_from_this() (getThis()) when
already within the dispatcher context.

Previously, the method always called getThis() to capture self, even
when already executing inside the dispatcher, which introduced
significant overhead due to shared_ptr management. Now, the check
g_dispatcher().context().isAsync() ensures that if we're already in the
dispatcher context, the operation is performed immediately and directly,
avoiding the cost of shared_from_this().

This change eliminates the need to create extra shared_ptr instances in
common scenarios, reducing pressure on the reference counting system and
improving overall performance, especially under high load.

* feat: enable canary map editor assets otbm version (opentibiabr#2777)

Dependes from: opentibiabr/remeres-map-editor#70 (opentibiabr/remeres-map-editor@6d501a5)


Enables the read of canary's map editor assets otbm version.

* fix: condition suppression removal logic on equip/de-equip (opentibiabr#3563)

Ensure only relevant condition suppressions are decremented when
de-equipping items. Prevents removing suppressions still active from
other sources.

Fix: opentibiabr#3267

* feat: protocol 14.12 (opentibiabr#3524)

feat: add client and server features for gameplay and UI improvements

- Renamed Supply Stash to Stash and removed depot slot limit count
- Added advanced filters for Stash item categories
- Reworked Cyclopedia Combat Stats into Offense, Defense, and Misc Stats
- Added detailed tooltips and integrated stats into Skills widget
- Introduced Magical Archive interface for spells and runes with filters
- Overhauled Quest Log and Tracker with pinning, search, sort, compact display, and notifications
- Enhanced Exaltation Forge with boots tier bonus and Dust management
- Redesigned Charms System with new Major and Minor charms and balance changes
- Added new mounts and outfits for customization
- Improved server and client behavior with advanced stash, spell archive, detailed stats, and enhanced tier systems
- Verified features through manual and in-game testing

* fix: docker build (opentibiabr#3575)

Docker expects the file to be on the bin folder, so we need to keep this
option enable otherwise we will have to update the docker files to
search for the binary in another place.

* feat: add yasir missing items up to 14.12 (opentibiabr#3581)

Yasir missing items based on https://tibia.fandom.com and few price fixes

* fix: clear player target on logout/removal (opentibiabr#3582)

Fix opentibiabr#3565

* fix: crash on shopPlayers cleanup in closeAllShopWindows (opentibiabr#3604)

Refactors the cleanup logic in Npc::closeAllShopWindows to ensure
shopPlayers is cleared only after all player shop windows are closed.
This prevents iterator invalidation and ensures proper resource
management.

* perf: parallelize player saves via thread pool (opentibiabr#3602)


Parallelises player saving in **SaveManager** via the global BS
thread-pool.
When `TOGGLE_SAVE_ASYNC` is **true** each `doSavePlayer` is queued with
`submit_task`, returning a `future<void>` that is stored alongside the
player’s name/ID. After dispatch, we iterate the vector, call
`future.get()`
and log per-player failures.  
Falls back to the old sequential loop when async is disabled.  
On a multi-core host this trims total save time by ≈ 50 % while still
surfacing exceptions individually.

* feat: new talkaction manage kv (opentibiabr#3502)

Modifications now allow to apply and check the kv of targets.

* feat: new talkaction ban (opentibiabr#3511)

This new ban command allows you to enter the days for the reason, fixed the maximum days bug, checks if the player has already been banned.

* fix: conclusion description Paw and Fur tasks (opentibiabr#3512)

* fix: gamestore exploit (opentibiabr#3515)

Fixed the exploit when holding enter and clicking the buy button multiple times, buying the same item multiple times even though it was charged for each purchase, this was used to stock up on many exp buffs.

* fix: the ape city quest mission 7 (opentibiabr#3532)

* fix: grave danger darashia boss sir nictros (opentibiabr#3533)

* fix: prevent task flood caused by double OTSYS_TIME() subtraction in action delay (opentibiabr#3591)

Fixes a bug where `Game::playerEquipItem` incorrectly subtracted
`OTSYS_TIME()` from a delay that had already been normalized inside
`Player::getNextActionTime()`.
This caused negative or extremely large delay values (up to ~28 days),
which led to the Dispatcher scheduling massive amounts of future tasks
that would never execute.

Over time, this behavior caused exponential growth in the
`Dispatcher::scheduledTasks` queue, consuming memory and degrading
server performance.

* fix: ensure stats are only applied when imbuement is successfully added (opentibiabr#3554)

Apply stat bonuses only after confirming that the imbuement has been
successfully added to the item.

Previously, the stat effects were applied independently of the imbuement
result, allowing bonuses to be granted even when the imbuement
failed—such as due to chance or item incompatibility.

* fix: potential deadlocks in KVStore by enforcing safe lock ordering (opentibiabr#3568)


This fixes potential deadlocks in KVStore caused by lock inversion
between KVStore::mutex_ and Database::recursive_mutex.

The change ensures that all database operations (save, load, loadPrefix)
are executed outside of the KVStore lock, enforcing a consistent lock
hierarchy.

* fix: use-after-free in Lua garbage collection of shared objects (opentibiabr#3553)

This fixes a critical use-after-free issue caused by the premature
destruction of SharedObject instances managed via std::shared_ptr during
Lua’s __gc finalization.

Previously, the luaGarbageCollection function called reset() directly on
the shared pointer, which could destroy the underlying object while it
was still in use by C++ code — potentially leading to heap corruption
and runtime crashes.

* fix: divine empowerment damage bonus (opentibiabr#3607)


Change values for divine empowerment damage bonus

* fix: add missing migration from player death column (opentibiabr#3540)

* fix: podium of renown description (opentibiabr#3558)

* fix: fluids descriptions (opentibiabr#3559)

* fix: candia races and fluids (opentibiabr#3566)

* fix: ramp from temple of the moon goddess (opentibiabr#3567)

* fix: annihilator quest & other monster values (opentibiabr#3580)

* fix: npc flickering soul (opentibiabr#3589)

* fix: grand master oberon messages (opentibiabr#3593)

* fix: low blow appearing twice in server log (opentibiabr#3573)

* fix: familiar cooldown (opentibiabr#3569)

Familiar was getting cooldown even when there was an error in the
summoning.

* fix: avoid duplicated call onrefreshCyclopediaMonsterTracker method (opentibiabr#3603)

• Introduced a new method isMonsterOnBestiaryTracker to verify if a
monster is currently tracked before sending updates
• Updated bestiary and bosstiary kill handlers to refresh the client
tracker only when the slain monster is part of the player’s tracking set

* fix: show more than one creature icon (opentibiabr#3610)


This change is intended to improve the visualization of creature icons
and make the player's life easier.

Today, creature icons only show the last "spell" that player use to
debuff/turn melee or if has Influenced/Fiendish do not change to your
debuff spell

Now up to three icons are displayed on monsters (Client limitations) in
`ProtocolGame::addCreatureIcon`

* fix: add tile null checks in combat and spell logic (opentibiabr#3614)

Added explicit null checks for tile pointers in combat and spell
functions to prevent invalid access. Improved error handling and logging
when spells are cast on invalid tiles, providing better feedback to
players and easier debugging.

* fix: add null and bounds checks in replaceThing method (opentibiabr#3615)

Added checks to ensure the 'thing' pointer is not null and the index is
within the bounds of 'itemlist' before proceeding in
Container::replaceThing. This prevents potential crashes or undefined
behavior due to invalid input.

* fix: add missing ON DELETE CASCADE (opentibiabr#3590)

* feat: add Nimmersats Dragons spawns (opentibiabr#3613)

* feat: add candia spawn (opentibiabr#3617)

* feat: add missing attributes to new helmets (opentibiabr#3621)

* fix: double destruction in Lua __gc for shared_ptr userdata (opentibiabr#3623)

Avoids premature object destruction by removing explicit reset() call.
Now only destroys and reconstructs the shared_ptr using placement new,
ensuring safe and idempotent cleanup when Lua triggers __gc multiple
times.

* enhancement: add ability to give minor charms to players as god (opentibiabr#3622)

* enhancement: add winged druid outfit to store (opentibiabr#3624)

* enhancement: delete duplicated /raid talkaction (opentibiabr#3626)

* fix: outfit monster value (opentibiabr#3627)

* fix: wrong ids of two items of black bert (opentibiabr#3628)

* fix: exit destination of gnomprona boss tp (opentibiabr#3630)

* fix: add coordinate validation in getTile method (opentibiabr#3631)

* enhancement: add buy bulk of carpets and fix magic carpet mount description (opentibiabr#3632)

* fix: reset exp boosts at server initialization (opentibiabr#3633)

* feat: dancing fairy action (opentibiabr#3636)

Added the dancing fairy's transform function, along with its
achievement.

* feat: birdcage (opentibiabr#3640)

* improve creature pushing (opentibiabr#3637)

Fixed a potential infinite loop, added null checks, and made creature
pushing safer by looping backwards.

- Switched to a reverse loop (for (i = size - 1; i >= 0; --i)) so that
moving creatures doesn’t mess up the indexes. (memyleak)
- Added safety checks for tile, the creature list, and individual
creature. (crash)
- after pushing or killing a monster, the code won’t accidentally
process the same creature again. (loop).

* improve: monster push items (opentibiabr#3638)

Added null checks and a removeCount limit to prevent stability issues.

* feat: azzilon (opentibiabr#3634)

* Fix: A-Z order GetAllKv (opentibiabr#3643)

It's a very simple modification to make all the kvs return in alphabetical order to improve the way they are viewed.

* fix: arbaziloth boss (opentibiabr#3647)

* fix: timira boss reward (opentibiabr#3649)

* fix: gloothomotive mount item (opentibiabr#3650)

Using Wind-up Key on a Wind-up Loco give you the Gloothomotive mount.

* fix: ferumbras ascension quest (opentibiabr#3646)

* enhancement: set boss cooldown when teleporting players to boss rooms (opentibiabr#3652)

This adds the cooldowns to all players entering to a boss and it will display the boss in Boss Cooldowns window.

* fix: the unwelcome boss room (opentibiabr#3653)

* fix: boss race id for ascending ferumbras (opentibiabr#3654)

* fix: library final boss room access teleports (opentibiabr#3655)

* fix: entrance to bakragore boss (opentibiabr#3656)

* fix: delete requirement of exact players to start cults of tibia bosses (opentibiabr#3657)

* fix: update outfit cache storage reference for golden outfit (opentibiabr#3658)

* fix: update quaidDen ID for grave danger quest (opentibiabr#3659)

* fix: spirit of purity mount (opentibiabr#3661)

* enhancement: add functionality to items used to obtain the second familiar (opentibiabr#3662)

* enhancement: add reported missing corpses (opentibiabr#3663)

* Add apply.patch with git apply instructions

Introduces apply.patch containing commands for applying patches using git, including options for handling whitespace and force updating.

* improve: refactor and extend Benchmark utility (opentibiabr#3665)

Moved Benchmark implementation from header to new benchmark.cpp file,
improving code organization. Added logging methods to Benchmark and
updated CMake and Visual Studio project files to include the new source
file.

* fix: underflow in container slot search for non-stackables (opentibiabr#3667)

Refactored the loop that searches for an empty slot in containers for
non-stackable items to prevent unsigned underflow and infinity loops.
The new implementation iterates from 0 to container capacity, ensuring
safe and correct behavior when the container is full.

* fix: destinations of rotten blood bosses exits (opentibiabr#3670)

* fix: remove spirit of purity mount from store (opentibiabr#3673)

* chore(macos): setup compilation on macos/clang (opentibiabr#3671)

Sets up compilation for macOS with the clang compiler. Had to fix some
issues with type casting for lua/database and hit a few warnings along
the way so fixed those as well.

# Changes
- Added `macos-*` presets
- Added macos github workflow
- Fixes a few high-priority clang warnings

* refactor: test setup and improve test isolation (opentibiabr#3676)

Stabilize unit tests on Windows MSVC and improve test isolation.

Fix intermittent crashes caused by the Boost UTest JUnit reporter holding a string view to temporary test names.
Use a static vector of strings for test names in position functions tests and static const cases in string functions tests.
Refactor dependency injection using a single static injector and a fresh helper for clean, per-test fixtures.
Update CMake to add build tests definition and standardize test invocation and reporting.
Disable Unity and lto for test targets on MSVC to keep predictable debug stacks.
Adjusted the memory account repository to deduplicate by ID before insert.
Minor cleanups in test naming, case handling, and expectations;

Tests now run deterministically on MSVC and Linux/MacOS without flakiness.

* chore: setup ctest from root (opentibiabr#3677)

Makes running test with `ctest` a bit easier.

Key changesL
- drop `*-test` build/config presets to simplify setup
- `*-debug` presets now always build in testing
- added test presets for `*-debug` that can be used with `ctest`

## Running tests

Tests can be run directly from the repository root using CMake test
presets:

```bash
# Configure and build tests for your platform
cmake --preset linux-debug && cmake --build --preset linux-debug

# Run all tests
ctest --preset linux-debug

# For other platforms use:
# ctest --preset macos-debug
# ctest --preset windows-debug
```

* refactor: DI usage in tests and improve integration test logic (opentibiabr#3678)

• Enable integration tests in CI for macOS, Ubuntu, and Windows with
ctest steps for unit and integration
• Update tests/build_and_run.sh to also run integration tests
• Refactor account integration tests into a dedicated file with its own
subdirectory and CMakeLists
• Add test_database.hpp and .env-based DB initialization with OS
environment precedence and required password
• Define TESTS_ENV_DEFAULT in CMake and provide tests/test.env as a
default config
• Use DI in tests with InMemoryLogger installed via injector and access
Database and Logger through DI
• Improve time handling and assertions using getTimeNow and approx for
premium and creation fields
• Organize AccountRepositoryDB suite in a dedicated namespace with
modular test registration functions
• Adjust log checks to validate the latest error message and clear the
log buffer before tests
• Wrap each test in BEGIN and ROLLBACK and add explicit
DatabaseException handling
• Fix and consolidate cases for saving accounts and syncing
premiumDaysPurchased from premiumRemainingDays
• Normalize size and type assertions, use references in assert helpers,
and apply clang-format

* improve: refactor storages in PlayerStorage component and optimized save (opentibiabr#3664)

The Player has previously managed the storage system through a raw
storageMap, with direct insertions, deletions, and range generation
(genReservedStorageRange). This change caused unnecessary complete
rewrites on save and spreads logic across Player, IOLoginData, and
related components.

Changes
- Introduced a new PlayerStorage component to encapsulate all
storage-related logic
- Removed the legacy storageMap from Player, centralizing load/save and
manipulation in the new component
- Implemented incremental persistence: only modified or removed keys are
saved to the database, avoiding complete rewrites
- Added support for reserved key ranges (outfits, familiars) within
PlayerStorage::getReservedRange
- Updated IOLoginDataLoad and IOLoginDataSave to delegate load/save to
PlayerStorage
- Added missing benchmark.cpp implementation and updated build files
accordingly
- Removed storage name in favor of KV.

This change refactor improves code organization, maintainability, and
performance. By persisting only modified keys instead of the full
storage set, save operations are faster and reduce unnecessary database
load.

* fix: operator precedence and minor code cleanup (opentibiabr#3679)

Corrected operator precedence in conditional statements in player.cpp
and game.cpp to ensure proper logic evaluation. Removed unused variable
in protocolgame.cpp and clarified unused parameter in cylinder.hpp.

* fix: missing return after unknown immunity in Lua functions (opentibiabr#3669)

Adds a missing 'return 1;' after pushing nil to the Lua stack when an
unknown immunity name is encountered in luaMonsterTypeCombatImmunities
and luaMonsterTypeConditionImmunities. This prevents further code
execution in error cases and ensures correct Lua behavior.

* refactor: KVStore eviction and add deleted key filtering (opentibiabr#3651)

Refactored the eviction logic in KVStore to defer persistence of evicted
entries, improving thread safety and efficiency. Added processEvictions
method and updated flush to persist both in-memory and pending
evictions. The keys() method now skips deleted entries, and a new unit
test verifies this behavior.

* fix: only push player if vocation is valid (opentibiabr#3648)

This pull request updates the logic for populating the list of players
in the `PlayerBadge::getPlayersInfoByAccount` method. Now, only players
for whom `setVocation` succeeds are added to the result list, which
helps ensure data integrity.

* refactor: player login container and hotkey handling (opentibiabr#3680)

Removed protocol version checks and open container logic from
IOLoginDataLoad, moving container opening to
ProtocolGame::sendAddCreature for all logins. Also removed the unused
sendHotkeyPreset function and its call, simplifying login flow and
improving code clarity. Fixed Lua event callback functions to return
correct values on error.

Fix: opentibiabr#3611

* fix: type safety on raid checks (opentibiabr#3675)

Ensure the database state is initialized to avoid RAID check exceptions.
Otherwise, errors like the following can occur:

[2025-31-08 09:34:43.520] [thread 140345198] [error] Lua Script Error Detected
---------------------------------------
Interface: Scripts Interface
Script ID: data/scripts/globalevents/raids.lua:callback
Error Description: data/libs/systems/raids.lua:87: attempt to perform arithmetic on local 'checksToday' (a nil value)
stack traceback:
        [C]: in function '__add'
        data/libs/systems/raids.lua:87: in function 'canStart'
        data/libs/systems/raids.lua:51: in function 'tryStart'
        data/scripts/globalevents/raids.lua:11: in function <data/scripts/globalevents/raids.lua:5>
---------------------------------------

* chore: add cmake-format and cmake-lint (opentibiabr#3672)

 This change sets up cmake-format to auto-fix PRs with the GHA workflow.

* fix: post merge fixes

* fix: dialog system fixes

* fix: rename migrations

* fix: most merge fixes

* docs: update docs

* refactor: questlog messages building; naming

* fix: correctly store tracked missions

* fix: avoid client crash by using items.xml weapon definition

* fix: post merge fixes

---------

Co-authored-by: mdbeng <37564938+mdbeng@users.noreply.github.com>
Co-authored-by: Júlio César Ueti <52474532+Mirino97@users.noreply.github.com>
Co-authored-by: Eduardo Dantas <eduardo.dantas@hotmail.com.br>
Co-authored-by: Ricardo Queiroz (Kaky) <64594117+ricardokaky@users.noreply.github.com>
Co-authored-by: gabrielgg98 <133166574+gabrielgg98@users.noreply.github.com>
Co-authored-by: Leilani A. <168607226+kaleohanopahala@users.noreply.github.com>
Co-authored-by: LeoTK <41605307+LeoTKBR@users.noreply.github.com>
Co-authored-by: murilo09 <78226931+murilo09@users.noreply.github.com>
Co-authored-by: Uriel Isordia <uisordia@gmail.com>
Co-authored-by: Renato Machado <mehahx@gmail.com>
Co-authored-by: Pedro Cruz <phac@cin.ufpe.br>
Co-authored-by: Renato Foot Guimarães Costallat <costallat@hotmail.com>
Co-authored-by: InVoidEcho <invoidecho@gmail.com>
Co-authored-by: Destroyyy007 <123918205+Destroyyy007@users.noreply.github.com>
Co-authored-by: fugu320 <rabirabit316@gmail.com>
Co-authored-by: Gabriel Alcântara Bernardes <gabrielalcantaratp@gmail.com>
Co-authored-by: Bruno Luís Lucarelo Lamonato <brunolamonato@gmail.com>
Co-authored-by: Victor <vasconcellosdevictor@gmail.com>
Co-authored-by: Majesty <32709570+majestyotbr@users.noreply.github.com>
Co-authored-by: Goosey <raklatif@gmail.com>
Co-authored-by: Slawomir Boczek <slawkens@gmail.com>
Co-authored-by: Luis Pablo <luis.pablo.lopez.lopez@uabc.edu.mx>
Co-authored-by: Robert Rodriguez <165123587+jbracovich@users.noreply.github.com>
Co-authored-by: Luan Santos <git@luan.sh>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants