diff --git a/doc/DoomGame.md b/doc/DoomGame.md index e53aa8bfa..e8ee8859b 100644 --- a/doc/DoomGame.md +++ b/doc/DoomGame.md @@ -530,7 +530,7 @@ See also: ## GameVariables methods --- -### `getAvailableGameVariable` +### `getAvailableGameVariables` | C++ | `std::vector getAvailableGameVariables()` | | :-- | :-- | @@ -1542,11 +1542,11 @@ See also: --- -### `getAudioSamplingRate` +### `getAudioSamplingRate` -| C++ | `SamplingRate getAudioSamplingRate()` | +| C++ | `int getAudioSamplingRate()` | | :-- | :-- | -| Python | `SamplingRate get_audio_sampling_rate()` | +| Python | `int get_audio_sampling_rate()` | Added in 1.1.9 diff --git a/scripts/create_python_docstrings_from_docs.py b/scripts/create_python_docstrings_from_docs.py new file mode 100755 index 000000000..481aa8197 --- /dev/null +++ b/scripts/create_python_docstrings_from_docs.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 + +import re + + +FILES_TO_PARSE = [ + {"filepath": "doc/DoomGame.md", "namespace": "DoomGamePython"}, + {"filepath": "doc/Utilities.md"}, +] +OUTPUT_FILE = "src/lib_python/ViZDoomDocstrings.h" +RAW_STRING_ESCAPE_SEQ = "DOCSTRING" +FUNCTION_HEADER_REGEX = r"^### *<\/a> *`([a-zA-Z]+)` *$" +LINES_TO_IGNORE_REGEXES = [ + r"---", # Lines + r"^\|.+\|$", # Tables + r"^See also:.*$", # See also + r"- \[.*\]\(.*\)", # List of links starting with - + r"\* \[.*\]\(.*\)", # List of links starting with * + r"^Added in .*$", # Added in annotations + r"^Changed in .*$", # Changed in annotations + r"^Deprecated since .*$", # Deprecated since annotations + r"^Removed in .*$", # Removed in annotations + r"^Config key: .*$", # Config annotations +] + + +if __name__ == "__main__": + with open(OUTPUT_FILE, "w") as output_file: + output_file.write( + """ +/* + This file is autogenerated by scripts/create_python_docstrings_from_docs.py + Do not edit it manually. Edit the Markdown files instead and regenerate it. +*/ + +#ifndef __VIZDOOM_DOCSTRINGS_H__ +#define __VIZDOOM_DOCSTRINGS_H__ + +namespace vizdoom {{ +namespace docstrings {{ + +""" + ) + + for file in FILES_TO_PARSE: + if "namespace" in file: + output_file.write(f"namespace {file['namespace']} {{\n\n") + + with open(file["filepath"]) as f: + lines = f.readlines() + + started = False + next_docstring = "" + for line in lines: + # If lines match pattern, extract the function name and arguments + match = re.match(FUNCTION_HEADER_REGEX, line) + if match: + if started: + next_docstring = next_docstring.strip() + next_docstring += f'){RAW_STRING_ESCAPE_SEQ}";\n\n' + output_file.write(next_docstring) + + next_docstring = "" + function_name = match.group(1) + output_file.write( + f' const char *{function_name} = R"{RAW_STRING_ESCAPE_SEQ}(' + ) + started = True + + elif started: + # Filter out some lines + if not any(re.match(r, line) for r in LINES_TO_IGNORE_REGEXES): + next_docstring += line + + if started: + output_file.write(f'){RAW_STRING_ESCAPE_SEQ}";\n\n') + + if "namespace" in file: + output_file.write(f"}} // namespace {file['namespace']}\n\n") + + output_file.write( + """ +} // namespace docstrings +} // namespace vizdoom +#endif +""" + ) diff --git a/src/lib_python/CMakeLists.txt b/src/lib_python/CMakeLists.txt index f5b39194f..07d83e79b 100644 --- a/src/lib_python/CMakeLists.txt +++ b/src/lib_python/CMakeLists.txt @@ -42,6 +42,7 @@ configure_file( ) set(VIZDOOM_PYTHON_SOURCES + ${VIZDOOM_PYTHON_SRC_DIR}/ViZDoomDocstrings.h ${VIZDOOM_PYTHON_SRC_DIR}/ViZDoomGamePython.h ${VIZDOOM_PYTHON_SRC_DIR}/ViZDoomGamePython.cpp ${VIZDOOM_PYTHON_SRC_DIR}/ViZDoomPythonModule.cpp) diff --git a/src/lib_python/ViZDoomDocstrings.h b/src/lib_python/ViZDoomDocstrings.h new file mode 100644 index 000000000..3343903cb --- /dev/null +++ b/src/lib_python/ViZDoomDocstrings.h @@ -0,0 +1,413 @@ + +/* + This file is autogenerated by scripts/create_python_docstrings_from_docs.py + Do not edit it manually. Edit the Markdown files instead and regenerate it. +*/ + +#ifndef __VIZDOOM_DOCSTRINGS_H__ +#define __VIZDOOM_DOCSTRINGS_H__ + +#include + +namespace vizdoom { +namespace docstrings { + +namespace DoomGamePython { + + const char *init = R"DOCSTRING(Initializes ViZDoom game instance and starts a new episode. +After calling this method, the first state from a new episode will be available. +Some configuration options cannot be changed after calling this method. +Init returns true when the game was started properly and false otherwise.)DOCSTRING"; + + const char *close = R"DOCSTRING(Closes ViZDoom game instance. +It is automatically invoked by the destructor. +The game can be initialized again after being closed.)DOCSTRING"; + + const char *newEpisode = R"DOCSTRING(Initializes a new episode. The state of an environment is completely restarted (all variables and rewards are reset to their initial values). +After calling this method, the first state from the new episode will be available. +If the `recordFilePath` is not empty, the new episode will be recorded to this file (as a Doom lump). + +In a multiplayer game, the host can call this method to finish the game. +Then the rest of the players must also call this method to start a new episode.)DOCSTRING"; + + const char *replayEpisode = R"DOCSTRING(Replays a recorded episode from the given file using the perspective of the specified player. +Players are numbered from 1, `player` equal to 0 results in replaying the demo using the perspective of the default player in the recording file. +After calling this method, the first state from the replay will be available. +All rewards, variables, and states are available during the replaying episode.)DOCSTRING"; + + const char *isRunning = R"DOCSTRING(Checks if the ViZDoom game instance is running.)DOCSTRING"; + + const char *isMultiplayerGame = R"DOCSTRING(Checks if the game is in multiplayer mode.)DOCSTRING"; + + const char *isRecordingEpisode = R"DOCSTRING(Checks if the game is in recording mode.)DOCSTRING"; + + const char *isReplayingEpisode = R"DOCSTRING(Checks if the game is in replaying mode.)DOCSTRING"; + + const char *setAction = R"DOCSTRING(Sets the player's action for the next tics. +Each value corresponds to a button specified with [`addAvailableButton`](#addAvailableButton) method +or in the configuration file (in order of appearance).)DOCSTRING"; + + const char *advanceAction = R"DOCSTRING(Processes a specified number of tics. If `updateState` is set, +the state will be updated after the last processed tic and a new reward will be calculated. +To get the new state, use `getState` and to get the new reward use `getLastReward`. +If `updateState` is not set, the state will not be updated.)DOCSTRING"; + + const char *makeAction = R"DOCSTRING(Method combining usability of [`setAction`](#setAction), [`advanceAction`](#advanceAction) and [`getLastReward`](#getLastReward). +Sets the player's action for the next tics, processes a specified number of tics, +updates the state and calculates a new reward, which is returned.)DOCSTRING"; + + const char *isNewEpisode = R"DOCSTRING(Returns true if the current episode is in the initial state - the first state, no actions were performed yet.)DOCSTRING"; + + const char *isEpisodeFinished = R"DOCSTRING(Returns true if the current episode is in the terminal state (is finished). +[`makeAction`](#makeAction) and [`advanceAction`](#advanceAction) methods will take no effect after this point (unless [`newEpisode`](#newEpisode) method is called).)DOCSTRING"; + + const char *isPlayerDead = R"DOCSTRING(Returns true if the player is dead. +In singleplayer, the player's death is equivalent to the end of the episode. +In multiplayer, when the player is dead [`respawnPlayer`](#respawnPlayer) method can be called.)DOCSTRING"; + + const char *respawnPlayer = R"DOCSTRING(This method respawns the player after death in multiplayer mode. +After calling this method, the first state after the respawn will be available.)DOCSTRING"; + + const char *sendGameCommand = R"DOCSTRING(Sends the command to Doom console. It can be used for controlling the game, changing settings, cheats, etc. +Some commands will be blocked in some modes.)DOCSTRING"; + + const char *getState = R"DOCSTRING(Returns [`GameState`](Types.md#gamestate) object with the current game state. +If the current episode is finished, `nullptr/null/None` will be returned.)DOCSTRING"; + + const char *getServerState = R"DOCSTRING(Returns [`ServerState`](Types.md#serverstate) object with the current server state.)DOCSTRING"; + + const char *getLastAction = R"DOCSTRING(Returns the last action performed. +Each value corresponds to a button added with `[addAvailableButton](#addAvailableButton)` (in order of appearance). +Most useful in `SPECTATOR` mode.)DOCSTRING"; + + const char *getEpisodeTime = R"DOCSTRING(Returns number of current episode tic.)DOCSTRING"; + + const char *save = R"DOCSTRING(Saves a game's internal state to the file using ZDoom's save game functionality.)DOCSTRING"; + + const char *load = R"DOCSTRING(Loads a game's internal state from the file using ZDoom's load game functionality. +A new state is available after loading. +Loading the game state does not reset the current episode state, +tic counter/time and total reward state keep their values. + + +## Buttons settings methods)DOCSTRING"; + + const char *getAvailableButtons = R"DOCSTRING(Returns the list of available `Buttons`.)DOCSTRING"; + + const char *setAvailableButtons = R"DOCSTRING(Set given list of `Button`s (e.g. `TURN_LEFT`, `MOVE_FORWARD`) as available `Buttons`,)DOCSTRING"; + + const char *addAvailableButton = R"DOCSTRING(Add [`Button`](Types.md#button) type (e.g. `TURN_LEFT`, `MOVE_FORWARD`) to available `Buttons` and sets the maximum allowed, absolute value for the specified button. +If the given button has already been added, it will not be added again, but the maximum value is overridden.)DOCSTRING"; + + const char *clearAvailableButtons = R"DOCSTRING(Clears all available `Buttons` added so far.)DOCSTRING"; + + const char *getAvailableButtonsSize = R"DOCSTRING(Returns the number of available `Buttons`.)DOCSTRING"; + + const char *setButtonMaxValue = R"DOCSTRING(Sets the maximum allowed absolute value for the specified button. +Setting the maximum value to 0 results in no constraint at all (infinity). +This method makes sense only for delta buttons. +The constraints limit applies in all Modes.)DOCSTRING"; + + const char *getButtonMaxValue = R"DOCSTRING(Returns the maximum allowed absolute value for the specified button.)DOCSTRING"; + + const char *getButton = R"DOCSTRING(Returns the current state of the specified button (`ATTACK`, `USE` etc.). + + + +## GameVariables methods)DOCSTRING"; + + const char *getAvailableGameVariables = R"DOCSTRING(Returns the list of available `GameVariables`.)DOCSTRING"; + + const char *setAvailableGameVariables = R"DOCSTRING(Set list of [`GameVariable`](Types.md#gamevariable) as available `GameVariables` in the [`GameState`](Types.md#gamestate) returned by `getState` method.)DOCSTRING"; + + const char *addAvailableGameVariable = R"DOCSTRING(Adds the specified [`GameVariable`](Types.md#gamevariable) to the list of available game variables (e.g. `HEALTH`, `AMMO1`, `ATTACK_READY`) in the [`GameState`](Types.md#gamestate) returned by `getState` method.)DOCSTRING"; + + const char *clearAvailableGameVariables = R"DOCSTRING(Clears the list of available `GameVariables` that are included in the GameState returned by [`getState`](#getState) method.)DOCSTRING"; + + const char *getAvailableGameVariablesSize = R"DOCSTRING(Returns the number of available `GameVariables`.)DOCSTRING"; + + const char *getGameVariable = R"DOCSTRING(Returns the current value of the specified game variable (`HEALTH`, `AMMO1` etc.). +The specified game variable does not need to be among available game variables (included in the state). +It could be used for e.g. shaping. Returns 0 in case of not finding given `GameVariable`. + + + +## Game Arguments methods)DOCSTRING"; + + const char *addGameArgs = R"DOCSTRING(Adds a custom argument that will be passed to ViZDoom process during initialization. +Useful for changing additional game settings.)DOCSTRING"; + + const char *clearGameArgs = R"DOCSTRING(Clears all arguments previously added with [`addGameArgs`](#addGameArgs) method. + + +## Reward methods)DOCSTRING"; + + const char *getLivingReward = R"DOCSTRING(Returns the reward granted to the player after every tic.)DOCSTRING"; + + const char *setLivingReward = R"DOCSTRING(Sets the reward granted to the player after every tic. A negative value is also allowed. + +Default value: 0)DOCSTRING"; + + const char *getDeathPenalty = R"DOCSTRING(Returns the penalty for the player's death.)DOCSTRING"; + + const char *setDeathPenalty = R"DOCSTRING(Sets a penalty for the player's death. Note that in case of a negative value, the player will be rewarded upon dying. + +Default value: 0)DOCSTRING"; + + const char *getLastReward = R"DOCSTRING(Returns a reward granted after the last update of state.)DOCSTRING"; + + const char *getTotalReward = R"DOCSTRING(Returns the sum of all rewards gathered in the current episode. + + +## General game setting methods)DOCSTRING"; + + const char *loadConfig = R"DOCSTRING(Loads configuration (resolution, available buttons, game variables etc.) from a configuration file. +In case of multiple invocations, older configurations will be overwritten by the recent ones. +Overwriting does not involve resetting to default values. Thus only overlapping parameters will be changed. +The method returns true if the whole configuration file was correctly read and applied, +false if the file contained errors.)DOCSTRING"; + + const char *getMode = R"DOCSTRING(Returns current mode.)DOCSTRING"; + + const char *setMode = R"DOCSTRING(Sets mode (`PLAYER`, `SPECTATOR`, `ASYNC_PLAYER`, `ASYNC_SPECTATOR`) in which the game will be running. + +Default value: `PLAYER`.)DOCSTRING"; + + const char *getTicrate = R"DOCSTRING(Returns current ticrate.)DOCSTRING"; + + const char *setTicrate = R"DOCSTRING(Sets ticrate for ASNYC Modes - number of logic tics executed per second. +The default Doom ticrate is 35. This value will play a game at normal speed. + +Default value: 35 (default Doom ticrate).)DOCSTRING"; + + const char *setViZDoomPath = R"DOCSTRING(Sets path to the ViZDoom engine executable vizdoom. + +Default value: "{vizdoom.so location}/{vizdoom or vizdoom.exe (on Windows)}".)DOCSTRING"; + + const char *setDoomGamePath = R"DOCSTRING(Sets the path to the Doom engine based game file (wad format). +If not used DoomGame will look for doom2.wad and freedoom2.wad (in that order) in the directory of ViZDoom's installation (where vizdoom.so/pyd is). + +Default value: "{vizdoom.so location}/{doom2.wad, doom.wad, freedoom2.wad or freedoom.wad}")DOCSTRING"; + + const char *setDoomScenarioPath = R"DOCSTRING(Sets the path to an additional scenario file (wad format). +If not provided, the default Doom single-player maps will be loaded. + +Default value: "")DOCSTRING"; + + const char *setDoomMap = R"DOCSTRING(Sets the map name to be used. + +Default value: "map01", if set to empty "map01" will be used.)DOCSTRING"; + + const char *setDoomSkill = R"DOCSTRING(Sets Doom game difficulty level, which is called skill in Doom. +The higher the skill, the harder the game becomes. +Skill level affects monsters' aggressiveness, monsters' speed, weapon damage, ammunition quantities, etc. +Takes effect from the next episode. + +- 1 - VERY EASY, “I'm Too Young to Die” in Doom. +- 2 - EASY, “Hey, Not Too Rough" in Doom. +- 3 - NORMAL, “Hurt Me Plenty” in Doom. +- 4 - HARD, “Ultra-Violence” in Doom. +- 5 - VERY HARD, “Nightmare!” in Doom. + +Default value: 3)DOCSTRING"; + + const char *setDoomConfigPath = R"DOCSTRING(Sets the path for ZDoom's configuration file. +The file is responsible for the configuration of the ZDoom engine itself. +If it does not exist, it will be created after the `vizdoom` executable is run. +This method is not needed for most of the tasks and is added for the convenience of users with hacking tendencies. + +Default value: "", if left empty "_vizdoom.ini" will be used.)DOCSTRING"; + + const char *getSeed = R"DOCSTRING(Return ViZDoom's seed.)DOCSTRING"; + + const char *setSeed = R"DOCSTRING(Sets the seed of the ViZDoom's RNG that generates seeds (initial state) for episodes. + +Default value: randomized in constructor)DOCSTRING"; + + const char *getEpisodeStartTime = R"DOCSTRING(Returns start delay of every episode in tics.)DOCSTRING"; + + const char *setEpisodeStartTime = R"DOCSTRING(Sets start delay of every episode in tics. +Every episode will effectively start (from the user's perspective) after the provided number of tics. + +Default value: 1)DOCSTRING"; + + const char *getEpisodeTimeout = R"DOCSTRING(Returns the number of tics after which the episode will be finished.)DOCSTRING"; + + const char *setEpisodeTimeout = R"DOCSTRING(Sets the number of tics after which the episode will be finished. 0 will result in no timeout. + + + +## Output/rendering setting methods)DOCSTRING"; + + const char *setScreenResolution = R"DOCSTRING(Sets the screen resolution. ZDoom engine supports only specific resolutions. +Supported resolutions are part of ScreenResolution enumeration (e.g., `RES_320X240`, `RES_640X480`, `RES_1920X1080`). +The buffers, as well as the content of ViZDoom's display window, will be affected. + +Default value: `RES_320X240`)DOCSTRING"; + + const char *getScreenFormat = R"DOCSTRING(Returns the format of the screen buffer and the automap buffer.)DOCSTRING"; + + const char *setScreenFormat = R"DOCSTRING(Sets the format of the screen buffer and the automap buffer. +Supported formats are defined in `ScreenFormat` enumeration type (e.g. `CRCGCB`, `RGB24`, `GRAY8`). +The format change affects only the buffers, so it will not have any effect on the content of ViZDoom's display window. + +Default value: `CRCGCB`)DOCSTRING"; + + const char *isDepthBufferEnabled = R"DOCSTRING(Returns true if the depth buffer is enabled.)DOCSTRING"; + + const char *setDepthBufferEnabled = R"DOCSTRING(Enables rendering of the depth buffer, it will be available in the state. +Depth buffer will contain noise if `viz_nocheat` is enabled. + +Default value: false)DOCSTRING"; + + const char *isLabelsBufferEnabled = R"DOCSTRING(Returns true if the labels buffer is enabled.)DOCSTRING"; + + const char *setLabelsBufferEnabled = R"DOCSTRING(Enables rendering of the labels buffer, it will be available in the state with the vector of `Label`s. +LabelsBuffer will contain noise if `viz_nocheat` is enabled. + +Default value: false)DOCSTRING"; + + const char *isAutomapBufferEnabled = R"DOCSTRING(Returns true if the automap buffer is enabled.)DOCSTRING"; + + const char *setAutomapBufferEnabled = R"DOCSTRING(Enables rendering of the automap buffer, it will be available in the state. + +Default value: false)DOCSTRING"; + + const char *setAutomapMode = R"DOCSTRING(Sets the automap mode (`NORMAL`, `WHOLE`, `OBJECTS`, `OBJECTS_WITH_SIZE`), +which determines what will be visible on it. + +Default value: `NORMAL`)DOCSTRING"; + + const char *setAutomapRotate = R"DOCSTRING(Determine if the automap will be rotating with the player. +If false, north always will be at the top of the buffer. + +Default value: false)DOCSTRING"; + + const char *setAutomapRenderTextures = R"DOCSTRING(Determine if the automap will be textured, showing the floor textures. + +Default value: true)DOCSTRING"; + + const char *setRenderHud = R"DOCSTRING(Determine if the hud will be rendered in the game. + +Default value: false)DOCSTRING"; + + const char *setRenderMinimalHud = R"DOCSTRING(Determine if the minimalistic version of the hud will be rendered instead of the full hud. + +Default value: false)DOCSTRING"; + + const char *setRenderWeapon = R"DOCSTRING(Determine if the weapon held by the player will be rendered in the game. + +Default value: true)DOCSTRING"; + + const char *setRenderCrosshair = R"DOCSTRING(Determine if the crosshair will be rendered in the game. + +Default value: false)DOCSTRING"; + + const char *setRenderDecals = R"DOCSTRING(Determine if the decals (marks on the walls) will be rendered in the game. + +Default value: true)DOCSTRING"; + + const char *setRenderParticles = R"DOCSTRING(Determine if the particles will be rendered in the game. + +Default value: true)DOCSTRING"; + + const char *setRenderEffectsSprites = R"DOCSTRING(Determine if some effects sprites (gun puffs, blood splats etc.) will be rendered in the game. + +Default value: true)DOCSTRING"; + + const char *setRenderMessages = R"DOCSTRING(Determine if in-game messages (information about pickups, kills, etc.) will be rendered in the game. + +Default value: false)DOCSTRING"; + + const char *setRenderCorpses = R"DOCSTRING(Determine if actors' corpses will be rendered in the game. + +Default value: true)DOCSTRING"; + + const char *setRenderScreenFlashes = R"DOCSTRING(Determine if the screen flash effect upon taking damage or picking up items will be rendered in the game. + +Default value: true)DOCSTRING"; + + const char *setRenderAllFrames = R"DOCSTRING(Determine if all frames between states will be rendered (when skip greater than 1 is used). +Allows smooth preview but can reduce performance. +It only makes sense to use it if the window is visible. + +Default value: false)DOCSTRING"; + + const char *setWindowVisible = R"DOCSTRING(Determines if ViZDoom's window will be visible. +ViZDoom with window disabled can be used on Linux systems without X Server. + +Default value: false)DOCSTRING"; + + const char *setConsoleEnabled = R"DOCSTRING(Determines if ViZDoom's console output will be enabled. + +Default value: false)DOCSTRING"; + + const char *setSoundEnabled = R"DOCSTRING(Determines if ViZDoom's sound will be played. + +Default value: false)DOCSTRING"; + + const char *getScreenWidth = R"DOCSTRING(Returns game's screen width - width of all buffers.)DOCSTRING"; + + const char *getScreenHeight = R"DOCSTRING(Returns game's screen height - height of all buffers.)DOCSTRING"; + + const char *getScreenChannels = R"DOCSTRING(Returns number of channels in screen buffer and map buffer (depth and labels buffer always have one channel).)DOCSTRING"; + + const char *getScreenPitch = R"DOCSTRING(Returns size in bytes of one row in screen buffer and map buffer.)DOCSTRING"; + + const char *getScreenSize = R"DOCSTRING(Returns size in bytes of screen buffer and map buffer.)DOCSTRING"; + + const char *isObjectsInfoEnabled = R"DOCSTRING(Returns true if the objects information is enabled.)DOCSTRING"; + + const char *setObjectsInfoEnabled = R"DOCSTRING(Enables information about all objects present in the current episode/level. +It will be available in the state. + +Default value: false)DOCSTRING"; + + const char *isSectorsInfoEnabled = R"DOCSTRING(Returns true if the information about sectors is enabled.)DOCSTRING"; + + const char *setSectorsInfoEnabled = R"DOCSTRING(Enables information about all sectors (map layout) present in the current episode/level. +It will be available in the state. + +Default value: false)DOCSTRING"; + + const char *isAudioBufferEnabled = R"DOCSTRING(Returns true if the audio buffer is enabled.)DOCSTRING"; + + const char *setAudioBufferEnabled = R"DOCSTRING(Returns true if the audio buffer is enabled. + +Default value: false)DOCSTRING"; + + const char *getAudioSamplingRate = R"DOCSTRING(Returns the sampling rate of the audio buffer.)DOCSTRING"; + + const char *setAudioSamplingRate = R"DOCSTRING(Sets the sampling rate of the audio buffer. + +Default value: false)DOCSTRING"; + + const char *getAudioBufferSize = R"DOCSTRING(Returns the size of the audio buffer.)DOCSTRING"; + + const char *setAudioBufferSize = R"DOCSTRING()DOCSTRING"; + +} // namespace DoomGamePython + + const char *doomTicsToMs = R"DOCSTRING(Calculates how many tics will be made during given number of milliseconds.)DOCSTRING"; + + const char *msToDoomTics = R"DOCSTRING(Calculates the number of milliseconds that will pass during specified number of tics.)DOCSTRING"; + + const char *doomTicsToSec = R"DOCSTRING(Calculates how many tics will be made during given number of seconds.)DOCSTRING"; + + const char *secToDoomTics = R"DOCSTRING(Calculates the number of seconds that will pass during specified number of tics.)DOCSTRING"; + + const char *doomFixedToDouble = R"DOCSTRING(Converts Doom's fixed point numeral to a floating point value. + +- Types: `User variables` in `GameVariables` + +Python aliases (added in 1.1): +`float doom_fixed_to_float(int / float doomFixed)`)DOCSTRING"; + + const char *isBinaryButton = R"DOCSTRING(Returns true if button is binary button.)DOCSTRING"; + + const char *isDeltaButton = R"DOCSTRING()DOCSTRING"; + + +} // namespace docstrings +} // namespace vizdoom +#endif diff --git a/src/lib_python/ViZDoomPythonModule.cpp b/src/lib_python/ViZDoomPythonModule.cpp index 5b812b420..bfb1bdf79 100644 --- a/src/lib_python/ViZDoomPythonModule.cpp +++ b/src/lib_python/ViZDoomPythonModule.cpp @@ -24,6 +24,7 @@ #include "ViZDoom.h" #include "ViZDoomGamePython.h" #include "ViZDoomVersion.h" +#include "ViZDoomDocstrings.h" #include #include @@ -75,11 +76,11 @@ PYBIND11_MODULE(vizdoom, vz){ #define ENUM_CLASS_VAL_2_PYT(c, v) .value( #v , c::v ) /* .value("VALUE", class::VALUE) */ - #define FUNC_2_PYT(f) vz.def( #f , f ) - /* vz.def("function", function) */ + #define FUNC_2_PYT(n, f) vz.def( n , f , docstrings::f ) + /* vz.def("name", function, docstrings::function) */ - #define CLASS_FUNC_2_PYT(c, f) .def( #f , &c::f ) - /* .def("function", &class::function) */ + #define CLASS_FUNC_2_PYT(n, cf) .def( n , &cf , docstrings::cf ) + /* .def("name", &class::function, docstrings::class::function) */ /* Consts */ @@ -611,148 +612,148 @@ PYBIND11_MODULE(vizdoom, vz){ pyb::class_(vz, "DoomGame") .def(pyb::init<>()) - .def("init", &DoomGamePython::init) - .def("load_config", &DoomGamePython::loadConfig) - .def("close", &DoomGamePython::close) - .def("is_running", &DoomGamePython::isRunning) - .def("is_multiplayer_game", &DoomGamePython::isMultiplayerGame) - .def("is_recording_episode", &DoomGamePython::isRecordingEpisode) - .def("is_replaying_episode", &DoomGamePython::isReplayingEpisode) - .def("new_episode", &DoomGamePython::newEpisode_) - .def("new_episode", &DoomGamePython::newEpisode_str) - .def("replay_episode", &DoomGamePython::replayEpisode_str) - .def("replay_episode", &DoomGamePython::replayEpisode_str_int) - .def("is_episode_finished", &DoomGamePython::isEpisodeFinished) - .def("is_new_episode", &DoomGamePython::isNewEpisode) - .def("is_player_dead", &DoomGamePython::isPlayerDead) - .def("respawn_player", &DoomGamePython::respawnPlayer) - .def("set_action", &DoomGamePython::setAction) - .def("make_action", &DoomGamePython::makeAction_list) - .def("make_action", &DoomGamePython::makeAction_list_int) - .def("advance_action", &DoomGamePython::advanceAction_) - .def("advance_action", &DoomGamePython::advanceAction_int) - .def("advance_action", &DoomGamePython::advanceAction_int_bool) - .def("save", &DoomGamePython::save) - .def("load", &DoomGamePython::load) - - .def("get_state", &DoomGamePython::getState, pyb::return_value_policy::take_ownership) - .def("get_server_state", &DoomGamePython::getServerState, pyb::return_value_policy::take_ownership) - - .def("get_game_variable", &DoomGamePython::getGameVariable) - .def("get_button", &DoomGamePython::getButton) - - .def("get_living_reward", &DoomGamePython::getLivingReward) - .def("set_living_reward", &DoomGamePython::setLivingReward) - - .def("get_death_penalty", &DoomGamePython::getDeathPenalty) - .def("set_death_penalty", &DoomGamePython::setDeathPenalty) - - .def("get_last_reward", &DoomGamePython::getLastReward) - .def("get_total_reward", &DoomGamePython::getTotalReward) - - .def("get_last_action", &DoomGamePython::getLastAction) - - .def("get_available_game_variables", &DoomGamePython::getAvailableGameVariables) - .def("set_available_game_variables", &DoomGamePython::setAvailableGameVariables) - .def("add_available_game_variable", &DoomGamePython::addAvailableGameVariable) - .def("clear_available_game_variables", &DoomGamePython::clearAvailableGameVariables) - .def("get_available_game_variables_size", &DoomGamePython::getAvailableGameVariablesSize) - - .def("get_available_buttons", &DoomGamePython::getAvailableButtons) - .def("set_available_buttons", &DoomGamePython::setAvailableButtons) - .def("add_available_button", &DoomGamePython::addAvailableButton_btn) - .def("add_available_button", &DoomGamePython::addAvailableButton_btn_double) - .def("clear_available_buttons", &DoomGamePython::clearAvailableButtons) - .def("get_available_buttons_size", &DoomGamePython::getAvailableButtonsSize) - .def("set_button_max_value", &DoomGamePython::setButtonMaxValue) - .def("get_button_max_value", &DoomGamePython::getButtonMaxValue) - - .def("add_game_args", &DoomGamePython::addGameArgs) - .def("clear_game_args", &DoomGamePython::clearGameArgs) - - .def("send_game_command", &DoomGamePython::sendGameCommand) - - .def("get_mode", &DoomGamePython::getMode) - .def("set_mode", &DoomGamePython::setMode) - - .def("get_ticrate", &DoomGamePython::getTicrate) - .def("set_ticrate", &DoomGamePython::setTicrate) - - .def("set_vizdoom_path", &DoomGamePython::setViZDoomPath) - .def("set_doom_game_path", &DoomGamePython::setDoomGamePath) - .def("set_doom_scenario_path", &DoomGamePython::setDoomScenarioPath) - .def("set_doom_map", &DoomGamePython::setDoomMap) - .def("set_doom_skill", &DoomGamePython::setDoomSkill) - .def("set_doom_config_path", &DoomGamePython::setDoomConfigPath) - - .def("get_seed", &DoomGamePython::getSeed) - .def("set_seed", &DoomGamePython::setSeed) - - .def("get_episode_start_time", &DoomGamePython::getEpisodeStartTime) - .def("set_episode_start_time", &DoomGamePython::setEpisodeStartTime) - .def("get_episode_timeout", &DoomGamePython::getEpisodeTimeout) - .def("set_episode_timeout", &DoomGamePython::setEpisodeTimeout) - .def("get_episode_time", &DoomGamePython::getEpisodeTime) - - .def("set_console_enabled",&DoomGamePython::setConsoleEnabled) - .def("set_sound_enabled",&DoomGamePython::setSoundEnabled) - - .def("is_audio_buffer_enabled",&DoomGamePython::isAudioBufferEnabled) - .def("set_audio_buffer_enabled",&DoomGamePython::setAudioBufferEnabled) - .def("get_audio_sampling_rate",&DoomGamePython::getAudioSamplingRate) - .def("set_audio_sampling_rate",&DoomGamePython::setAudioSamplingRate) - .def("get_audio_buffer_size",&DoomGamePython::getAudioBufferSize) - .def("set_audio_buffer_size",&DoomGamePython::setAudioBufferSize) - - .def("set_screen_resolution", &DoomGamePython::setScreenResolution) - .def("set_screen_format", &DoomGamePython::setScreenFormat) - - .def("is_depth_buffer_enabled", &DoomGamePython::isDepthBufferEnabled) - .def("set_depth_buffer_enabled", &DoomGamePython::setDepthBufferEnabled) - .def("is_labels_buffer_enabled", &DoomGamePython::isLabelsBufferEnabled) - .def("set_labels_buffer_enabled", &DoomGamePython::setLabelsBufferEnabled) - .def("is_automap_buffer_enabled", &DoomGamePython::isAutomapBufferEnabled) - .def("set_automap_buffer_enabled", &DoomGamePython::setAutomapBufferEnabled) - .def("set_automap_mode", &DoomGamePython::setAutomapMode) - .def("set_automap_rotate", &DoomGamePython::setAutomapRotate) - .def("set_automap_render_textures", &DoomGamePython::setAutomapRenderTextures) - .def("is_objects_info_enabled", &DoomGamePython::isObjectsInfoEnabled) - .def("set_objects_info_enabled", &DoomGamePython::setObjectsInfoEnabled) - .def("is_sectors_info_enabled", &DoomGamePython::isSectorsInfoEnabled) - .def("set_sectors_info_enabled", &DoomGamePython::setSectorsInfoEnabled) - - .def("set_render_hud", &DoomGamePython::setRenderHud) - .def("set_render_minimal_hud", &DoomGamePython::setRenderMinimalHud) - .def("set_render_weapon", &DoomGamePython::setRenderWeapon) - .def("set_render_crosshair", &DoomGamePython::setRenderCrosshair) - .def("set_render_decals", &DoomGamePython::setRenderDecals) - .def("set_render_particles", &DoomGamePython::setRenderParticles) - .def("set_render_effects_sprites", &DoomGamePython::setRenderEffectsSprites) - .def("set_render_messages", &DoomGamePython::setRenderMessages) - .def("set_render_corpses", &DoomGamePython::setRenderCorpses) - .def("set_render_screen_flashes", &DoomGamePython::setRenderScreenFlashes) - .def("set_render_all_frames", &DoomGamePython::setRenderAllFrames) - .def("set_window_visible", &DoomGamePython::setWindowVisible) - .def("get_screen_width", &DoomGamePython::getScreenWidth) - .def("get_screen_height", &DoomGamePython::getScreenHeight) - .def("get_screen_channels", &DoomGamePython::getScreenChannels) - .def("get_screen_size", &DoomGamePython::getScreenSize) - .def("get_screen_pitch", &DoomGamePython::getScreenPitch) - .def("get_screen_format", &DoomGamePython::getScreenFormat); + CLASS_FUNC_2_PYT("init", DoomGamePython::init) + CLASS_FUNC_2_PYT("load_config", DoomGamePython::loadConfig) + CLASS_FUNC_2_PYT("close", DoomGamePython::close) + CLASS_FUNC_2_PYT("is_running", DoomGamePython::isRunning) + CLASS_FUNC_2_PYT("is_multiplayer_game", DoomGamePython::isMultiplayerGame) + CLASS_FUNC_2_PYT("is_recording_episode", DoomGamePython::isRecordingEpisode) + CLASS_FUNC_2_PYT("is_replaying_episode", DoomGamePython::isReplayingEpisode) + .def("new_episode", &DoomGamePython::newEpisode_, docstrings::DoomGamePython::newEpisode) + .def("new_episode", &DoomGamePython::newEpisode_str, docstrings::DoomGamePython::newEpisode) + .def("replay_episode", &DoomGamePython::replayEpisode_str, docstrings::DoomGamePython::replayEpisode) + .def("replay_episode", &DoomGamePython::replayEpisode_str_int, docstrings::DoomGamePython::replayEpisode) + CLASS_FUNC_2_PYT("is_episode_finished", DoomGamePython::isEpisodeFinished) + CLASS_FUNC_2_PYT("is_new_episode", DoomGamePython::isNewEpisode) + CLASS_FUNC_2_PYT("is_player_dead", DoomGamePython::isPlayerDead) + CLASS_FUNC_2_PYT("respawn_player", DoomGamePython::respawnPlayer) + CLASS_FUNC_2_PYT("set_action", DoomGamePython::setAction) + .def("make_action", &DoomGamePython::makeAction_list, docstrings::DoomGamePython::makeAction) + .def("make_action", &DoomGamePython::makeAction_list_int, docstrings::DoomGamePython::makeAction) + .def("advance_action", &DoomGamePython::advanceAction_, docstrings::DoomGamePython::advanceAction) + .def("advance_action", &DoomGamePython::advanceAction_int, docstrings::DoomGamePython::advanceAction) + .def("advance_action", &DoomGamePython::advanceAction_int_bool, docstrings::DoomGamePython::advanceAction) + CLASS_FUNC_2_PYT("save", DoomGamePython::save) + CLASS_FUNC_2_PYT("load", DoomGamePython::load) + + .def("get_state", &DoomGamePython::getState, pyb::return_value_policy::take_ownership, docstrings::DoomGamePython::getState) + .def("get_server_state", &DoomGamePython::getServerState, pyb::return_value_policy::take_ownership, docstrings::DoomGamePython::getServerState) + + CLASS_FUNC_2_PYT("get_game_variable", DoomGamePython::getGameVariable) + CLASS_FUNC_2_PYT("get_button", DoomGamePython::getButton) + + CLASS_FUNC_2_PYT("get_living_reward", DoomGamePython::getLivingReward) + CLASS_FUNC_2_PYT("set_living_reward", DoomGamePython::setLivingReward) + + CLASS_FUNC_2_PYT("get_death_penalty", DoomGamePython::getDeathPenalty) + CLASS_FUNC_2_PYT("set_death_penalty", DoomGamePython::setDeathPenalty) + + CLASS_FUNC_2_PYT("get_last_reward", DoomGamePython::getLastReward) + CLASS_FUNC_2_PYT("get_total_reward", DoomGamePython::getTotalReward) + + CLASS_FUNC_2_PYT("get_last_action", DoomGamePython::getLastAction) + + CLASS_FUNC_2_PYT("get_available_game_variables", DoomGamePython::getAvailableGameVariables) + CLASS_FUNC_2_PYT("set_available_game_variables", DoomGamePython::setAvailableGameVariables) + CLASS_FUNC_2_PYT("add_available_game_variable", DoomGamePython::addAvailableGameVariable) + CLASS_FUNC_2_PYT("clear_available_game_variables", DoomGamePython::clearAvailableGameVariables) + CLASS_FUNC_2_PYT("get_available_game_variables_size", DoomGamePython::getAvailableGameVariablesSize) + + CLASS_FUNC_2_PYT("get_available_buttons", DoomGamePython::getAvailableButtons) + CLASS_FUNC_2_PYT("set_available_buttons", DoomGamePython::setAvailableButtons) + .def("add_available_button", &DoomGamePython::addAvailableButton_btn, docstrings::DoomGamePython::addAvailableButton) + .def("add_available_button", &DoomGamePython::addAvailableButton_btn_double, docstrings::DoomGamePython::addAvailableButton) + CLASS_FUNC_2_PYT("clear_available_buttons", DoomGamePython::clearAvailableButtons) + CLASS_FUNC_2_PYT("get_available_buttons_size", DoomGamePython::getAvailableButtonsSize) + CLASS_FUNC_2_PYT("set_button_max_value", DoomGamePython::setButtonMaxValue) + CLASS_FUNC_2_PYT("get_button_max_value", DoomGamePython::getButtonMaxValue) + + CLASS_FUNC_2_PYT("add_game_args", DoomGamePython::addGameArgs) + CLASS_FUNC_2_PYT("clear_game_args", DoomGamePython::clearGameArgs) + + CLASS_FUNC_2_PYT("send_game_command", DoomGamePython::sendGameCommand) + + CLASS_FUNC_2_PYT("get_mode", DoomGamePython::getMode) + CLASS_FUNC_2_PYT("set_mode", DoomGamePython::setMode) + + CLASS_FUNC_2_PYT("get_ticrate", DoomGamePython::getTicrate) + CLASS_FUNC_2_PYT("set_ticrate", DoomGamePython::setTicrate) + + CLASS_FUNC_2_PYT("set_vizdoom_path", DoomGamePython::setViZDoomPath) + CLASS_FUNC_2_PYT("set_doom_game_path", DoomGamePython::setDoomGamePath) + CLASS_FUNC_2_PYT("set_doom_scenario_path", DoomGamePython::setDoomScenarioPath) + CLASS_FUNC_2_PYT("set_doom_map", DoomGamePython::setDoomMap) + CLASS_FUNC_2_PYT("set_doom_skill", DoomGamePython::setDoomSkill) + CLASS_FUNC_2_PYT("set_doom_config_path", DoomGamePython::setDoomConfigPath) + + CLASS_FUNC_2_PYT("get_seed", DoomGamePython::getSeed) + CLASS_FUNC_2_PYT("set_seed", DoomGamePython::setSeed) + + CLASS_FUNC_2_PYT("get_episode_start_time", DoomGamePython::getEpisodeStartTime) + CLASS_FUNC_2_PYT("set_episode_start_time", DoomGamePython::setEpisodeStartTime) + CLASS_FUNC_2_PYT("get_episode_timeout", DoomGamePython::getEpisodeTimeout) + CLASS_FUNC_2_PYT("set_episode_timeout", DoomGamePython::setEpisodeTimeout) + CLASS_FUNC_2_PYT("get_episode_time", DoomGamePython::getEpisodeTime) + + CLASS_FUNC_2_PYT("set_console_enabled", DoomGamePython::setConsoleEnabled) + CLASS_FUNC_2_PYT("set_sound_enabled", DoomGamePython::setSoundEnabled) + + CLASS_FUNC_2_PYT("is_audio_buffer_enabled", DoomGamePython::isAudioBufferEnabled) + CLASS_FUNC_2_PYT("set_audio_buffer_enabled", DoomGamePython::setAudioBufferEnabled) + CLASS_FUNC_2_PYT("get_audio_sampling_rate", DoomGamePython::getAudioSamplingRate) + CLASS_FUNC_2_PYT("set_audio_sampling_rate", DoomGamePython::setAudioSamplingRate) + CLASS_FUNC_2_PYT("get_audio_buffer_size", DoomGamePython::getAudioBufferSize) + CLASS_FUNC_2_PYT("set_audio_buffer_size", DoomGamePython::setAudioBufferSize) + + CLASS_FUNC_2_PYT("set_screen_resolution", DoomGamePython::setScreenResolution) + CLASS_FUNC_2_PYT("set_screen_format", DoomGamePython::setScreenFormat) + + CLASS_FUNC_2_PYT("is_depth_buffer_enabled", DoomGamePython::isDepthBufferEnabled) + CLASS_FUNC_2_PYT("set_depth_buffer_enabled", DoomGamePython::setDepthBufferEnabled) + CLASS_FUNC_2_PYT("is_labels_buffer_enabled", DoomGamePython::isLabelsBufferEnabled) + CLASS_FUNC_2_PYT("set_labels_buffer_enabled", DoomGamePython::setLabelsBufferEnabled) + CLASS_FUNC_2_PYT("is_automap_buffer_enabled", DoomGamePython::isAutomapBufferEnabled) + CLASS_FUNC_2_PYT("set_automap_buffer_enabled", DoomGamePython::setAutomapBufferEnabled) + CLASS_FUNC_2_PYT("set_automap_mode", DoomGamePython::setAutomapMode) + CLASS_FUNC_2_PYT("set_automap_rotate", DoomGamePython::setAutomapRotate) + CLASS_FUNC_2_PYT("set_automap_render_textures", DoomGamePython::setAutomapRenderTextures) + CLASS_FUNC_2_PYT("is_objects_info_enabled", DoomGamePython::isObjectsInfoEnabled) + CLASS_FUNC_2_PYT("set_objects_info_enabled", DoomGamePython::setObjectsInfoEnabled) + CLASS_FUNC_2_PYT("is_sectors_info_enabled", DoomGamePython::isSectorsInfoEnabled) + CLASS_FUNC_2_PYT("set_sectors_info_enabled", DoomGamePython::setSectorsInfoEnabled) + + CLASS_FUNC_2_PYT("set_render_hud", DoomGamePython::setRenderHud) + CLASS_FUNC_2_PYT("set_render_minimal_hud", DoomGamePython::setRenderMinimalHud) + CLASS_FUNC_2_PYT("set_render_weapon", DoomGamePython::setRenderWeapon) + CLASS_FUNC_2_PYT("set_render_crosshair", DoomGamePython::setRenderCrosshair) + CLASS_FUNC_2_PYT("set_render_decals", DoomGamePython::setRenderDecals) + CLASS_FUNC_2_PYT("set_render_particles", DoomGamePython::setRenderParticles) + CLASS_FUNC_2_PYT("set_render_effects_sprites", DoomGamePython::setRenderEffectsSprites) + CLASS_FUNC_2_PYT("set_render_messages", DoomGamePython::setRenderMessages) + CLASS_FUNC_2_PYT("set_render_corpses", DoomGamePython::setRenderCorpses) + CLASS_FUNC_2_PYT("set_render_screen_flashes", DoomGamePython::setRenderScreenFlashes) + CLASS_FUNC_2_PYT("set_render_all_frames", DoomGamePython::setRenderAllFrames) + CLASS_FUNC_2_PYT("set_window_visible", DoomGamePython::setWindowVisible) + CLASS_FUNC_2_PYT("get_screen_width", DoomGamePython::getScreenWidth) + CLASS_FUNC_2_PYT("get_screen_height", DoomGamePython::getScreenHeight) + CLASS_FUNC_2_PYT("get_screen_channels", DoomGamePython::getScreenChannels) + CLASS_FUNC_2_PYT("get_screen_size", DoomGamePython::getScreenSize) + CLASS_FUNC_2_PYT("get_screen_pitch", DoomGamePython::getScreenPitch) + CLASS_FUNC_2_PYT("get_screen_format", DoomGamePython::getScreenFormat); /* Utilities */ /*----------------------------------------------------------------------------------------------------------------*/ - vz.def("doom_tics_to_ms", doomTicsToMs); - vz.def("ms_to_doom_tics", msToDoomTics); - vz.def("doom_tics_to_sec", doomTicsToSec); - vz.def("sec_to_doom_tics", secToDoomTics); + FUNC_2_PYT("doom_tics_to_ms", doomTicsToMs); + FUNC_2_PYT("ms_to_doom_tics", msToDoomTics); + FUNC_2_PYT("doom_tics_to_sec", doomTicsToSec); + FUNC_2_PYT("sec_to_doom_tics", secToDoomTics); vz.def("doom_fixed_to_double", doomFixedToDouble_int); vz.def("doom_fixed_to_double", doomFixedToDouble_double); vz.def("doom_fixed_to_float", doomFixedToDouble_int); vz.def("doom_fixed_to_float", doomFixedToDouble_double); - vz.def("is_binary_button", isBinaryButton); - vz.def("is_delta_button", isDeltaButton); + FUNC_2_PYT("is_binary_button", isBinaryButton); + FUNC_2_PYT("is_delta_button", isDeltaButton); } diff --git a/tests/test_docstrings.py b/tests/test_docstrings.py new file mode 100755 index 000000000..f2e3709ef --- /dev/null +++ b/tests/test_docstrings.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +import vizdoom as vzd + + +def _check_object_docstrings(object): + object_methods = [ + method_name + for method_name in dir(object) + if callable(getattr(object, method_name)) + ] + + for method in object_methods: + assert method.__doc__ is not None, f"Method {method} has no docstring" + + +def test_docstrings(): + _check_object_docstrings(vzd.DoomGame) + + +if __name__ == "__main__": + test_docstrings()