diff --git a/DllMain.cpp b/DllMain.cpp index 3e1a7aa9..2ce88a57 100644 --- a/DllMain.cpp +++ b/DllMain.cpp @@ -33,7 +33,9 @@ constexpr const wchar_t* USER_AGENT = L"Mozilla/5.0 (Windows NT 6.3; Trident/7.0 using namespace std; using namespace filesystem; -#pragma region Function Define +static vector g_plugins; + +#pragma region Function //注入时事件 void Init(); //Dll入口函数 @@ -135,7 +137,7 @@ static void CheckPluginVersion() { return; cout << "[BDSpyrunner] Checking plugin version..." << endl; Json info = AccessUrlForJson(L"https://api.github.com/repos/twoone-3/BDSpyrunner/releases/latest"); - if (info["tag_name"] == VERSION_STRING) { + if (info["tag_name"] == PYR_VERSION) { cout << "[BDSpyrunner] Your plugin version is latest." << endl; return; } @@ -152,12 +154,12 @@ static void CheckPluginVersion() { } //事件回调 template -static bool EventCallBack(EventCode e, const char* format, Args... args) { +static bool EventCallBack(const EventCode e, const char* format, Args... args) { bool intercept = true; Py_BEGIN_CALL; for (PyObject* cb : g_callback_functions[e]) { PyObject* result = PyObject_CallFunction(cb, format, args...); - PyErr_Print(); + PrintPythonError(); if (result == Py_False) intercept = false; } @@ -216,6 +218,8 @@ HOOK(ChangeSettingCommand_setup, void, "?setup@ChangeSettingCommand@@SAXAEAVComm } original(_this); } +#pragma endregion +#pragma region Listener //开服完成 HOOK(onServerStarted, void, "?startServerThread@ServerInstance@@QEAAXXZ", uintptr_t _this) { @@ -253,7 +257,7 @@ HOOK(onConsoleInput, bool, "??$inner_enqueue@$0A@AEBV?$basic_string@DU?$char_tra cout << '>'; return false; } - if (EventCallBack(EventCode::onConsoleInput, "O", ToPyUnicode(*cmd))) + if (EventCallBack(EventCode::onConsoleInput, "O", StringToPyUnicode(*cmd))) return original(_this, cmd); return false; } @@ -298,7 +302,7 @@ HOOK(onUseItem, bool, "?useItemOn@GameMode@@UEAA_NAEAVItemStack@@AEBVBlockPos@@E //放置方块 HOOK(onPlaceBlock, bool, "?mayPlace@BlockSource@@QEAA_NAEBVBlock@@AEBVBlockPos@@EPEAVActor@@_N@Z", BlockSource* _this, Block* b, BlockPos* bp, unsigned char a4, Actor* p, bool _bool) { - if (isPlayer(p)) { + if (IsPlayer(p)) { BlockLegacy* bl = b->getBlockLegacy(); short bid = bl->getBlockItemID(); string bn = bl->getBlockName(); @@ -316,7 +320,7 @@ HOOK(onPlaceBlock, bool, "?mayPlace@BlockSource@@QEAA_NAEBVBlock@@AEBVBlockPos@@ //破坏方块 HOOK(onDestroyBlock, bool, "?checkBlockDestroyPermissions@BlockSource@@QEAA_NAEAVActor@@AEBVBlockPos@@AEBVItemStackBase@@_N@Z", BlockSource* _this, Actor* a1, BlockPos* a2, ItemStack* a3, bool a4) { - if (isPlayer(a1)) { + if (IsPlayer(a1)) { BlockLegacy* bl = _this->getBlock(a2)->getBlockLegacy(); short bid = bl->getBlockItemID(); string bn = bl->getBlockName(); @@ -500,7 +504,7 @@ HOOK(onInputCommand, void, "?handle@ServerNetworkHandler@@UEAAXAEBVNetworkIdenti if (data != g_commands.end() && data->second.second) { Py_BEGIN_CALL; PyObject_CallFunction(data->second.second, "O", ToEntity(p)); - PyErr_Print(); + PrintPythonError(); Py_END_CALL; return; } @@ -630,7 +634,7 @@ HOOK(onScoreChanged, void, "?onScoreChanged@ServerScoreboard@@UEAAXAEBUScoreboar //耕地破坏 HOOK(onFallBlockTransform, void, "?transformOnFall@FarmBlock@@UEBAXAEAVBlockSource@@AEBVBlockPos@@PEAVActor@@M@Z", uintptr_t _this, BlockSource* a1, BlockPos* a2, Actor* p, uintptr_t a4) { - if (isPlayer(p)) { + if (IsPlayer(p)) { if (!EventCallBack(EventCode::onFallBlockTransform, "{s:O,s:O,s:i}", "player", ToEntity(p), @@ -714,7 +718,7 @@ HOOK(onRide, bool, "?canAddRider@Actor@@UEBA_NAEAV1@@Z", return original(a1, a2); return false; } -//放入取出物品展示框的物品(未测试) +//放入取出物品展示框的物品 HOOK(onUseFrameBlock, bool, "?use@ItemFrameBlock@@UEBA_NAEAVPlayer@@AEBVBlockPos@@E@Z", uintptr_t _this, Player* a2, BlockPos* a3) { if (EventCallBack(EventCode::onUseFrameBlock, @@ -726,7 +730,7 @@ HOOK(onUseFrameBlock, bool, "?use@ItemFrameBlock@@UEBA_NAEAVPlayer@@AEBVBlockPos return original(_this, a2, a3); return false; } -//点击物品展示框(未测试) +//点击物品展示框 HOOK(onUseFrameBlocka, bool, "?attack@ItemFrameBlock@@UEBA_NPEAVPlayer@@AEBVBlockPos@@@Z", uintptr_t _this, Player* a2, BlockPos* a3) { if (EventCallBack(EventCode::onUseFrameBlock, @@ -750,7 +754,7 @@ HOOK(onSneak, void, "?sendActorSneakChanged@ActorEventCoordinator@@QEAAXAEAVActo if (EventCallBack(EventCode::onSneak, "O", ToEntity(a1))) return original(_this, a1, a2); } -//火势蔓延(未测试) +//火势蔓延 HOOK(onFireSpread, bool, "?_trySpawnBlueFire@FireBlock@@AEBA_NAEAVBlockSource@@AEBVBlockPos@@@Z", uintptr_t _this, BlockSource* bs, BlockPos* bp) { BlockLegacy* bl = bs->getBlock(bp)->getBlockLegacy(); @@ -779,7 +783,7 @@ HOOK(onBlockInteracted, void, "?onBlockInteractedWith@VanillaServerGameplayEvent )) return original(_this, pl, bp); } -//方块被爆炸破坏(未测试) +//方块被爆炸破坏 HOOK(onBlockExploded, void, "?onExploded@Block@@QEBAXAEAVBlockSource@@AEBVBlockPos@@PEAVActor@@@Z", Block* _this, BlockSource* bs, BlockPos* bp, Actor* actor) { BlockLegacy* bl = bs->getBlock(bp)->getBlockLegacy(); @@ -812,6 +816,7 @@ HOOK(onUseSingBlock, uintptr_t, "?use@SignBlock@@UEBA_NAEAVPlayer@@AEBVBlockPos@ return 0; } #pragma endregion + void Init() { //如果目录不存在创建目录 if (!exists(PLUGIN_PATH)) @@ -819,10 +824,15 @@ void Init() { if (!exists(CACHE_PATH)) create_directory(CACHE_PATH); //检测服务端版本 - if (!GetBDSVersion()._Starts_with("1.17.31.01")) - Py_FatalError("[BDSpyrunner] The server version isn't the latest version, unknown problems may occur if you continue to use it"); + //if (!GetBDSVersion()._Starts_with("1.17.31.01")) + // Py_FatalError("[BDSpyrunner] The server version isn't the latest version, unknown problems may occur if you continue to use it"); + //将plugins/py加入模块搜索路径 - Py_SetPath((wstring(PLUGIN_PATH L";") + Py_GetPath()).c_str()); + { + wstring py_path(PLUGIN_PATH L";"); + py_path.append(Py_GetPath()); + Py_SetPath(py_path.c_str()); + } #if 0 //预初始化3.8+ PyPreConfig cfg; @@ -848,12 +858,12 @@ void Init() { if (name.front() == '_') continue; cout << "[BDSpyrunner] Loading " << name << endl; - PyImport_Import(ToPyUnicode(name)); - PyErr_Print(); + g_plugins.push_back(PyImport_Import(StringToPyUnicode(name))); + PrintPythonError(); } } //释放当前线程 PyEval_SaveThread(); //输出版本号信息 - cout << "[BDSpyrunner] " << VERSION_STRING << " loaded, © 2021 twoone3." << endl; -} + cout << "[BDSpyrunner] " << PYR_VERSION << " loaded, © 2021 twoone3." << endl; + } diff --git a/README.md b/README.md index 0f868468..fa3f95f3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![Liscense](https://img.shields.io/github/license/twoone-3/BDSpyrunner) ![Downloads](https://img.shields.io/github/downloads/twoone-3/BDSpyrunner/total) ![Release](https://img.shields.io/github/v/release/twoone-3/BDSpyrunner) -![BDS](https://img.shields.io/badge/support--BDS--version-1.17.31.01-blue) +![BDS](https://img.shields.io/badge/support--BDS--version-1.17.32.02-blue) [简体中文](README_ZH.md) | English # Introduction diff --git a/README_ZH.md b/README_ZH.md index 7ed9cf5a..1a7d9a70 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -2,7 +2,7 @@ ![Liscense](https://img.shields.io/github/license/twoone-3/BDSpyrunner) ![Downloads](https://img.shields.io/github/downloads/twoone-3/BDSpyrunner/total) ![Release](https://img.shields.io/github/v/release/twoone-3/BDSpyrunner) -![BDS](https://img.shields.io/badge/support--BDS--version-1.17.31.01-blue) +![BDS](https://img.shields.io/badge/support--BDS--version-1.17.32.02-blue) 简体中文 | [English](README.md) # 简介 diff --git a/mc/Actor.cpp b/mc/Actor.cpp index 1e03290e..2b6f8435 100644 --- a/mc/Actor.cpp +++ b/mc/Actor.cpp @@ -20,7 +20,7 @@ string Actor::getNameTag() { //设置生物名称信息 -void Actor::setNameTag(const string&name) { +void Actor::setNameTag(const string& name) { VirtualCall(0x1F8, this, &name); } @@ -79,7 +79,7 @@ ItemStack* Actor::getArmor(int slot) { //获取实体类型 unsigned Actor::getEntityTypeId() { - return VirtualCall(0x520, this); + return VirtualCall(0x558, this); //return SymCall("?getEntityTypeId@Actor@@UEBA?AW4ActorType@@XZ", this); } @@ -210,7 +210,7 @@ void Actor::kill() { string Player::getUuid() {//IDA ServerNetworkHandler::_createNewPlayer 222 string p; SymCall("?asString@UUID@mce@@QEBA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ", - this + 3000, &p); + uintptr_t(this) + 2976, &p); return p; } @@ -218,7 +218,7 @@ string Player::getUuid() {//IDA ServerNetworkHandler::_createNewPlayer 222 string& Player::getXuid() { return SymCall("?getPlayerXUID@Level@@UEBAAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBVUUID@mce@@@Z", - getLevel(), this + 3000); + Global::data, uintptr_t(this) + 2976); } //获取网络标识符 @@ -349,15 +349,6 @@ void Player::sendPacket(uintptr_t pkt) { this, pkt); } -//使玩家客户端崩溃 -void Player::crash() { - uintptr_t pkt = createPacket(58); - FETCH(int, pkt + 14) = 0; - FETCH(int, pkt + 15) = 0; - FETCH(bool, pkt + 48) = 1; - sendPacket(pkt); -} - unsigned Player::sendModalFormRequestPacket(const string& str) { static unsigned id = 0; uintptr_t pkt = createPacket(100); @@ -422,3 +413,9 @@ void Player::sendSetScorePacket(char type, const vector& slot) FETCH(vector, pkt + 56) = slot; sendPacket(pkt); } + +bool IsPlayer(Actor* ptr) { + if (ptr && ptr->getEntityTypeId() == 319) + return true; + return false; +} diff --git a/mc/Actor.h b/mc/Actor.h index f7babf18..f08bac28 100644 --- a/mc/Actor.h +++ b/mc/Actor.h @@ -69,6 +69,7 @@ struct Actor { }; struct Mob : Actor {}; struct Player : Mob { + //ȡuuid std::string getUuid(); //ݵͼϢȡxuid std::string& getXuid(); @@ -110,8 +111,6 @@ struct Player : Mob { void sendInventroy(); //ˢ void resendAllChunks(); - //ͻ - void crash(); //ݰ void sendPacket(uintptr_t pkt); unsigned sendModalFormRequestPacket(const std::string& str); @@ -123,3 +122,5 @@ struct Player : Mob { void sendsetDisplayObjectivePacket(const std::string& title, const std::string& name = "name"); void sendSetScorePacket(char type, const std::vector& slot); }; +//ǷΪ +bool IsPlayer(Actor* ptr); diff --git a/mc/Level.cpp b/mc/Level.cpp index 27fdfe7b..87e5ab49 100644 --- a/mc/Level.cpp +++ b/mc/Level.cpp @@ -12,6 +12,11 @@ BlockSource* Level::getBlockSource(int did) { return FETCH(BlockSource*, d + 96);//IDA Level::tickEntities 120 } +void Level::forEachPlayer(const std::function& fn) { + SymCall("?forEachPlayer@Level@@UEBAXV?$function@$$A6A_NAEBVPlayer@@@Z@std@@@Z", + this, &fn); +} + Scoreboard* Level::getScoreBoard() { return FETCH(Scoreboard*, this + 8600);//IDA Level::getScoreboard } @@ -37,10 +42,6 @@ Player* Level::getPlayerByXuid(const string& xuid) { this, &xuid); } -vector Level::getAllPlayers() { - return FETCH(vector, this + 112);//IDA Level::forEachPlayer -} - BlockPalette* Level::getBlockPalette() { return FETCH(BlockPalette*, this + 2120); } diff --git a/mc/Level.h b/mc/Level.h index 181e75e5..f344f8ca 100644 --- a/mc/Level.h +++ b/mc/Level.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include "Position.h" struct Actor; @@ -18,12 +19,12 @@ struct Spawner { struct Level { //ȡԴ ûάȷؿָ BlockSource* getBlockSource(int did); + void forEachPlayer(const std::function&); Scoreboard* getScoreBoard(); unsigned getSeed(); std::string getPlayerNames(); Actor* fetchEntity(uintptr_t id); Player* getPlayerByXuid(const std::string& xuid); - std::vector getAllPlayers(); BlockPalette* getBlockPalette(); Spawner* getSpawner(); }; diff --git a/mc/tool.h b/mc/tool.h index c02050b1..34f80a2b 100644 --- a/mc/tool.h +++ b/mc/tool.h @@ -32,10 +32,7 @@ inline ReturnType VirtualCall(uintptr_t off, void* _this, Args... args) { // call a function by symbol string template inline ReturnType SymCall(const char* sym, Args... args) { - void* found = SYM(sym); - if (!found) - std::cerr << "Failed to call " << sym << std::endl; - return reinterpret_cast(found)(args...); + return reinterpret_cast(SYM(sym))(std::forward(args)...); } // replace the function inline void* SymHook(const char* sym, void* org, void* hook) { @@ -55,20 +52,3 @@ struct Global { inline std::string GetBDSVersion() { return SymCall("?getServerVersionString@Common@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ"); } - -//ַϣ -inline constexpr size_t Hash(const char* s) { - unsigned h = 0; - for (; *s; ++s) - h = 5 * h + *s; - return static_cast(h); -} - -//ǷΪ -inline bool isPlayer(void* ptr) { - for (auto p : Global::data->getAllPlayers()) { - if (ptr == p) - return true; - } - return false; -} diff --git a/mod/CPython.h b/mod/CPython.h index 1847095d..91060c99 100644 --- a/mod/CPython.h +++ b/mod/CPython.h @@ -2,3 +2,14 @@ #pragma comment(lib,"lib/python37.lib") #define PY_SSIZE_T_CLEAN #include "../include/Python.h" + +//ַתUnicode +inline PyObject* StringToPyUnicode(std::string_view str) { + return PyUnicode_FromStringAndSize(str.data(), str.length()); +} +//ӡϢ +inline void PrintPythonError() { + if (PyErr_Occurred()) { + PyErr_Print(); + } +} \ No newline at end of file diff --git a/mod/Entity.cpp b/mod/Entity.cpp index df626bd5..5a5fb686 100644 --- a/mod/Entity.cpp +++ b/mod/Entity.cpp @@ -18,7 +18,7 @@ struct PyEntity { Py_RETURN_ERROR("This entity pointer is nullptr"); } static Player* asPlayer(PyObject* self) { - if (isPlayer(reinterpret_cast(self)->actor)) + if (IsPlayer(reinterpret_cast(self)->actor)) return reinterpret_cast(reinterpret_cast(self)->actor); else Py_RETURN_ERROR("This entity pointer is nullptr or is not player pointer"); @@ -34,7 +34,7 @@ struct PyEntity { Actor* a = asActor(self); if (!a) return nullptr; - return ToPyUnicode(a->getNameTag()); + return StringToPyUnicode(a->getNameTag()); } static Py_hash_t hash(PyObject* self) { return reinterpret_cast(asActor(self)); @@ -43,7 +43,7 @@ struct PyEntity { Actor* a = asActor(self); if (!a) return nullptr; - return ToPyUnicode(a->getNameTag()); + return StringToPyUnicode(a->getNameTag()); } }; @@ -81,7 +81,7 @@ PyObject* PyEntity_GetName(PyObject* self, void*) { Actor* a = PyEntity::asActor(self); if (!a) return nullptr; - return ToPyUnicode(a->getNameTag()); + return StringToPyUnicode(a->getNameTag()); } int PyEntity_SetName(PyObject* self, PyObject* arg, void*) { @@ -100,7 +100,7 @@ PyObject* PyEntity_GetUuid(PyObject* self, void*) { Player* p = PyEntity::asPlayer(self); if (!p) return nullptr; - return ToPyUnicode(p->getUuid()); + return StringToPyUnicode(p->getUuid()); } //ȡXUID @@ -108,7 +108,7 @@ PyObject* PyEntity_GetXuid(PyObject* self, void*) { Player* p = PyEntity::asPlayer(self); if (!p) return nullptr; - return ToPyUnicode(p->getXuid()); + return StringToPyUnicode(p->getXuid()); } //ȡ @@ -156,7 +156,7 @@ PyObject* PyEntity_GetTypeName(PyObject* self, void*) { Actor* a = PyEntity::asActor(self); if (!a) return nullptr; - return ToPyUnicode(a->getEntityTypeName()); + return StringToPyUnicode(a->getEntityTypeName()); } //ȡnbt @@ -164,7 +164,7 @@ PyObject* PyEntity_GetNBTInfo(PyObject* self, void*) { Actor* a = PyEntity::asActor(self); if (!a) return nullptr; - return ToPyUnicode(CompoundTagtoJson(a->save()).dump(4)); + return StringToPyUnicode(CompoundTagtoJson(a->save()).dump(4)); } //ȡֵ @@ -229,7 +229,7 @@ PyObject* PyEntity_GetDeviceId(PyObject* self, void*) { Player* p = PyEntity::asPlayer(self); if (!p) return nullptr; - return ToPyUnicode(p->getDeviceId()); + return StringToPyUnicode(p->getDeviceId()); } //ȡ豸 @@ -245,7 +245,7 @@ PyObject* PyEntity_GetIP(PyObject* self, void*) { Player* p = PyEntity::asPlayer(self); if (!p) return nullptr; - return ToPyUnicode(Global::data->getSystemAddress(p->getClientId()).toString()); + return StringToPyUnicode(Global::data->getSystemAddress(p->getClientId()).toString()); } //ȡ/Ʒ @@ -273,7 +273,7 @@ PyObject* PyEntity_GetAllItem(PyObject* self, PyObject*) { value["OffHand"] = CompoundTagtoJson(p->getOffHand()->save()); value["Hand"] = CompoundTagtoJson(p->getSelectedItem()->save()); - return ToPyUnicode(value.dump(4)); + return StringToPyUnicode(value.dump(4)); } PyObject* PyEntity_SetAllItem(PyObject* self, PyObject* args) { @@ -592,20 +592,11 @@ PyObject* PyEntity_GetTags(PyObject* self, PyObject*) { span tags = a->getTags(); PyObject* list = PyList_New(0); for (size_t i = 0; i < tags.size; i++) { - PyList_Append(list, ToPyUnicode(tags.data[i])); + PyList_Append(list, StringToPyUnicode(tags.data[i])); } return list; } -//ͻ -PyObject* PyEntity_Crash(PyObject* self, PyObject*) { - Player* p = PyEntity::asPlayer(self); - if (!p) - return nullptr; - p->crash(); - Py_RETURN_NONE; -} - //ɱʵ PyObject* PyEntity_Kill(PyObject* self, PyObject*) { Actor* a = PyEntity::asActor(self); @@ -661,7 +652,6 @@ PyMethodDef PyEntity_Methods[]{ {"addTag", PyEntity_AddTag, METH_VARARGS, nullptr}, {"removeTag", PyEntity_RemoveTag, METH_VARARGS, nullptr}, {"getTags", PyEntity_GetTags, METH_NOARGS, nullptr}, - {"crash", PyEntity_Crash, METH_NOARGS, nullptr}, {"kill", PyEntity_Kill, METH_NOARGS, nullptr}, {nullptr} }; diff --git a/mod/Entity.h b/mod/Entity.h index 4a5cb76e..9e5d1ca4 100644 --- a/mod/Entity.h +++ b/mod/Entity.h @@ -17,10 +17,6 @@ //Entity extern PyTypeObject PyEntity_Type; -//ַתUnicode -inline PyObject* ToPyUnicode(std::string_view str) { - return PyUnicode_FromStringAndSize(str.data(), str.length()); -} //Vec3תlist inline PyObject* ToList(Vec3 * vec) { PyObject* list = PyList_New(3); diff --git a/mod/Module.cpp b/mod/Module.cpp index 8c35a4a3..9094b047 100644 --- a/mod/Module.cpp +++ b/mod/Module.cpp @@ -30,18 +30,18 @@ constexpr int IsSlimeChunk(unsigned x, unsigned z) { static PyObject* minVersionRequire(PyObject*, PyObject* args) { int v1, v2, v3; if (PyArg_ParseTuple(args, "iii:" __FUNCTION__, &v1, &v2, &v3)) { - if (v1 > VERSION_1) + if (v1 > PYR_MAJOR_VERSION) Py_RETURN_ERROR("The plugin version does not meet the minimum requirements"); - if (v2 > VERSION_2) + if (v2 > PYR_MINOR_VERSION) Py_RETURN_ERROR("The plugin version does not meet the minimum requirements"); - if (v3 > VERSION_3) + if (v3 > PYR_MICRO_VERSION) Py_RETURN_ERROR("The plugin version does not meet the minimum requirements"); } Py_RETURN_NONE; } //ȡBDS汾 static PyObject* getBDSVersion(PyObject*, PyObject*) { - return ToPyUnicode(GetBDSVersion()); + return StringToPyUnicode(GetBDSVersion()); } //ָ static PyObject* logout(PyObject*, PyObject* args) { @@ -103,9 +103,12 @@ static PyObject* getPlayerList(PyObject*, PyObject*) { PyObject* list = PyList_New(0); if (!Global::data) Py_RETURN_ERROR("Level is not set"); - for (Player* p : Global::data->getAllPlayers()) { - PyList_Append(list, ToEntity(p)); - } + Global::data->forEachPlayer( + [list](Player* p)->bool { + PyList_Append(list, ToEntity(p)); + return true; + } + ); return list; } //޸˵˺ֵ @@ -181,7 +184,7 @@ static PyObject* getStructure(PyObject*, PyObject* args) { StructureTemplate st("tmp"); st.fillFromWorld(bs, &start, &ss); - return ToPyUnicode(CompoundTagtoJson(st.save()).dump(4)); + return StringToPyUnicode(CompoundTagtoJson(st.save()).dump(4)); } Py_RETURN_NONE; } diff --git a/mod/Version.h b/mod/Version.h index 3e3b1170..5018d851 100644 --- a/mod/Version.h +++ b/mod/Version.h @@ -1,5 +1,5 @@ #pragma once -constexpr unsigned VERSION_1 = 1; -constexpr unsigned VERSION_2 = 7; -constexpr unsigned VERSION_3 = 11; -constexpr const char* VERSION_STRING = "v1.7.11"; \ No newline at end of file +constexpr unsigned PYR_MAJOR_VERSION = 1; +constexpr unsigned PYR_MINOR_VERSION = 8; +constexpr unsigned PYR_MICRO_VERSION = 0; +constexpr const char* PYR_VERSION = "v1.8.0"; \ No newline at end of file