From 5f84c28241cfff9fef86114ee52c66bdee1f64c1 Mon Sep 17 00:00:00 2001 From: H0zen Date: Sat, 3 Oct 2026 02:52:05 +0300 Subject: [PATCH 1/3] [AH] Auction house bot and service as modules Rule: every module has, and must have, its own .conf, whose first key is Enable; it is installed with the module. mangosd.conf knows no module. Core: - Add AuctionHouseModule / AuctionHouseModules (src/game/Object/AuctionHouseModule.h): lifecycle, commands, book queries and request hooks; modules register from a static object, the core never names one. - AuctionHouseHandler, AuctionHouseMgr, Mail, World, WorldConfig, WorldSession, ObjectMgr, Player: drop every AH service branch, type and setting; call the module hooks instead. - Remove the forged "AuctionHouse" bot owner (GUID 0xFFFFFFFE). - Player::CanUseItem checks inline again (no AhUsabilityRef). - ChatCommand takes a free-function handler; module command tables are merged into the root table, sorted by name. - MailDraft::SendMailToInTransaction takes a plain list of after-commit effects. - mangosd: -t runs tests registered with RegisterMangosdTest; -a sets the bot config file through AuctionHouseModules; modules stop after the maps unload. - mangosd.conf: no AH service keys; ConfVersion bumped. Modules: - src/modules/AuctionHouseBot: the in-process bot, BUILD_AHBOT (default ON), Enable as the first key of ahbot.conf (ConfVersion bumped), .ahbot commands. - src/modules/AhService: IPC, worker, custody, intent executor, .ah commands and the self-tests, BUILD_AH_SERVICE (default OFF), all its keys in ah-service.conf with Enable first (AH.Service.Enabled is now AH.Service.Worker; AH.Service.Config is gone, the worker gets the same file). - .ah reload and .ah status take over the service parts of .ahbot reload/status. - The playerbots' ike3 AhBot (src/modules/Bots/ahbot) is no longer built; src/modules/Bots/AhBotPrices.cpp answers its price queries as before (0, 0, 1.0). Fixes: - Cancelling an auction no longer aborts the server: the mails were sent inside the open transaction and opened a nested one (MANGOS_ASSERT). They now write into it and their live effects run after the commit. - AuctionHouseBot seller prices: 64-bit math, saturated to uint32 (was a 32-bit wrap and an out-of-range conversion). Docs: - CLAUDE.md, extra/doc/AuctionHouseBot.md, src/modules/AhService/README.md. - KNOWN_DEFECTS.md in both modules, from the review of the split. Co-Authored-By: Claude Opus 5.5 --- .codacy.yml | 2 +- CLAUDE.md | 13 +- CMakeLists.txt | 5 +- cmake/MangosParams.cmake | 4 +- extra/doc/AuctionHouseBot.md | 335 +- src/CMakeLists.txt | 13 +- src/game/AuctionHouseBot/AhBotSystemOwner.h | 36 - src/game/CMakeLists.txt | 19 +- src/game/ChatCommands/AHBotCommands.cpp | 344 - .../ChatCommands/AuctionHouseCommands.cpp | 24 +- src/game/Object/AuctionHouseMgr.cpp | 960 +-- src/game/Object/AuctionHouseMgr.h | 105 +- src/game/Object/AuctionHouseModule.cpp | 164 + src/game/Object/AuctionHouseModule.h | 175 + src/game/Object/ObjectGuid.cpp | 8 - src/game/Object/ObjectMgr.cpp | 57 +- src/game/Object/ObjectMgrAreaTrigger.cpp | 1 - src/game/Object/ObjectMgrCreatures.cpp | 1 - src/game/Object/ObjectMgrGameObjectInfo.cpp | 1 - src/game/Object/ObjectMgrGameObjects.cpp | 1 - src/game/Object/ObjectMgrGameTele.cpp | 1 - src/game/Object/ObjectMgrGossipMenu.cpp | 1 - src/game/Object/ObjectMgrGraveyard.cpp | 1 - src/game/Object/ObjectMgrInstanceData.cpp | 1 - src/game/Object/ObjectMgrItems.cpp | 1 - src/game/Object/ObjectMgrLocaleStrings.cpp | 1 - src/game/Object/ObjectMgrLocales.cpp | 1 - src/game/Object/ObjectMgrNameCheck.cpp | 28 - src/game/Object/ObjectMgrPlayerInfo.cpp | 1 - src/game/Object/ObjectMgrQuestRelations.cpp | 1 - src/game/Object/ObjectMgrQuests.cpp | 1 - src/game/Object/ObjectMgrReputation.cpp | 1 - src/game/Object/ObjectMgrSpellData.cpp | 1 - src/game/Object/ObjectMgrTaxi.cpp | 1 - src/game/Object/ObjectMgrText.cpp | 1 - src/game/Object/ObjectMgrTrainerVendor.cpp | 1 - src/game/Object/Player.cpp | 16 - src/game/Object/Player.h | 17 - src/game/Object/PlayerItemValidation.cpp | 180 +- src/game/Server/WorldSession.h | 32 +- .../WorldHandlers/AuctionHouseHandler.cpp | 3345 +-------- src/game/WorldHandlers/Chat.cpp | 104 +- src/game/WorldHandlers/Chat.h | 39 +- src/game/WorldHandlers/ChatArgExtract.cpp | 1 - src/game/WorldHandlers/ChatHelp.cpp | 1 - src/game/WorldHandlers/ChatMessage.cpp | 1 - .../WorldHandlers/ChatMessageValidation.cpp | 1 - src/game/WorldHandlers/Mail.cpp | 55 +- src/game/WorldHandlers/Mail.h | 18 +- src/game/WorldHandlers/MailHandler.cpp | 11 - src/game/WorldHandlers/World.cpp | 532 +- src/game/WorldHandlers/World.h | 97 - src/game/WorldHandlers/WorldConfig.cpp | 63 +- src/game/WorldHandlers/WorldSessionMgr.cpp | 10 - src/mangosd/AhService.h | 111 - src/mangosd/CMakeLists.txt | 2 - src/mangosd/MangosdTest.cpp | 6633 +---------------- src/mangosd/MangosdTest.h | 5 + src/mangosd/Master.cpp | 13 +- src/mangosd/mangosd.conf.dist.in | 82 - src/mangosd/mangosd.cpp | 4 +- src/modules/AhService/CMakeLists.txt | 50 + src/modules/AhService/KNOWN_DEFECTS.md | 469 ++ src/modules/AhService/README.md | 332 + .../AhService}/ipc/AuctionIntents.h | 0 .../AhService}/ipc/BoundedQueue.h | 0 .../AhService}/ipc/BrowseMessages.h | 0 .../AhService}/ipc/CMakeLists.txt | 0 .../AhService}/ipc/IpcChannel.cpp | 0 src/{ => modules/AhService}/ipc/IpcChannel.h | 0 .../AhService}/ipc/IpcClientHandler.cpp | 0 .../AhService}/ipc/IpcClientHandler.h | 0 src/{ => modules/AhService}/ipc/IpcLink.h | 0 .../AhService}/ipc/IpcMessage.cpp | 0 src/{ => modules/AhService}/ipc/IpcMessage.h | 0 src/{ => modules/AhService}/ipc/IpcOpcodes.h | 0 .../AhService}/ipc/IpcProcess.cpp | 0 src/{ => modules/AhService}/ipc/IpcProcess.h | 0 src/{ => modules/AhService}/ipc/IpcReliable.h | 0 .../AhService}/ipc/IpcServerHandler.cpp | 0 .../AhService}/ipc/IpcServerHandler.h | 0 src/{ => modules/AhService}/ipc/IpcSocket.cpp | 0 src/{ => modules/AhService}/ipc/IpcSocket.h | 0 src/{ => modules/AhService}/ipc/IpcThread.cpp | 0 src/{ => modules/AhService}/ipc/IpcThread.h | 0 .../AhService}/ipc/IpcVersion.cpp | 0 src/{ => modules/AhService}/ipc/IpcVersion.h | 0 .../AhService}/ipc/PlayerMutations.h | 0 .../AhService}/ipc/WorkerSupervisor.cpp | 0 .../AhService}/ipc/WorkerSupervisor.h | 0 .../AhService/tests/AhServiceTests.cpp | 6449 ++++++++++++++++ .../worker}/AhBotDefines.h | 0 .../worker}/AuctionBook.cpp | 0 .../worker}/AuctionBook.h | 0 .../worker}/BotBrain.cpp | 0 .../{AhWorker => AhService/worker}/BotBrain.h | 0 .../worker}/BrowseHandler.cpp | 0 .../worker}/BrowseHandler.h | 0 .../worker}/CMakeLists.txt | 9 +- .../{AhWorker => AhService/worker}/Console.h | 0 .../worker}/Console_posix.cpp | 0 .../worker}/Console_win.cpp | 0 .../worker}/ItemInstanceFields.cpp | 0 .../worker}/ItemInstanceFields.h | 0 .../worker}/ItemPool.cpp | 0 .../{AhWorker => AhService/worker}/ItemPool.h | 0 .../worker}/Journal.cpp | 0 .../{AhWorker => AhService/worker}/Journal.h | 0 .../{AhWorker => AhService/worker}/Main.cpp | 0 .../worker}/MarketSnapshot.cpp | 0 .../worker}/MarketSnapshot.h | 0 .../worker}/MutationHandler.cpp | 0 .../worker}/MutationHandler.h | 0 .../worker}/ServiceConfig.cpp | 0 .../worker}/ServiceConfig.h | 0 .../worker}/ServiceDatabase.cpp | 0 .../worker}/ServiceDatabase.h | 0 .../worker}/Usability.cpp | 0 .../worker}/Usability.h | 0 .../worker}/ah-service.conf.dist.in | 82 + .../worker}/difftest/AhUsabilityDiffTest.cpp | 2 +- .../worker/difftest}/AhUsabilityRef.cpp | 0 .../worker/difftest}/AhUsabilityRef.h | 0 .../worker}/difftest/CMakeLists.txt | 5 +- .../worker}/tools/custody_crash_test.md | 0 .../worker}/tools/sp2_differential.md | 0 src/modules/AhService/world/AhService.cpp | 122 + src/modules/AhService/world/AhService.h | 99 + src/modules/AhService/world/AhServiceBook.cpp | 964 +++ src/modules/AhService/world/AhServiceBook.h | 92 + .../AhService/world}/AhServiceCommands.cpp | 169 +- .../AhService/world/AhServiceCommands.h | 34 + .../AhService/world/AhServiceHandlers.cpp | 3026 ++++++++ .../AhService/world/AhServiceHandlers.h | 50 + .../AhService/world/AhServiceModule.cpp | 188 + .../AhService/world/AhServiceWorld.cpp | 497 ++ src/modules/AhService/world/AhServiceWorld.h | 43 + .../world}/AuctionIntentExecutor.cpp | 17 +- .../AhService/world}/AuctionIntentExecutor.h | 0 .../AhService/world}/BrowsePending.cpp | 0 .../AhService/world}/BrowsePending.h | 0 .../AhService/world}/CustodyDeferred.h | 34 - .../AhService/world}/CustodyLedger.cpp | 0 .../AhService/world}/CustodyLedger.h | 0 .../AhService/world}/CustodyReconciler.cpp | 0 .../AhService/world}/CustodyReconciler.h | 0 .../AhService/world}/CustodyService.cpp | 10 +- .../AhService/world}/CustodyService.h | 0 .../AhService/world}/MutationPending.cpp | 0 .../AhService/world}/MutationPending.h | 0 .../AuctionHouseBot/AuctionHouseBot.cpp | 63 +- .../AuctionHouseBot/AuctionHouseBot.h | 14 +- .../AuctionHouseBotCommands.cpp | 267 + .../AuctionHouseBot/AuctionHouseBotCommands.h | 34 + .../AuctionHouseBot/AuctionHouseBotModule.cpp | 109 + src/modules/AuctionHouseBot/CMakeLists.txt | 38 + src/modules/AuctionHouseBot/KNOWN_DEFECTS.md | 29 + .../AuctionHouseBot/ahbot.conf.dist.in | 12 +- src/modules/Bots/AhBotPrices.cpp | 64 + src/modules/CMakeLists.txt | 12 +- 160 files changed, 14054 insertions(+), 13015 deletions(-) delete mode 100644 src/game/AuctionHouseBot/AhBotSystemOwner.h delete mode 100644 src/game/ChatCommands/AHBotCommands.cpp create mode 100644 src/game/Object/AuctionHouseModule.cpp create mode 100644 src/game/Object/AuctionHouseModule.h delete mode 100644 src/mangosd/AhService.h create mode 100644 src/modules/AhService/CMakeLists.txt create mode 100644 src/modules/AhService/KNOWN_DEFECTS.md create mode 100644 src/modules/AhService/README.md rename src/{ => modules/AhService}/ipc/AuctionIntents.h (100%) rename src/{ => modules/AhService}/ipc/BoundedQueue.h (100%) rename src/{ => modules/AhService}/ipc/BrowseMessages.h (100%) rename src/{ => modules/AhService}/ipc/CMakeLists.txt (100%) rename src/{ => modules/AhService}/ipc/IpcChannel.cpp (100%) rename src/{ => modules/AhService}/ipc/IpcChannel.h (100%) rename src/{ => modules/AhService}/ipc/IpcClientHandler.cpp (100%) rename src/{ => modules/AhService}/ipc/IpcClientHandler.h (100%) rename src/{ => modules/AhService}/ipc/IpcLink.h (100%) rename src/{ => modules/AhService}/ipc/IpcMessage.cpp (100%) rename src/{ => modules/AhService}/ipc/IpcMessage.h (100%) rename src/{ => modules/AhService}/ipc/IpcOpcodes.h (100%) rename src/{ => modules/AhService}/ipc/IpcProcess.cpp (100%) rename src/{ => modules/AhService}/ipc/IpcProcess.h (100%) rename src/{ => modules/AhService}/ipc/IpcReliable.h (100%) rename src/{ => modules/AhService}/ipc/IpcServerHandler.cpp (100%) rename src/{ => modules/AhService}/ipc/IpcServerHandler.h (100%) rename src/{ => modules/AhService}/ipc/IpcSocket.cpp (100%) rename src/{ => modules/AhService}/ipc/IpcSocket.h (100%) rename src/{ => modules/AhService}/ipc/IpcThread.cpp (100%) rename src/{ => modules/AhService}/ipc/IpcThread.h (100%) rename src/{ => modules/AhService}/ipc/IpcVersion.cpp (100%) rename src/{ => modules/AhService}/ipc/IpcVersion.h (100%) rename src/{ => modules/AhService}/ipc/PlayerMutations.h (100%) rename src/{ => modules/AhService}/ipc/WorkerSupervisor.cpp (100%) rename src/{ => modules/AhService}/ipc/WorkerSupervisor.h (100%) create mode 100644 src/modules/AhService/tests/AhServiceTests.cpp rename src/modules/{AhWorker => AhService/worker}/AhBotDefines.h (100%) rename src/modules/{AhWorker => AhService/worker}/AuctionBook.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/AuctionBook.h (100%) rename src/modules/{AhWorker => AhService/worker}/BotBrain.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/BotBrain.h (100%) rename src/modules/{AhWorker => AhService/worker}/BrowseHandler.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/BrowseHandler.h (100%) rename src/modules/{AhWorker => AhService/worker}/CMakeLists.txt (90%) rename src/modules/{AhWorker => AhService/worker}/Console.h (100%) rename src/modules/{AhWorker => AhService/worker}/Console_posix.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/Console_win.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/ItemInstanceFields.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/ItemInstanceFields.h (100%) rename src/modules/{AhWorker => AhService/worker}/ItemPool.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/ItemPool.h (100%) rename src/modules/{AhWorker => AhService/worker}/Journal.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/Journal.h (100%) rename src/modules/{AhWorker => AhService/worker}/Main.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/MarketSnapshot.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/MarketSnapshot.h (100%) rename src/modules/{AhWorker => AhService/worker}/MutationHandler.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/MutationHandler.h (100%) rename src/modules/{AhWorker => AhService/worker}/ServiceConfig.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/ServiceConfig.h (100%) rename src/modules/{AhWorker => AhService/worker}/ServiceDatabase.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/ServiceDatabase.h (100%) rename src/modules/{AhWorker => AhService/worker}/Usability.cpp (100%) rename src/modules/{AhWorker => AhService/worker}/Usability.h (100%) rename src/modules/{AhWorker => AhService/worker}/ah-service.conf.dist.in (61%) rename src/modules/{AhWorker => AhService/worker}/difftest/AhUsabilityDiffTest.cpp (99%) rename src/{game/Object => modules/AhService/worker/difftest}/AhUsabilityRef.cpp (100%) rename src/{game/Object => modules/AhService/worker/difftest}/AhUsabilityRef.h (100%) rename src/modules/{AhWorker => AhService/worker}/difftest/CMakeLists.txt (85%) rename src/modules/{AhWorker => AhService/worker}/tools/custody_crash_test.md (100%) rename src/modules/{AhWorker => AhService/worker}/tools/sp2_differential.md (100%) create mode 100644 src/modules/AhService/world/AhService.cpp create mode 100644 src/modules/AhService/world/AhService.h create mode 100644 src/modules/AhService/world/AhServiceBook.cpp create mode 100644 src/modules/AhService/world/AhServiceBook.h rename src/{game/ChatCommands => modules/AhService/world}/AhServiceCommands.cpp (79%) create mode 100644 src/modules/AhService/world/AhServiceCommands.h create mode 100644 src/modules/AhService/world/AhServiceHandlers.cpp create mode 100644 src/modules/AhService/world/AhServiceHandlers.h create mode 100644 src/modules/AhService/world/AhServiceModule.cpp create mode 100644 src/modules/AhService/world/AhServiceWorld.cpp create mode 100644 src/modules/AhService/world/AhServiceWorld.h rename src/{game/AuctionHouseBot => modules/AhService/world}/AuctionIntentExecutor.cpp (99%) rename src/{game/AuctionHouseBot => modules/AhService/world}/AuctionIntentExecutor.h (100%) rename src/{game/AuctionHouseBot => modules/AhService/world}/BrowsePending.cpp (100%) rename src/{game/AuctionHouseBot => modules/AhService/world}/BrowsePending.h (100%) rename src/{game/AuctionHouseBot => modules/AhService/world}/CustodyDeferred.h (67%) rename src/{game/AuctionHouseBot => modules/AhService/world}/CustodyLedger.cpp (100%) rename src/{game/AuctionHouseBot => modules/AhService/world}/CustodyLedger.h (100%) rename src/{game/AuctionHouseBot => modules/AhService/world}/CustodyReconciler.cpp (100%) rename src/{game/AuctionHouseBot => modules/AhService/world}/CustodyReconciler.h (100%) rename src/{game/AuctionHouseBot => modules/AhService/world}/CustodyService.cpp (97%) rename src/{game/AuctionHouseBot => modules/AhService/world}/CustodyService.h (100%) rename src/{game/AuctionHouseBot => modules/AhService/world}/MutationPending.cpp (100%) rename src/{game/AuctionHouseBot => modules/AhService/world}/MutationPending.h (100%) rename src/{game => modules}/AuctionHouseBot/AuctionHouseBot.cpp (98%) rename src/{game => modules}/AuctionHouseBot/AuctionHouseBot.h (97%) create mode 100644 src/modules/AuctionHouseBot/AuctionHouseBotCommands.cpp create mode 100644 src/modules/AuctionHouseBot/AuctionHouseBotCommands.h create mode 100644 src/modules/AuctionHouseBot/AuctionHouseBotModule.cpp create mode 100644 src/modules/AuctionHouseBot/CMakeLists.txt create mode 100644 src/modules/AuctionHouseBot/KNOWN_DEFECTS.md rename src/{game => modules}/AuctionHouseBot/ahbot.conf.dist.in (95%) create mode 100644 src/modules/Bots/AhBotPrices.cpp diff --git a/.codacy.yml b/.codacy.yml index a184e7151f..094f6deb22 100644 --- a/.codacy.yml +++ b/.codacy.yml @@ -14,7 +14,7 @@ # IS NUL-terminated, and no core calls that overload at all -- every one of them uses # the two-iterator form. # -# src/modules/{Bots,AhWorker} are deliberately absent: they are in-tree, they +# src/modules/{Bots,AuctionHouseBot,AhService} are deliberately absent: they are in-tree, they # are ours, and they are analysed. exclude_paths: - "dep/**" diff --git a/CLAUDE.md b/CLAUDE.md index 3e796c801e..4ae83a2c0a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -12,7 +12,8 @@ this repo. Humans: also read [`doc/CodingStandard.md`](doc/CodingStandard.md). `Rel##_##_###_*.sql` migrations that chain via `db_version`. - Clone/update **recursively**: `dep`, `src/realmd`, `src/modules/{SD3,Eluna}`, `src/tools/Extractor_projects` and `win` are submodules. Never shallow-update a submodule to a non-tip pinned SHA. -- Less-obvious locations: out-of-process services in `src/ipc/` + `src/ah-service/`; scripting in +- Less-obvious locations: auction modules in `src/modules/AuctionHouseBot/` and `src/modules/AhService/` + (registered through `src/game/Object/AuctionHouseModule.h`); scripting in `src/modules/` (Eluna = Lua, SD3 = C++, Bots = playerbots). ## Build & test @@ -34,7 +35,7 @@ make -j"$(nproc)" && make install -j"$(nproc)" Windows: use the EasyBuild helper in `win/`. **A PR MUST keep CI green:** the Linux build compiles with **both** GCC and Clang, Windows builds on AppVeyor, and Codacy/CodeFactor gate quality. If you touch -`src/ipc/` or `src/ah-service/`, keep `ah-service --selftest` passing (it must print `intent codec selftest OK` +`src/modules/AhService/`, keep `ah-service --selftest` passing (it must print `intent codec selftest OK` and `ipc selftest OK`). ## Code style @@ -56,9 +57,11 @@ Source of truth: [`doc/CodingStandard.md`](doc/CodingStandard.md). Non-default r ## Architecture note -The **in-process AuctionHouseBot is the default**; the out-of-process AH service is additive and default-off -(`AH.Service.Enabled`). `mangosd` is the **sole authority** over game state — worker/service "intents" are -re-validated server-side before they are applied. +Auction house extras are **modules**: the core knows only `AuctionHouseModule` and never names one. Each +module is a CMake option (`BUILD_AHBOT`, default on; `BUILD_AH_SERVICE`, default off), brings its own +`.conf` whose first key is `Enable`, and registers itself from a static object. The playerbots' ike3 AhBot +(`src/modules/Bots/ahbot/`) is not built; `src/modules/Bots/AhBotPrices.cpp` answers its price queries. `mangosd.conf` stays module-agnostic. `mangosd` is the **sole authority** over game state — +worker/service "intents" are re-validated server-side before they are applied. ## Review focus (for `@claude`) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ea7e48c27..4e4360baa6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,7 +73,8 @@ option(PCH "Enable precompiled headers" ON) option(WITH_IO_URING "Use the io_uring network backend (Linux, needs liburing)" OFF) option(DEBUG "Enable debug build (only on non IDEs)" OFF) option(WITHOUT_GIT "Disable Git revision detection" OFF) -option(BUILD_AH_SERVICE "Build the out-of-process auction-house service" ON) +option(BUILD_AHBOT "Build the auction house bot module" ON) +option(BUILD_AH_SERVICE "Build the out-of-process auction house service module" OFF) option(WITH_TESTS "Build the unit tests" OFF) option(WITH_NET_TESTS "Build the socket tests (slow; never in CI)" OFF) #================================================================================== @@ -99,6 +100,8 @@ message( SCRIPT_LIB_SD3 Compile with support for ScriptDev3 scripts Modules: PLAYERBOTS Enable Player Bots + BUILD_AHBOT Build the auction house bot module + BUILD_AH_SERVICE Build the out-of-process auction house service module To set an option simply type -D