diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml deleted file mode 100644 index a01bada4e..000000000 --- a/.github/workflows/clang-format.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Check formatting - -on: - pull_request: - paths: - - '**' - - '!.gitignore' - - '!*.md' - - '!.github/**' - - '.github/workflows/clang-format.yml' - -permissions: - contents: read - pull-requests: write - -jobs: - format-check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - with: - ref: ${{ github.event.pull_request.head.sha }} - fetch-depth: 0 - - - name: Fetch base commit - run: git fetch origin ${{ github.event.pull_request.base.sha }} - - - name: Install clang-format-20 - run: | - wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key | sudo tee /etc/apt/trusted.gpg.d/apt.llvm.org.asc - sudo add-apt-repository -y "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-20 main" - sudo apt-get install -y -qq clang-format-20 - - - uses: reviewdog/action-setup@v1 - - - name: Check formatting on changed lines - env: - REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git clang-format-20 --binary clang-format-20 \ - --diff ${{ github.event.pull_request.base.sha }} -- \ - '*.c' '*.cpp' '*.cc' '*.h' '*.hpp' \ - | reviewdog \ - -name="clang-format" \ - -f=diff \ - -reporter=github-pr-check \ - -fail-level=error \ - -filter-mode=added diff --git a/BACKPORTING.md b/BACKPORTING.md new file mode 100644 index 000000000..484fb3d23 --- /dev/null +++ b/BACKPORTING.md @@ -0,0 +1,15 @@ +# Approach to Backported Features +All backported features incorperated into MinecraftConsoles should be, when merged, functionally identical to their state in the version of the game we're currently targeting. This should be in reference to a known 4J build of LCE. Verification can either be done by doing a decompilation based match of the implementation or, alternatively, all functionality and limitations of the given feature should be compared against the version of LCE we're targeting. + +# Approach to Bugfixes +Anything that does not behave in an "expected" manner, especially if its behavior is not widely accepted as a gameplay mechanic, is valid for fixing in our repository. This includes bugfixes that were made in versions past the version we target, but excludes any visual changes that may not have been included at the build we're targeting. + +If you provide a visual bugfix that fixes a distinctive quirk of the LCE renderer, it should be provided in an "off by default" state that can be toggled on in-game by the user. There is no guarantee that we will merge it. + +If your visual bugfix is a fix added in a future version of LCE than the one we're targeting, it should also be put behind a toggle or equivalent system for keeping it off by default. + +# Targeted Version +We are currently accepting backports for up to and including TU24. Feature backports from TU25 and above will not be accepted. + +# Original Codebase +MinecraftConsoles is based on a WIP build of TU19, built on top of the December 2014 codebase. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 855491da1..fd5d7f03f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,9 @@ # Scope of Project At the moment, this project's scope is generally limited outside of adding new content to the game (blocks, mobs, items). We are currently prioritizing stability, quality of life, and platform support over these things. +## Backporting +If you're backporting a feature, please read [BACKPORTING.md](./BACKPORTING.md) + ## Parity We are attempting to keep our version of LCE as close to visual and experience parity with the original console experience of LCE as possible. This means that we will not be accepting changes that... - Backport things from Java Edition that did not ever exist in LCE diff --git a/Minecraft.Client/ChatScreen.cpp b/Minecraft.Client/ChatScreen.cpp index e2933a0cf..afffc7f6b 100644 --- a/Minecraft.Client/ChatScreen.cpp +++ b/Minecraft.Client/ChatScreen.cpp @@ -11,6 +11,7 @@ const wstring ChatScreen::allowedChars = SharedConstants::acceptableLetters; vector ChatScreen::s_chatHistory; int ChatScreen::s_historyIndex = -1; wstring ChatScreen::s_historyDraft; +int ChatScreen::s_chatIndex = 0; bool ChatScreen::isAllowedChatChar(wchar_t c) { @@ -22,6 +23,8 @@ ChatScreen::ChatScreen() frame = 0; cursorIndex = 0; s_historyIndex = -1; + + ChatScreen::s_chatIndex = 0; } void ChatScreen::init() @@ -83,6 +86,20 @@ void ChatScreen::handleHistoryDown() applyHistoryMessage(); } +int ChatScreen::getChatIndex() +{ + return ChatScreen::s_chatIndex; +} + +void ChatScreen::correctChatIndex(int newChatIndex) { + ChatScreen::s_chatIndex = newChatIndex; +} + +void ChatScreen::setWheelValue(int wheel) { + ChatScreen::s_chatIndex += wheel; + if (ChatScreen::s_chatIndex < 0) ChatScreen::s_chatIndex = 0; +} + void ChatScreen::keyPressed(wchar_t ch, int eventKey) { if (eventKey == Keyboard::KEY_ESCAPE) @@ -131,6 +148,7 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey) cursorIndex--; return; } + if (isAllowedChatChar(ch) && static_cast(message.length()) < SharedConstants::maxChatLength) { message.insert(cursorIndex, 1, ch); diff --git a/Minecraft.Client/ChatScreen.h b/Minecraft.Client/ChatScreen.h index c4e37a937..70d65e8ce 100644 --- a/Minecraft.Client/ChatScreen.h +++ b/Minecraft.Client/ChatScreen.h @@ -16,6 +16,7 @@ private: static std::vector s_chatHistory; static int s_historyIndex; static wstring s_historyDraft; + static int s_chatIndex; static const wstring allowedChars; static bool isAllowedChatChar(wchar_t c); @@ -28,6 +29,9 @@ public: virtual void handleHistoryUp(); virtual void handleHistoryDown(); + static int getChatIndex(); + static void correctChatIndex(int newChatIndex); + static void setWheelValue(int wheel); protected: void keyPressed(wchar_t ch, int eventKey); public: diff --git a/Minecraft.Client/Common/UI/UIController.cpp b/Minecraft.Client/Common/UI/UIController.cpp index 5f86b2df5..96e0ba2f9 100644 --- a/Minecraft.Client/Common/UI/UIController.cpp +++ b/Minecraft.Client/Common/UI/UIController.cpp @@ -1,5 +1,6 @@ #include "stdafx.h" #include "UIController.h" +#include #include "UI.h" #include "UIScene.h" #include "UIControl_Slider.h" @@ -1428,6 +1429,9 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key) } #endif + if (key == 4) ChatScreen::setWheelValue(1); + if (key == 5) ChatScreen::setWheelValue(-1); + if(pressed) app.DebugPrintf("Pressed %d\n",key); if(released) app.DebugPrintf("Released %d\n",key); // Repeat handling diff --git a/Minecraft.Client/Common/UI/UIScene_Credits.cpp b/Minecraft.Client/Common/UI/UIScene_Credits.cpp index a475acc35..40c05cff1 100644 --- a/Minecraft.Client/Common/UI/UIScene_Credits.cpp +++ b/Minecraft.Client/Common/UI/UIScene_Credits.cpp @@ -491,17 +491,19 @@ SCreditTextItemDef UIScene_Credits::gs_aCreditDefs[MAX_CREDIT_STRINGS] = {L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, {L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, {L"MinecraftConsoles", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eExtraLargeText}, - {L"Project Maintainers", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eLargeText}, - {L"smartcmd", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, - {L"codeHusky", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, - {L"Patoke", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, - {L"rtm516", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, - {L"mattsumi", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, - {L"dxf", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, - {L"la", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, {L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, - {L"Thank you to our 100+ contributors on GitHub!", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eLargeText}, - {L"github.com/smartcmd/MinecraftConsoles", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, + {L"Project Maintainers", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eLargeText}, + {L"codeHusky", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, + {L"mattsumi", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, + {L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, + {L"Former Maintainers", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eLargeText}, + {L"smartcmd", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, + {L"Patoke", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, + {L"rtm516", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, + {L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, + {L"Thank you to our 120+ contributors on GitHub!", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eLargeText}, + {L"github.com/MCLCE/MinecraftConsoles", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, + {L"(formerly smartcmd/MinecraftConsoles)", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, {L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, {L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText}, {L"Additional Thanks", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eLargeText}, diff --git a/Minecraft.Client/Common/UI/UIScene_EndPoem.cpp b/Minecraft.Client/Common/UI/UIScene_EndPoem.cpp index 297898155..0de42d636 100644 --- a/Minecraft.Client/Common/UI/UIScene_EndPoem.cpp +++ b/Minecraft.Client/Common/UI/UIScene_EndPoem.cpp @@ -50,14 +50,7 @@ UIScene_EndPoem::UIScene_EndPoem(int iPad, void *initData, UILayer *parentLayer) Minecraft *pMinecraft = Minecraft::GetInstance(); wstring playerName = L""; - if(pMinecraft->localplayers[ui.GetWinUserIndex()] != nullptr) - { - playerName = escapeXML( pMinecraft->localplayers[ui.GetWinUserIndex()]->getDisplayName() ); - } - else - { - playerName = escapeXML( pMinecraft->localplayers[ProfileManager.GetPrimaryPad()]->getDisplayName() ); - } + playerName = escapeXML( pMinecraft->localplayers[ProfileManager.GetPrimaryPad()]->getDisplayName() ); noNoiseString = replaceAll(noNoiseString,L"{*PLAYER*}",playerName); Random random(8124371); diff --git a/Minecraft.Client/Common/UI/UIScene_HUD.cpp b/Minecraft.Client/Common/UI/UIScene_HUD.cpp index 1559a6ec3..705ee0749 100644 --- a/Minecraft.Client/Common/UI/UIScene_HUD.cpp +++ b/Minecraft.Client/Common/UI/UIScene_HUD.cpp @@ -9,6 +9,7 @@ #include "../../EnderDragonRenderer.h" #include "../../../Minecraft.World/net.minecraft.world.inventory.h" #include "../../../Minecraft.World/StringHelpers.h" +#include UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer) { @@ -761,16 +762,31 @@ void UIScene_HUD::render(S32 width, S32 height, C4JRender::eViewportType viewpor void UIScene_HUD::handleTimerComplete(int id) { Minecraft *pMinecraft = Minecraft::GetInstance(); + bool isChatOpen = (dynamic_cast(pMinecraft->getScreen()) != nullptr); bool anyVisible = false; if(pMinecraft->localplayers[m_iPad]!= nullptr) { Gui *pGui = pMinecraft->gui; - //DWORD messagesToDisplay = min( CHAT_LINES_COUNT, pGui->getMessagesCount(m_iPad) ); - for( unsigned int i = 0; i < CHAT_LINES_COUNT; ++i ) + DWORD totalMessages = pGui->getMessagesCount(m_iPad); + DWORD messagesToDisplay = min( CHAT_LINES_COUNT, totalMessages); + DWORD maxScroll = max(0, totalMessages - messagesToDisplay); + + bool canScroll = messagesToDisplay < totalMessages; + int startIndex = (canScroll && isChatOpen ? ChatScreen::getChatIndex() : 0); + + if (startIndex > maxScroll) { + ChatScreen::correctChatIndex(maxScroll); + startIndex = maxScroll; + } + + app.DebugPrintf("handleTimerComplete: %d | %d | %d\n", maxScroll, startIndex, totalMessages); + + for( unsigned int i = 0; i < messagesToDisplay; ++i ) { - float opacity = pGui->getOpacity(m_iPad, i); - if( opacity > 0 ) + unsigned int msgIndex = startIndex + i; + float opacity = pGui->getOpacity(m_iPad, msgIndex); + if( opacity > 0 || isChatOpen) { #if 0 // def _WINDOWS64 // Use Iggy chat until Gui::render has visual parity // Chat drawn by Gui::render with color codes. Hides Iggy chat to avoid double chats. @@ -778,9 +794,10 @@ void UIScene_HUD::handleTimerComplete(int id) m_labelChatText[i].setOpacity(0); m_labelChatText[i].setLabel(L""); #else - m_controlLabelBackground[i].setOpacity(opacity); - m_labelChatText[i].setOpacity(opacity); - m_labelChatText[i].setLabel( pGui->getMessagesCount(m_iPad) ? pGui->getMessage(m_iPad,i) : L"" ); + + m_controlLabelBackground[i].setOpacity((isChatOpen ? 1 : opacity)); + m_labelChatText[i].setOpacity((isChatOpen ? 1 : opacity)); + m_labelChatText[i].setLabel(pGui->getMessage(m_iPad, msgIndex)); #endif anyVisible = true; } diff --git a/Minecraft.Client/EnderDragonRenderer.cpp b/Minecraft.Client/EnderDragonRenderer.cpp index ed50748e3..44e921928 100644 --- a/Minecraft.Client/EnderDragonRenderer.cpp +++ b/Minecraft.Client/EnderDragonRenderer.cpp @@ -89,6 +89,11 @@ void EnderDragonRenderer::render(shared_ptr _mob, double x, double y, do // 4J - dynamic cast required because we aren't using templates/generics in our version shared_ptr mob = dynamic_pointer_cast(_mob); BossMobGuiInfo::setBossHealth(mob, false); + if (!mob->getCustomName().empty()) + { + BossMobGuiInfo::name = mob->getCustomName(); + } + MobRenderer::render(mob, x, y, z, rot, a); if (mob->nearestCrystal != nullptr) { diff --git a/Minecraft.Client/EntityTracker.cpp b/Minecraft.Client/EntityTracker.cpp index 24e4815ba..79ce26582 100644 --- a/Minecraft.Client/EntityTracker.cpp +++ b/Minecraft.Client/EntityTracker.cpp @@ -81,7 +81,7 @@ void EntityTracker::addEntity(shared_ptr e, int range, int updateInterva { assert(false); // Entity already tracked } - if( e->entityId >= 2048 ) + if( e->entityId >= 16384 ) { __debugbreak(); } diff --git a/Minecraft.Client/Font.cpp b/Minecraft.Client/Font.cpp index f610c5855..205e348a0 100644 --- a/Minecraft.Client/Font.cpp +++ b/Minecraft.Client/Font.cpp @@ -310,6 +310,8 @@ void Font::draw(const wstring &str, bool dropShadow, int initialColor) t->begin(); t->color(currentColor & 0x00ffffff, (currentColor >> 24) & 255); + bool prev = t->setMipmapEnable(false); // Disable mipmapping for fonts, and save previous enabled value to be restored later - Botch + for (int i = 0; i < static_cast(cleanStr.length()); ++i) { // Map character @@ -371,6 +373,8 @@ void Font::draw(const wstring &str, bool dropShadow, int initialColor) addCharacterQuad(c); } + t->setMipmapEnable(prev); //Reinstates previously used enabled value - Botch + t->end(); } diff --git a/Minecraft.Client/Gui.cpp b/Minecraft.Client/Gui.cpp index 474a28110..4d6a882f3 100644 --- a/Minecraft.Client/Gui.cpp +++ b/Minecraft.Client/Gui.cpp @@ -1208,7 +1208,20 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) // Disable the depth test so the text shows on top of the paperdoll glDisable(GL_DEPTH_TEST); +#ifdef _WINDOWS64 + float scaleWidth = (g_rScreenWidth / 1920.0f); + float scaleHeight = (g_rScreenHeight / 1080.0f); + float scale = min(scaleWidth, scaleHeight); //stop stretching + + if (scale < 0.5f) scale = 0.5f; // force minimum scale + if (scale > 1.2f) // resolutions over 1296 pixels tall + { + scale = scale - 0.33f; // tame overscaling on 1440p + } + + glScalef(scale, scale, 1); +#endif // Loop through the lines and draw them all on screen int yPos = debugTop; for (const auto &line : lines) @@ -1217,6 +1230,9 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse) yPos += 10; } +#ifdef _WINDOWS64 + glScalef(1, 1, 1); +#endif // Restore the depth test glEnable(GL_DEPTH_TEST); diff --git a/Minecraft.Client/Gui.h b/Minecraft.Client/Gui.h index 64b8dfbe8..440d4e5b4 100644 --- a/Minecraft.Client/Gui.h +++ b/Minecraft.Client/Gui.h @@ -17,6 +17,7 @@ private: static const int m_iMaxMessageWidth = 280; static ItemRenderer *itemRenderer; vector guiMessages[XUSER_MAX_COUNT]; + int chatIndex = 0; Random *random; Minecraft *minecraft; diff --git a/Minecraft.Client/HumanoidModel.cpp b/Minecraft.Client/HumanoidModel.cpp index 6cbb8d729..a120ed055 100644 --- a/Minecraft.Client/HumanoidModel.cpp +++ b/Minecraft.Client/HumanoidModel.cpp @@ -241,7 +241,7 @@ void HumanoidModel::setupAnim(float time, float r, float bob, float yRot, float if (riding) { - if(uiBitmaskOverrideAnim&(1<xRot += -HALF_PI * 0.4f; arm1->xRot += -HALF_PI * 0.4f; diff --git a/Minecraft.Client/ItemInHandRenderer.cpp b/Minecraft.Client/ItemInHandRenderer.cpp index 9c999ed42..462cb81fe 100644 --- a/Minecraft.Client/ItemInHandRenderer.cpp +++ b/Minecraft.Client/ItemInHandRenderer.cpp @@ -286,6 +286,20 @@ void ItemInHandRenderer::renderItem(shared_ptr mob, shared_ptrgetAnimOverrideBitmask() & (1 << HumanoidModel::eAnim_SmallModel)) + { + if (mob->isRiding()) + { + std::shared_ptr ridingEntity = mob->riding; + if (ridingEntity != nullptr) // Safety check; + { + yo += 0.3f; // reverts the change in Boat.cpp for smaller models. + } + } + } glEnable(GL_RESCALE_NORMAL); glTranslatef(-xo, -yo, 0); diff --git a/Minecraft.Client/Minecraft.cpp b/Minecraft.Client/Minecraft.cpp index 6299e70ee..f8493dded 100644 --- a/Minecraft.Client/Minecraft.cpp +++ b/Minecraft.Client/Minecraft.cpp @@ -1537,8 +1537,12 @@ void Minecraft::run_middle() // Utility keys always work regardless of KBM active state if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_PAUSE) && !ui.GetMenuDisplayed(i)) { - localplayers[i]->ullButtonsPressed|=1LL<(getScreen()) != nullptr) { + setScreen(nullptr); + } else { + localplayers[i]->ullButtonsPressed|=1LL< _mob, double x, double y, double armorParts1->sneaking = armorParts2->sneaking = humanoidModel->sneaking = mob->isSneaking(); double yp = y - mob->heightOffset; - if (mob->isSneaking() && !mob->instanceof(eTYPE_LOCALPLAYER)) + if (mob->isSneaking()) { yp -= 2 / 16.0f; } + if (mob->getAnimOverrideBitmask() & (1 << HumanoidModel::eAnim_SmallModel)) + { + if (mob->isRiding()) + { + std::shared_ptr ridingEntity = mob->riding; + if (ridingEntity != nullptr) // Safety check; + { + if (ridingEntity->instanceof(eTYPE_BOAT)) + { + yp += 0.25f; // reverts the change in Boat.cpp for smaller models. + } + } + } + } + // Check if an idle animation is needed if(mob->getAnimOverrideBitmask()&(1< _sheep, int layer, floa int c2 = (value + 1) % Sheep::COLOR_LENGTH; float subStep = ((sheep->tickCount % colorDuration) + a) / static_cast(colorDuration); - glColor3f(Sheep::COLOR[c1][0] * (1.0f - subStep) + Sheep::COLOR[c2][0] * subStep, Sheep::COLOR[c1][1] * (1.0f - subStep) + Sheep::COLOR[c2][1] * subStep, Sheep::COLOR[c1][2] - * (1.0f - subStep) + Sheep::COLOR[c2][2] * subStep); + glColor3f( + Sheep::COLOR[c1][0] * (1.0f - subStep) + Sheep::COLOR[c2][0] * subStep, + Sheep::COLOR[c1][1] * (1.0f - subStep) + Sheep::COLOR[c2][1] * subStep, + Sheep::COLOR[c1][2] * (1.0f - subStep) + Sheep::COLOR[c2][2] * subStep); } else { - int color = sheep->getColor(); - glColor3f(Sheep::COLOR[color][0], Sheep::COLOR[color][1], Sheep::COLOR[color][2]); + float brightness = SharedConstants::TEXTURE_LIGHTING ? 1.0f : sheep->getBrightness(a); + int color = sheep->getColor(); + glColor3f(brightness * Sheep::COLOR[color][0], brightness * Sheep::COLOR[color][1], brightness * Sheep::COLOR[color][2]); + } // 4J - change brought forward from 1.8.2 - float brightness = SharedConstants::TEXTURE_LIGHTING ? 1.0f : sheep->getBrightness(a); - int color = sheep->getColor(); - glColor3f(brightness * Sheep::COLOR[color][0], brightness * Sheep::COLOR[color][1], brightness * Sheep::COLOR[color][2]); + + + /* Fix; this code originally completely overrided the _jeb and normal textures so i just commented it out and updated the part that should have worked. + + float brightness = SharedConstants::TEXTURE_LIGHTING ? 1.0f : sheep->getBrightness(a); + int color = sheep->getColor(); + glColor3f(brightness * Sheep::COLOR[color][0], brightness * Sheep::COLOR[color][1], brightness * Sheep::COLOR[color][2]); */ + + return 1; } return -1; diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp index acd6e886e..875717f61 100644 --- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp +++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp @@ -57,6 +57,13 @@ extern Renderer InternalRenderManager; #include "Xbox/Resource.h" +// request use of dedicated GPU from AMD and Nvidia drivers +extern "C" +{ + __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; + __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; +} + #ifdef _MSC_VER #pragma comment(lib, "legacy_stdio_definitions.lib") #endif @@ -472,6 +479,8 @@ IDXGISwapChain* g_pSwapChain = nullptr; ID3D11RenderTargetView* g_pRenderTargetView = nullptr; ID3D11DepthStencilView* g_pDepthStencilView = nullptr; ID3D11Texture2D* g_pDepthStencilBuffer = nullptr; +static const float kClearColorWhite[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; +static const float kClearColorBlack[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; // // FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) @@ -663,7 +672,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) } break; default: - return DefWindowProc(hWnd, message, wParam, lParam); + return DefWindowProcW(hWnd, message, wParam, lParam); } return 0; } @@ -675,23 +684,23 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) // ATOM MyRegisterClass(HINSTANCE hInstance) { - WNDCLASSEX wcex; + WNDCLASSEXW wcex; - wcex.cbSize = sizeof(WNDCLASSEX); + wcex.cbSize = sizeof(WNDCLASSEXW); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; - wcex.hIcon = LoadIcon(hInstance, "Minecraft"); + wcex.hIcon = LoadIconW(hInstance, L"Minecraft"); wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - wcex.lpszMenuName = "Minecraft"; - wcex.lpszClassName = "MinecraftClass"; + wcex.lpszMenuName = L"Minecraft"; + wcex.lpszClassName = L"MinecraftClass"; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_MINECRAFTWINDOWS)); - return RegisterClassEx(&wcex); + return RegisterClassExW(&wcex); } // @@ -711,8 +720,8 @@ BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) RECT wr = {0, 0, g_rScreenWidth, g_rScreenHeight}; // set the size, but not the position AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size - g_hWnd = CreateWindow( "MinecraftClass", - "Minecraft", + g_hWnd = CreateWindowW( L"MinecraftClass", + L"Minecraft", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, @@ -1564,7 +1573,14 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, continue; } + const float* clearColor = app.GetGameStarted() ? kClearColorBlack : kClearColorWhite; + RenderManager.SetClearColour(clearColor); RenderManager.StartFrame(); + if (!app.GetGameStarted()) + { + RenderManager.SetClearColour(kClearColorWhite); // set intro scene background to white + RenderManager.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } #if 0 if(pMinecraft->soundEngine->isStreamingWavebankReady() && !pMinecraft->soundEngine->isPlayingStreamingGameMusic() && diff --git a/Minecraft.Client/WitherBossRenderer.cpp b/Minecraft.Client/WitherBossRenderer.cpp index e358c6dab..dc1d8f923 100644 --- a/Minecraft.Client/WitherBossRenderer.cpp +++ b/Minecraft.Client/WitherBossRenderer.cpp @@ -20,6 +20,10 @@ void WitherBossRenderer::render(shared_ptr entity, double x, double y, d shared_ptr mob = dynamic_pointer_cast(entity); BossMobGuiInfo::setBossHealth(mob, true); + if (!mob->getCustomName().empty()) + { + BossMobGuiInfo::name = mob->getCustomName(); + } int modelVersion = dynamic_cast(model)->modelVersion(); if (modelVersion != this->modelVersion) diff --git a/Minecraft.Server/Windows64/ServerMain.cpp b/Minecraft.Server/Windows64/ServerMain.cpp index bd568f0c7..201ff17c9 100644 --- a/Minecraft.Server/Windows64/ServerMain.cpp +++ b/Minecraft.Server/Windows64/ServerMain.cpp @@ -28,6 +28,7 @@ #include "../../Minecraft.World/TilePos.h" #include "../../Minecraft.World/compression.h" #include "../../Minecraft.World/OldChunkStorage.h" +#include "../../Minecraft.World/ConsoleSaveFileOriginal.h" #include "../../Minecraft.World/net.minecraft.world.level.tile.h" #include "../../Minecraft.World/Random.h" @@ -325,6 +326,7 @@ static void TickCoreSystems() g_NetworkManager.DoWork(); ProfileManager.Tick(); StorageManager.Tick(); + ConsoleSaveFileOriginal::flushPendingBackgroundSave(); } /** @@ -655,7 +657,7 @@ int main(int argc, char **argv) break; } - if (autosaveRequested && app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle) + if (autosaveRequested && app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle && !ConsoleSaveFileOriginal::hasPendingBackgroundSave()) { LogWorldIO("autosave completed"); autosaveRequested = false; @@ -669,7 +671,7 @@ int main(int argc, char **argv) DWORD now = GetTickCount(); if ((LONG)(now - nextAutosaveTick) >= 0) { - if (app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle) + if (app.GetXuiServerAction(kServerActionPad) == eXuiServerAction_Idle && !ConsoleSaveFileOriginal::hasPendingBackgroundSave()) { LogWorldIO("requesting autosave"); app.SetXuiServerAction(kServerActionPad, eXuiServerAction_AutoSaveGame); @@ -685,25 +687,38 @@ int main(int argc, char **argv) LogInfof("shutdown", "Dedicated server stopped"); MinecraftServer *server = MinecraftServer::getInstance(); - if (server != NULL) - { - server->setSaveOnExit(true); - } - if (server != NULL) + if (server != NULL && !ConsoleSaveFileOriginal::hasPendingBackgroundSave()) { + server->setSaveOnExit(true); LogWorldIO("requesting save before shutdown"); LogWorldIO("using saveOnExit for shutdown"); } + if (ConsoleSaveFileOriginal::hasPendingBackgroundSave()) + { + LogWorldIO("Waiting for autosave to complete..."); + } + MinecraftServer::HaltServer(); if (g_NetworkManager.ServerStoppedValid()) { C4JThread waitThread(&WaitForServerStoppedThreadProc, NULL, "WaitServerStopped"); waitThread.Run(); + while (waitThread.isRunning()) + { + TickCoreSystems(); + Sleep(10); + } waitThread.WaitForCompletion(INFINITE); } + while (ConsoleSaveFileOriginal::hasPendingBackgroundSave()) + { + TickCoreSystems(); + Sleep(10); + } + LogInfof("shutdown", "Cleaning up and exiting."); WinsockNetLayer::Shutdown(); LogDebugf("shutdown", "Network layer shutdown complete."); diff --git a/Minecraft.Server/cmake/sources/Common.cmake b/Minecraft.Server/cmake/sources/Common.cmake index 06aa0bfe1..58ae26ce2 100644 --- a/Minecraft.Server/cmake/sources/Common.cmake +++ b/Minecraft.Server/cmake/sources/Common.cmake @@ -494,6 +494,9 @@ set(_MINECRAFT_SERVER_COMMON_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/iob_shim.asm" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/stdafx.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.Client/stubs.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.World/Entity.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.World/ConsoleSaveFileOriginal.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/../Minecraft.World/ConsoleSaveFileOriginal.h" "${CMAKE_CURRENT_SOURCE_DIR}/../include/lce_filesystem/lce_filesystem.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Console/ServerCliInput.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/Console/ServerCliInput.h" diff --git a/Minecraft.World/Boat.cpp b/Minecraft.World/Boat.cpp index 60d0c807e..7be52e53a 100644 --- a/Minecraft.World/Boat.cpp +++ b/Minecraft.World/Boat.cpp @@ -87,7 +87,7 @@ Boat::Boat(Level *level, double x, double y, double z) : Entity( level ) double Boat::getRideHeight() { - return heightOffset; + return heightOffset - 0.4f; } bool Boat::hurt(DamageSource *source, float hurtDamage) diff --git a/Minecraft.World/ConsoleSaveFileOriginal.cpp b/Minecraft.World/ConsoleSaveFileOriginal.cpp index 7e00b82a9..8d6571b22 100644 --- a/Minecraft.World/ConsoleSaveFileOriginal.cpp +++ b/Minecraft.World/ConsoleSaveFileOriginal.cpp @@ -12,6 +12,26 @@ #include "../Minecraft.Client/Common/GameRules/LevelGenerationOptions.h" #include "../Minecraft.World/net.minecraft.world.level.chunk.storage.h" +#ifdef MINECRAFT_SERVER_BUILD +#include +#include +#include + +static std::atomic s_bgSaveActive{false}; +static std::mutex s_bgSaveMutex; + +struct BackgroundSaveResult +{ + ConsoleSaveFile *owner = nullptr; + PBYTE thumbData = nullptr; + DWORD thumbSize = 0; + BYTE textMeta[88] = {}; + int textMetaBytes = 0; + bool pending = false; +}; +static BackgroundSaveResult s_bgResult; +#endif + #ifdef _XBOX #define RESERVE_ALLOCATION MEM_RESERVE | MEM_LARGE_PAGES @@ -673,6 +693,83 @@ void ConsoleSaveFileOriginal::Flush(bool autosave, bool updateThumbnail ) unsigned int fileSize = header.GetFileSize(); +#ifdef MINECRAFT_SERVER_BUILD + // on the server we dont want to block the tick thread doing compression!!! + // sna[pshot pvSaveMem while we still hold the lock then hand it off to a background thread + byte *snap = new (std::nothrow) byte[fileSize]; + if (snap) + { + // copy the save buffer while we still own the lock so nothing can write to it mid-copy + QueryPerformanceCounter(&qwTime); + memcpy(snap, pvSaveMem, fileSize); + QueryPerformanceCounter(&qwNewTime); + app.DebugPrintf("snapshot %u bytes in %.3f sec\n", fileSize, + (qwNewTime.QuadPart - qwTime.QuadPart) * fSecsPerTick); + + PBYTE thumb = nullptr; + DWORD thumbSz = 0; + app.GetSaveThumbnail(&thumb, &thumbSz); + + BYTE meta[88]; + ZeroMemory(meta, 88); + int64_t seed = 0; + bool hasSeed = false; + if (MinecraftServer *sv = MinecraftServer::getInstance(); sv && sv->levels[0]) + { + seed = sv->levels[0]->getLevelData()->getSeed(); + hasSeed = true; + } + int metaLen = app.CreateImageTextData(meta, seed, hasSeed, + app.GetGameHostOption(eGameHostOption_All), Minecraft::GetInstance()->getCurrentTexturePackId()); + + // telemetry + INT uid = 0; + StorageManager.GetSaveUniqueNumber(&uid); + TelemetryManager->RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), uid, fileSize); + + ReleaseSaveAccess(); + s_bgSaveActive.store(true, std::memory_order_release); + + std::thread([snap, fileSize, thumb, thumbSz, meta, metaLen, this]() { + unsigned int compLen = fileSize + 8; + byte *buf = static_cast(StorageManager.AllocateSaveData(compLen)); + if (!buf) + { + // FAIL!! attempt precalc + compLen = 0; + Compression::getCompression()->Compress(nullptr, &compLen, snap, fileSize); + compLen += 8; + buf = static_cast(StorageManager.AllocateSaveData(compLen)); + } + if (buf) + { + // COM,PRESS + Compression::getCompression()->Compress(buf + 8, &compLen, snap, fileSize); + ZeroMemory(buf, 8); + memcpy(buf + 4, &fileSize, sizeof(fileSize)); + + // store the result so flushPendingBackgroundSave() can pick it up on the main thread next tick + // StorageManager isnt thread safe so we cant call SetSaveImages or SaveSaveData from here. Bwoomp + std::lock_guard lk(s_bgSaveMutex); + s_bgResult.owner = this; + s_bgResult.thumbData = thumb; + s_bgResult.thumbSize = thumbSz; + memcpy(s_bgResult.textMeta, meta, sizeof(meta)); + s_bgResult.textMetaBytes = metaLen; + s_bgResult.pending = true; + } + else + { + app.DebugPrintf("save buf alloc failed\n"); + s_bgSaveActive.store(false, std::memory_order_release); + } + delete[] snap; + }).detach(); + return; + } + app.DebugPrintf("snapshot alloc failed (%u bytes)\n", fileSize); +#endif + // Assume that the compression will make it smaller so initially attempt to allocate the current file size // We add 4 bytes to the start so that we can signal compressed data // And another 4 bytes to store the decompressed data size @@ -838,6 +935,10 @@ int ConsoleSaveFileOriginal::SaveSaveDataCallback(LPVOID lpParam,bool bRes) { ConsoleSaveFile *pClass=static_cast(lpParam); +#ifdef MINECRAFT_SERVER_BUILD + s_bgSaveActive.store(false, std::memory_order_release); +#endif + return 0; } @@ -1085,3 +1186,25 @@ void *ConsoleSaveFileOriginal::getWritePointer(FileEntry *file) { return static_cast(pvSaveMem) + file->currentFilePointer;; } + +#ifdef MINECRAFT_SERVER_BUILD +void ConsoleSaveFileOriginal::flushPendingBackgroundSave() +{ + std::lock_guard lk(s_bgSaveMutex); + if (!s_bgResult.pending) + return; + + StorageManager.SetSaveImages( + s_bgResult.thumbData, s_bgResult.thumbSize, + nullptr, 0, s_bgResult.textMeta, s_bgResult.textMetaBytes); + StorageManager.SaveSaveData(&ConsoleSaveFileOriginal::SaveSaveDataCallback, s_bgResult.owner); + + s_bgResult.pending = false; + // the actual write isnt done until SaveSaveDataCallback fires +} + +bool ConsoleSaveFileOriginal::hasPendingBackgroundSave() +{ + return s_bgSaveActive.load(std::memory_order_acquire); +} +#endif diff --git a/Minecraft.World/ConsoleSaveFileOriginal.h b/Minecraft.World/ConsoleSaveFileOriginal.h index 9c91fafcf..453cacd91 100644 --- a/Minecraft.World/ConsoleSaveFileOriginal.h +++ b/Minecraft.World/ConsoleSaveFileOriginal.h @@ -77,6 +77,11 @@ public: virtual void LockSaveAccess(); virtual void ReleaseSaveAccess(); +#ifdef MINECRAFT_SERVER_BUILD + static void flushPendingBackgroundSave(); + static bool hasPendingBackgroundSave(); +#endif + virtual ESavePlatform getSavePlatform(); virtual bool isSaveEndianDifferent(); virtual void setLocalPlatform(); diff --git a/Minecraft.World/EnderDragon.h b/Minecraft.World/EnderDragon.h index 9f39767eb..1bb8f5ce1 100644 --- a/Minecraft.World/EnderDragon.h +++ b/Minecraft.World/EnderDragon.h @@ -183,7 +183,7 @@ public: double getHeadPartYRotDiff(int partIndex, doubleArray bodyPos, doubleArray partPos); Vec3 *getHeadLookVector(float a); - virtual wstring getAName() { return app.GetString(IDS_ENDERDRAGON); }; + virtual wstring getAName() { if (hasCustomName()) return getCustomName(); return app.GetString(IDS_ENDERDRAGON); }; virtual float getHealth() { return LivingEntity::getHealth(); }; virtual float getMaxHealth() { return LivingEntity::getMaxHealth(); }; }; diff --git a/Minecraft.World/Entity.cpp b/Minecraft.World/Entity.cpp index 8168705df..02664cd5b 100644 --- a/Minecraft.World/Entity.cpp +++ b/Minecraft.World/Entity.cpp @@ -27,13 +27,17 @@ const wstring Entity::RIDING_TAG = L"Riding"; -int Entity::entityCounter = 2048; // 4J - changed initialiser to 2048, as we are using range 0 - 2047 as special unique smaller ids for things that need network tracked +//int Entity::entityCounter = 2048; // 4J - changed initialiser to 2048, as we are using range 0 - 2047 as special unique smaller ids for things that need network tracked +int Entity::entityCounter = 16384; //now using full range of 0 - 16383, limit is 32k but we shouldnt need that yet DWORD Entity::tlsIdx = TlsAlloc(); // 4J - added getSmallId & freeSmallId methods -unsigned int Entity::entityIdUsedFlags[2048/32] = {0}; -unsigned int Entity::entityIdWanderFlags[2048/32] = {0}; -unsigned int Entity::entityIdRemovingFlags[2048/32] = {0}; +//unsigned int Entity::entityIdUsedFlags[2048/32] = {0}; +//unsigned int Entity::entityIdWanderFlags[2048/32] = {0}; +//unsigned int Entity::entityIdRemovingFlags[2048/32] = {0}; +unsigned int Entity::entityIdUsedFlags[16384/32] = {0}; +unsigned int Entity::entityIdWanderFlags[16384/32] = {0}; +unsigned int Entity::entityIdRemovingFlags[16384/32] = {0}; int Entity::extraWanderIds[EXTRA_WANDER_MAX] = {0}; int Entity::extraWanderTicks = 0; int Entity::extraWanderCount = 0; @@ -65,7 +69,7 @@ int Entity::getSmallId() } } - for( int i = 0; i < (2048 / 32 ); i++ ) + for( int i = 0; i < (16384 / 32 ); i++ ) { unsigned int uiFlags = *puiUsedFlags; if( uiFlags != 0xffffffff ) @@ -102,7 +106,7 @@ int Entity::getSmallId() if (entityCounter == 0x7ffffff) { - entityCounter = 2048; + entityCounter = 16384; } return fallbackId; #else @@ -116,7 +120,7 @@ void Entity::countFlagsForPIX() { int freecount = 0; unsigned int *puiUsedFlags = entityIdUsedFlags; - for( int i = 0; i < (2048 / 32 ); i++ ) + for( int i = 0; i < (16384 / 32 ); i++ ) { unsigned int uiFlags = *puiUsedFlags; if( uiFlags != 0xffffffff ) @@ -134,7 +138,7 @@ void Entity::countFlagsForPIX() puiUsedFlags++; } PIXAddNamedCounter(freecount,"Small Ids free"); - PIXAddNamedCounter(2048 - freecount,"Small Ids used"); + PIXAddNamedCounter(16384 - freecount,"Small Ids used"); } void Entity::resetSmallId() @@ -149,7 +153,7 @@ void Entity::resetSmallId() void Entity::freeSmallId(int index) { if( ( (size_t)TlsGetValue(tlsIdx) ) == 0 ) return; // Don't do anything with small ids if this isn't the server thread - if( index >= 2048 ) return; // Don't do anything if this isn't a short id + if( index >= 16384 ) return; // Don't do anything if this isn't a short id unsigned int i = index / 32; unsigned int j = index % 32; @@ -172,7 +176,7 @@ void Entity::useSmallIds() void Entity::considerForExtraWandering(bool enable) { if( ( (size_t)TlsGetValue(tlsIdx) ) == 0 ) return; // Don't do anything with small ids if this isn't the server thread - if( entityId >= 2048 ) return; // Don't do anything if this isn't a short id + if( entityId >= 16384 ) return; // Don't do anything if this isn't a short id unsigned int i = entityId / 32; unsigned int j = entityId % 32; @@ -192,7 +196,7 @@ void Entity::considerForExtraWandering(bool enable) bool Entity::isExtraWanderingEnabled() { if( ( (size_t)TlsGetValue(tlsIdx) ) == 0 ) return false; // Don't do anything with small ids if this isn't the server thread - if( entityId >= 2048 ) return false; // Don't do anything if this isn't a short id + if( entityId >= 16384 ) return false; // Don't do anything if this isn't a short id for( int i = 0; i < extraWanderCount; i++ ) { @@ -224,12 +228,12 @@ void Entity::tickExtraWandering() int entityId = 0; if( extraWanderCount ) { - entityId = ( extraWanderIds[ extraWanderCount - 1 ] + 1 ) % 2048; + entityId = ( extraWanderIds[ extraWanderCount - 1 ] + 1 ) % 16384; } extraWanderCount = 0; - for( int k = 0; ( k < 2048 ) && ( extraWanderCount < EXTRA_WANDER_MAX); k++ ) + for( int k = 0; ( k < 16384 ) && ( extraWanderCount < EXTRA_WANDER_MAX); k++ ) { unsigned int i = entityId / 32; unsigned int j = entityId % 32; @@ -241,7 +245,7 @@ void Entity::tickExtraWandering() // printf("%d, ", entityId); } - entityId = ( entityId + 1 ) % 2048; + entityId = ( entityId + 1 ) % 16384; } // printf("\n"); } @@ -261,7 +265,7 @@ void Entity::_init(bool useSmallId, Level *level) else { entityId = Entity::entityCounter++; - if(entityCounter == 0x7ffffff ) entityCounter = 2048; + if(entityCounter == 0x7ffffff ) entityCounter = 16384; } viewScale = 1.0; diff --git a/Minecraft.World/Entity.h b/Minecraft.World/Entity.h index a738c2ba7..9fb0f5489 100644 --- a/Minecraft.World/Entity.h +++ b/Minecraft.World/Entity.h @@ -382,9 +382,12 @@ private: int getSmallId(); void freeSmallId(int index); - static unsigned int entityIdUsedFlags[2048/32]; - static unsigned int entityIdWanderFlags[2048/32]; - static unsigned int entityIdRemovingFlags[2048/32]; + //static unsigned int entityIdUsedFlags[2048/32]; + //static unsigned int entityIdWanderFlags[2048/32]; + //static unsigned int entityIdRemovingFlags[2048/32]; + static unsigned int entityIdUsedFlags[16384/32]; + static unsigned int entityIdWanderFlags[16384/32]; + static unsigned int entityIdRemovingFlags[16384/32]; static int extraWanderIds[EXTRA_WANDER_MAX]; static int extraWanderCount; static int extraWanderTicks; diff --git a/Minecraft.World/MoveEntityPacket.cpp b/Minecraft.World/MoveEntityPacket.cpp index cae28e912..aef9e6217 100644 --- a/Minecraft.World/MoveEntityPacket.cpp +++ b/Minecraft.World/MoveEntityPacket.cpp @@ -35,7 +35,7 @@ void MoveEntityPacket::read(DataInputStream *dis) //throws IOException void MoveEntityPacket::write(DataOutputStream *dos) //throws IOException { - if( (id < 0 ) || (id >= 2048 ) ) + if( (id < 0 ) || (id >= 16384 ) ) { // We shouln't be tracking an entity that doesn't have a short type of id __debugbreak(); diff --git a/Minecraft.World/MoveEntityPacketSmall.cpp b/Minecraft.World/MoveEntityPacketSmall.cpp index ec67f37f2..7d91a15d5 100644 --- a/Minecraft.World/MoveEntityPacketSmall.cpp +++ b/Minecraft.World/MoveEntityPacketSmall.cpp @@ -19,7 +19,7 @@ MoveEntityPacketSmall::MoveEntityPacketSmall() MoveEntityPacketSmall::MoveEntityPacketSmall(int id) { - if( (id < 0 ) || (id >= 2048 ) ) + if( (id < 0 ) || (id >= 16384 ) ) { // We shouln't be tracking an entity that doesn't have a short type of id __debugbreak(); @@ -42,7 +42,7 @@ void MoveEntityPacketSmall::read(DataInputStream *dis) //throws IOException void MoveEntityPacketSmall::write(DataOutputStream *dos) //throws IOException { - if( (id < 0 ) || (id >= 2048 ) ) + if( (id < 0 ) || (id >= 16384 ) ) { // We shouln't be tracking an entity that doesn't have a short type of id __debugbreak(); @@ -99,7 +99,7 @@ void MoveEntityPacketSmall::PosRot::read(DataInputStream *dis) //throws IOExcept void MoveEntityPacketSmall::PosRot::write(DataOutputStream *dos) //throws IOException { - if( (id < 0 ) || (id >= 2048 ) ) + if( (id < 0 ) || (id >= 16384 ) ) { // We shouln't be tracking an entity that doesn't have a short type of id __debugbreak(); @@ -138,7 +138,7 @@ void MoveEntityPacketSmall::Pos::read(DataInputStream *dis) //throws IOException void MoveEntityPacketSmall::Pos::write(DataOutputStream *dos) //throws IOException { - if( (id < 0 ) || (id >= 2048 ) ) + if( (id < 0 ) || (id >= 16384 ) ) { // We shouln't be tracking an entity that doesn't have a short type of id __debugbreak(); @@ -176,7 +176,7 @@ void MoveEntityPacketSmall::Rot::read(DataInputStream *dis) //throws IOException void MoveEntityPacketSmall::Rot::write(DataOutputStream *dos) //throws IOException { - if( (id < 0 ) || (id >= 2048 ) ) + if( (id < 0 ) || (id >= 16384 ) ) { // We shouln't be tracking an entity that doesn't have a short type of id __debugbreak(); diff --git a/Minecraft.World/PortalTile.cpp b/Minecraft.World/PortalTile.cpp index 5e664e656..1b64212b8 100644 --- a/Minecraft.World/PortalTile.cpp +++ b/Minecraft.World/PortalTile.cpp @@ -67,21 +67,8 @@ bool PortalTile::isCubeShaped() return false; } -bool PortalTile::trySpawnPortal(Level *level, int x, int y, int z, bool actuallySpawn) +bool PortalTile::validPortalFrame(Level* level, int x, int y, int z, int xd, int zd, bool actuallySpawn) { - int xd = 0; - int zd = 0; - if (level->getTile(x - 1, y, z) == Tile::obsidian_Id || level->getTile(x + 1, y, z) == Tile::obsidian_Id) xd = 1; - if (level->getTile(x, y, z - 1) == Tile::obsidian_Id || level->getTile(x, y, z + 1) == Tile::obsidian_Id) zd = 1; - - if (xd == zd) return false; - - if (level->getTile(x - xd, y, z - zd) == 0) - { - x -= xd; - z -= zd; - } - for (int xx = -1; xx <= 2; xx++) { for (int yy = -1; yy <= 3; yy++) @@ -101,9 +88,7 @@ bool PortalTile::trySpawnPortal(Level *level, int x, int y, int z, bool actually } } } - - if( !actuallySpawn ) - return true; + if (!actuallySpawn) return true; for (int xx = 0; xx < 2; xx++) { @@ -112,9 +97,52 @@ bool PortalTile::trySpawnPortal(Level *level, int x, int y, int z, bool actually level->setTileAndData(x + xd * xx, y + yy, z + zd * xx, Tile::portalTile_Id, 0, Tile::UPDATE_CLIENTS); } } - + return true; +} +bool PortalTile::trySpawnPortal(Level *level, int x, int y, int z, bool actuallySpawn) +{ + int xd = 0; + int zd = 0; + if (level->getTile(x - 1, y, z) == Tile::obsidian_Id || level->getTile(x + 1, y, z) == Tile::obsidian_Id) xd = 1; + if (level->getTile(x, y, z - 1) == Tile::obsidian_Id || level->getTile(x, y, z + 1) == Tile::obsidian_Id) zd = 1; + + bool twoPosible = false; // two neth portals posible (x and z direction) + if (xd == zd) + { + if (xd == 1) twoPosible = true; + else return false; + } + + bool changedx = false; // changed x so it can be reverted if two portals are posible + if (level->getTile(x - xd, y, z) == 0) + { + changedx = true; + x--; + } + else if (level->getTile(x, y, z - zd) == 0 && !twoPosible) + { + z--; + } + + if (!twoPosible) + { + if (!validPortalFrame(level, x, y, z, xd, zd, actuallySpawn)) return false; + } + else + { + if (!validPortalFrame(level, x, y, z, xd, 0, actuallySpawn)) + { + if (changedx) x++; // revert x (this check wants to check z not x and z) + + if (level->getTile(x, y, z - zd) == 0) z--; + + if (!validPortalFrame(level, x, y, z, 0, zd, actuallySpawn)) + return false; + } + } + return true; } void PortalTile::neighborChanged(Level *level, int x, int y, int z, int type) diff --git a/Minecraft.World/PortalTile.h b/Minecraft.World/PortalTile.h index 7be4320f2..7415efbf2 100644 --- a/Minecraft.World/PortalTile.h +++ b/Minecraft.World/PortalTile.h @@ -13,6 +13,7 @@ public: virtual void updateShape(LevelSource *level, int x, int y, int z, int forceData = -1, shared_ptr forceEntity = shared_ptr()); // 4J added forceData, forceEntity param virtual bool isSolidRender(bool isServerLevel = false); virtual bool isCubeShaped(); + virtual bool validPortalFrame(Level* level, int x, int y, int z, int xd, int zd, bool actuallySpawn); virtual bool trySpawnPortal(Level *level, int x, int y, int z, bool actuallySpawn); virtual void neighborChanged(Level *level, int x, int y, int z, int type); virtual bool shouldRenderFace(LevelSource *level, int x, int y, int z, int face); diff --git a/Minecraft.World/WitherBoss.h b/Minecraft.World/WitherBoss.h index 47e2dff18..e066908ec 100644 --- a/Minecraft.World/WitherBoss.h +++ b/Minecraft.World/WitherBoss.h @@ -105,5 +105,5 @@ public: // 4J Stu - These are required for the BossMob interface virtual float getMaxHealth() { return Monster::getMaxHealth(); }; virtual float getHealth() { return Monster::getHealth(); }; - virtual wstring getAName() { return app.GetString(IDS_WITHER); }; + virtual wstring getAName() { if (hasCustomName()) return getCustomName(); return app.GetString(IDS_WITHER); }; }; \ No newline at end of file diff --git a/README.md b/README.md index 303728adf..560a798a5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,15 @@ ![Legacy Edition Banner](.github/banner.png) # MinecraftConsoles (Legacy Console Edition) -[![Discord](https://img.shields.io/badge/Discord-Join%20Server-5865F2?logo=discord&logoColor=white)](https://discord.gg/jrum7HhegA) +[![Discord](https://img.shields.io/badge/Discord-Join%20Server-5865F2?logo=discord&logoColor=white)](https://discord.gg/dH8AZWGcau) + +--- +## IMPORTANT UPDATE +**This repo was moved to a new org!** + +Please change all links and references from `smartcmd/MinecraftConsoles` to `MCLCE/MinecraftConsoles` instead. + +--- This project is based on source code of Minecraft Legacy Console Edition v1.6.0560.0 (TU19) with some fixes and improvements applied. @@ -9,11 +17,11 @@ The current goal of MinecraftConsoles is to be a multi-platform base for further See our our [Contributor's Guide](./CONTRIBUTING.md) for more information on the goals of this project. -## Download +## Download ### Client -Windows users can download our [Nightly Build](https://github.com/smartcmd/MinecraftConsoles/releases/tag/nightly)! Simply download the `.zip` file and extract it to a folder where you'd like to keep the game. You can set your username in `username.txt` (you'll have to make this file) +Windows users can download our [Nightly Build](https://github.com/MCLCE/MinecraftConsoles/releases/tag/nightly)! Simply download the `.zip` file and extract it to a folder where you'd like to keep the game. You can set your username in `username.txt` (you'll have to make this file) ### Server -If you're looking for Dedicated Server software, download its [Nightly Build here](https://github.com/smartcmd/MinecraftConsoles/releases/tag/nightly-dedicated-server). Similar instructions to the client more or less, though see further down in this README for more info on that. +If you're looking for Dedicated Server software, download its [Nightly Build here](https://github.com/MCLCE/MinecraftConsoles/releases/tag/nightly-dedicated-server). Similar instructions to the client more or less, though see further down in this README for more info on that. ## Platform Support @@ -220,4 +228,4 @@ For more information, see [COMPILE.md](COMPILE.md). ## Star History -[![Star History Chart](https://api.star-history.com/svg?repos=smartcmd/MinecraftConsoles&type=date&legend=top-left)](https://www.star-history.com/?spm=a2c6h.12873639.article-detail.7.7b9d7fabjNxTRk#smartcmd/MinecraftConsoles&type=date&legend=top-left) +[![Star History Chart](https://api.star-history.com/svg?repos=MCLCE/MinecraftConsoles&type=date&legend=top-left)](https://www.star-history.com/?spm=a2c6h.12873639.article-detail.7.7b9d7fabjNxTRk#MCLCE/MinecraftConsoles&type=date&legend=top-left) diff --git a/docker-compose.dedicated-server.ghcr.yml b/docker-compose.dedicated-server.ghcr.yml index 8bcaf4843..f311f834c 100644 --- a/docker-compose.dedicated-server.ghcr.yml +++ b/docker-compose.dedicated-server.ghcr.yml @@ -1,12 +1,12 @@ services: minecraft-lce-dedicated-server: - image: ghcr.io/kuwacom/minecraft-lce-dedicated-server:nightly + image: ghcr.io/smartcmd/minecraft-lce-dedicated-server:nightly container_name: minecraft-lce-dedicated-server restart: unless-stopped tty: true stdin_open: true environment: - TZ: ${TZ:-Asia/Tokyo} + TZ: ${TZ:-Etc/UTC} WINEARCH: win64 WINEPREFIX: /var/opt/wineprefix64 WINEDEBUG: -all @@ -15,12 +15,15 @@ services: # minimum required virtual screen XVFB_DISPLAY: ${XVFB_DISPLAY:-:99} XVFB_SCREEN: ${XVFB_SCREEN:-720x1280x16} + # ip & port the server will run on + SERVER_BIND_IP: ${SERVER_BIND_IP:-0.0.0.0} + SERVER_PORT: ${SERVER_PORT:-25565} volumes: # - wineprefix64:/var/opt/wineprefix64 - ./server-data:/srv/persist ports: - - "25565:25565/tcp" - - "25565:25565/udp" + - "$SERVER_PORT:$SERVER_PORT/tcp" + - "$SERVER_PORT:$SERVER_PORT/udp" stop_grace_period: 30s # volumes: diff --git a/docker-compose.dedicated-server.yml b/docker-compose.dedicated-server.yml index 4a0d33137..23caf26fd 100644 --- a/docker-compose.dedicated-server.yml +++ b/docker-compose.dedicated-server.yml @@ -10,7 +10,7 @@ services: tty: true stdin_open: true environment: - TZ: ${TZ:-Asia/Tokyo} + TZ: ${TZ:-Etc/UTC} WINEARCH: win64 WINEPREFIX: /var/opt/wineprefix64 WINEDEBUG: -all @@ -18,13 +18,16 @@ services: SERVER_CLI_INPUT_MODE: ${SERVER_CLI_INPUT_MODE:-stream} # minimum required virtual screen XVFB_DISPLAY: ${XVFB_DISPLAY:-:99} - XVFB_SCREEN: ${XVFB_SCREEN:-64x64x16} + XVFB_SCREEN: ${XVFB_SCREEN:-720x1280x16} + # ip & port the server will run on + SERVER_BIND_IP: ${SERVER_BIND_IP:-0.0.0.0} + SERVER_PORT: ${SERVER_PORT:-25565} volumes: # - wineprefix64:/var/opt/wineprefix64 - ./server-data:/srv/persist ports: - - "25565:25565/tcp" - - "25565:25565/udp" + - "$SERVER_PORT:$SERVER_PORT/tcp" + - "$SERVER_PORT:$SERVER_PORT/udp" stop_grace_period: 30s # volumes: diff --git a/docker/dedicated-server/entrypoint.sh b/docker/dedicated-server/entrypoint.sh index 26b40da98..0eece2742 100644 --- a/docker/dedicated-server/entrypoint.sh +++ b/docker/dedicated-server/entrypoint.sh @@ -3,9 +3,8 @@ set -euo pipefail SERVER_DIR="/srv/mc" SERVER_EXE="Minecraft.Server.exe" -# ip & port are fixed since they run inside the container -SERVER_PORT="25565" -SERVER_BIND_IP="0.0.0.0" +SERVER_PORT="${SERVER_PORT:-25565}" +SERVER_BIND_IP="${SERVER_BIND_IP:-0.0.0.0}" PERSIST_DIR="/srv/persist" WINE_CMD=""