mirror of
https://github.com/neoStudiosLCE/neoLegacy.git
synced 2026-06-09 02:02:59 +00:00
Merge remote-tracking branch 'itsRevela/main' into upstream-merge
# Conflicts: # Minecraft.Client/Common/Audio/SoundNames.cpp # Minecraft.Client/SheepRenderer.cpp # Minecraft.World/SoundTypes.h # README.md # cmake/CopyAssets.cmake
This commit is contained in:
commit
734f186cd3
|
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
project(MinecraftConsoles LANGUAGES C CXX RC ASM_MASM)
|
||||
project(LCE-Revelations LANGUAGES C CXX RC ASM_MASM)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
|
|
|||
|
|
@ -128,8 +128,6 @@ set(ASSET_FOLDER_PAIRS
|
|||
"${CMAKE_CURRENT_SOURCE_DIR}/music" "music"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Common/Media" "Common/Media"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Common/res" "Common/res"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Common/Trial" "Common/Trial"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Common/Tutorial" "Common/Tutorial"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/${PLATFORM_NAME}Media" "${PLATFORM_NAME}Media"
|
||||
)
|
||||
setup_asset_folder_copy(Minecraft.Client "${ASSET_FOLDER_PAIRS}")
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ const wstring ChatScreen::allowedChars = SharedConstants::acceptableLetters;
|
|||
vector<wstring> ChatScreen::s_chatHistory;
|
||||
int ChatScreen::s_historyIndex = -1;
|
||||
wstring ChatScreen::s_historyDraft;
|
||||
int ChatScreen::s_chatIndex = 0;
|
||||
|
||||
bool ChatScreen::isAllowedChatChar(wchar_t c)
|
||||
{
|
||||
|
|
@ -28,6 +29,8 @@ ChatScreen::ChatScreen()
|
|||
frame = 0;
|
||||
cursorIndex = 0;
|
||||
s_historyIndex = -1;
|
||||
|
||||
ChatScreen::s_chatIndex = 0;
|
||||
}
|
||||
|
||||
void ChatScreen::init()
|
||||
|
|
@ -89,6 +92,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)
|
||||
|
|
@ -140,7 +157,7 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey)
|
|||
cursorIndex--;
|
||||
return;
|
||||
}
|
||||
if (isAllowedChatChar(ch) && static_cast<int>(message.length()) < SharedConstants::maxChatLength)
|
||||
if (isAllowedChatChar(ch) && static_cast<int>(message.length()) < SharedConstants::maxVisibleLength)
|
||||
{
|
||||
message.insert(cursorIndex, 1, ch);
|
||||
cursorIndex++;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ private:
|
|||
static std::vector<wstring> 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:
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@
|
|||
#include "../Minecraft.World/DurangoStats.h"
|
||||
#include "../Minecraft.World/GenericStats.h"
|
||||
#endif
|
||||
#include <regex>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
|
@ -1607,17 +1608,35 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
bool replaceEntitySource = false;
|
||||
bool replaceItem = false;
|
||||
|
||||
static std::wregex IDS_Pattern(LR"(\{\*IDS_(\d+)\*\})"); //maybe theres a better way to do translateable IDS
|
||||
|
||||
int stringArgsSize = packet->m_stringArgs.size();
|
||||
|
||||
wstring playerDisplayName = L"";
|
||||
wstring sourceDisplayName = L"";
|
||||
|
||||
// On platforms other than Xbox One this just sets display name to gamertag
|
||||
if (packet->m_stringArgs.size() >= 1) playerDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[0]);
|
||||
if (packet->m_stringArgs.size() >= 2) sourceDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[1]);
|
||||
if (stringArgsSize >= 1) playerDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[0]);
|
||||
if (stringArgsSize >= 2) sourceDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[1]);
|
||||
|
||||
switch(packet->m_messageType)
|
||||
{
|
||||
case ChatPacket::e_ChatCustom:
|
||||
message = (packet->m_stringArgs.size() >= 1) ? packet->m_stringArgs[0] : L"";
|
||||
case ChatPacket::e_ChatActionBar:
|
||||
if (stringArgsSize >= 1) {
|
||||
message = packet->m_stringArgs[0];
|
||||
|
||||
std::wsmatch match;
|
||||
while (std::regex_search(message, match, IDS_Pattern)) {
|
||||
message = replaceAll(message, match[0], app.GetString(std::stoi(match[1].str())));
|
||||
}
|
||||
|
||||
message = app.EscapeHTMLString(message); //do this to enforce escaped string
|
||||
message = app.FormatChatMessage(message); //this needs to be last cause it converts colors to html colors that would have been escaped
|
||||
} else {
|
||||
message = L"empty message";
|
||||
}
|
||||
displayOnGui = (packet->m_messageType == ChatPacket::e_ChatCustom);
|
||||
break;
|
||||
case ChatPacket::e_ChatBedOccupied:
|
||||
message = app.GetString(IDS_TILE_BED_OCCUPIED);
|
||||
|
|
@ -1967,7 +1986,7 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
|
||||
if(replacePlayer)
|
||||
{
|
||||
message = replaceAll(message,L"{*PLAYER*}",playerDisplayName);
|
||||
message = replaceAll(message,L"{*PLAYER*}", playerDisplayName);
|
||||
}
|
||||
|
||||
if(replaceEntitySource)
|
||||
|
|
@ -2002,7 +2021,9 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
// flag that a message is a death message
|
||||
bool bIsDeathMessage = (packet->m_messageType>=ChatPacket::e_ChatDeathInFire) && (packet->m_messageType<=ChatPacket::e_ChatDeathIndirectMagicItem);
|
||||
|
||||
if( displayOnGui ) minecraft->gui->addMessage(message,m_userIndex, bIsDeathMessage);
|
||||
if( displayOnGui ) minecraft->gui->addMessage(message, m_userIndex, bIsDeathMessage);
|
||||
|
||||
if (!displayOnGui && !message.empty()) minecraft->gui->setActionBarMessage(message);
|
||||
}
|
||||
|
||||
void ClientConnection::handleAnimate(shared_ptr<AnimatePacket> packet)
|
||||
|
|
|
|||
|
|
@ -270,6 +270,8 @@ const WCHAR *ConsoleSoundEngine::wchSoundNames[eSoundType_MAX]=
|
|||
L"item.armor.equip_generic4",
|
||||
L"item.armor.equip_generic5",
|
||||
L"item.armor.equip_generic6"
|
||||
|
||||
L"damage.critical", //eSoundType_DAMAGE_CRITICAL,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -6786,6 +6786,87 @@ wstring CMinecraftApp::FormatHTMLString(int iPad, const wstring &desc, int shado
|
|||
return text;
|
||||
}
|
||||
|
||||
//found list of html escapes at https://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-in-html
|
||||
wstring CMinecraftApp::EscapeHTMLString(const wstring& desc)
|
||||
{
|
||||
static std::unordered_map<wchar_t, wchar_t*> replacementMap = {
|
||||
{L'&', L"&"},
|
||||
{L'<', L"<"},
|
||||
{L'>', L">"},
|
||||
{L'\"', L"""},
|
||||
{L'\'', L"'"},
|
||||
};
|
||||
|
||||
wstring finalString = L"";
|
||||
for (int i = 0; i < desc.size(); i++) {
|
||||
wchar_t _char = desc[i];
|
||||
auto it = replacementMap.find(_char);
|
||||
|
||||
if (it != replacementMap.end()) finalString += it->second;
|
||||
else finalString += _char;
|
||||
}
|
||||
|
||||
return finalString;
|
||||
}
|
||||
|
||||
wstring CMinecraftApp::FormatChatMessage(const wstring& desc, bool applyColor)
|
||||
{
|
||||
static std::wstring_view colorFormatString = L"<font color=\"#%08x\" shadowcolor=\"#%08x\">";
|
||||
|
||||
wstring results = desc;
|
||||
wchar_t replacements[64];
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_0), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§0", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_1), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§1", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_2), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§2", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_3), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§3", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_4), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§4", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_5), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§5", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_6), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§6", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_7), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§7", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_8), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§8", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_9), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§9", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_a), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§a", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_b), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§b", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_c), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§c", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_d), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§d", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_e), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§e", replacements);
|
||||
|
||||
swprintf(replacements, 64, (applyColor ? colorFormatString.data() : L""), GetHTMLColour(eHTMLColor_f), 0xFFFFFFFF);
|
||||
results = replaceAll(results, L"§f", replacements);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
wstring CMinecraftApp::GetActionReplacement(int iPad, unsigned char ucAction)
|
||||
{
|
||||
unsigned int input = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal(iPad) ,ucAction);
|
||||
|
|
|
|||
|
|
@ -567,7 +567,9 @@ public:
|
|||
int GetHTMLColour(eMinecraftColour colour);
|
||||
int GetHTMLColor(eMinecraftColour colour) { return GetHTMLColour(colour); }
|
||||
int GetHTMLFontSize(EHTMLFontSize size);
|
||||
wstring FormatHTMLString(int iPad, const wstring &desc, int shadowColour = 0xFFFFFFFF);
|
||||
wstring FormatHTMLString(int iPad, const wstring& desc, int shadowColour = 0xFFFFFFFF);
|
||||
wstring EscapeHTMLString(const wstring &desc);
|
||||
wstring FormatChatMessage(const wstring& desc, bool applyColor = true);
|
||||
wstring GetActionReplacement(int iPad, unsigned char ucAction);
|
||||
wstring GetVKReplacement(unsigned int uiVKey);
|
||||
wstring GetIconReplacement(unsigned int uiIcon);
|
||||
|
|
|
|||
|
|
@ -204,6 +204,12 @@ bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParame
|
|||
ProfileManager.SetDeferredSignoutEnabled(true);
|
||||
#endif
|
||||
|
||||
// Clear any stale cancel flag latched by the previous join's progress
|
||||
// UI teardown, otherwise the next join's first tick insta-closes.
|
||||
EnterCriticalSection(&bCancelRequestedCS);
|
||||
g_NetworkManager.m_bCancelRequested = false;
|
||||
LeaveCriticalSection(&bCancelRequestedCS);
|
||||
|
||||
int64_t seed = 0;
|
||||
bool dedicatedNoLocalHostPlayer = false;
|
||||
if (lpParameter != nullptr)
|
||||
|
|
|
|||
|
|
@ -134,7 +134,14 @@ void CPlatformNetworkManagerStub::NotifyPlayerLeaving(IQNetPlayer* pQNetPlayer)
|
|||
if (socket != nullptr)
|
||||
{
|
||||
if (m_pIQNet->IsHost())
|
||||
{
|
||||
g_NetworkManager.CloseConnection(networkPlayer);
|
||||
|
||||
// Propagate the TCP drop to the game Socket so any orphaned
|
||||
// PendingConnection at this smallId cleans up before its login
|
||||
// timer fires and leaks a DisconnectPacket to the reused slot.
|
||||
socket->close(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pIQNet->IsHost())
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ IUIScene_AbstractContainerMenu::IUIScene_AbstractContainerMenu()
|
|||
m_pointerPos.y = 0.0f;
|
||||
m_bPointerDrivenByMouse = false;
|
||||
|
||||
m_iLastMouseTickTimeNs = -1;
|
||||
}
|
||||
|
||||
IUIScene_AbstractContainerMenu::~IUIScene_AbstractContainerMenu()
|
||||
|
|
@ -311,6 +312,21 @@ void IUIScene_AbstractContainerMenu::handleEnchantButton(int slot, int iPad) {
|
|||
|
||||
void IUIScene_AbstractContainerMenu::onMouseTick()
|
||||
{
|
||||
// Frame-rate independent cursor input, normalized to a 60Hz reference frame.
|
||||
const int64_t kRefFrameNs = 1000000000LL / 60;
|
||||
const int64_t kMinDeltaNs = 1000000LL;
|
||||
const int64_t kMaxDeltaNs = 100000000LL;
|
||||
int64_t iNowNs = System::nanoTime();
|
||||
float fFrameScale = 1.0f;
|
||||
if ( m_iLastMouseTickTimeNs > 0 )
|
||||
{
|
||||
int64_t iDeltaNs = iNowNs - m_iLastMouseTickTimeNs;
|
||||
if ( iDeltaNs < kMinDeltaNs ) iDeltaNs = kMinDeltaNs;
|
||||
if ( iDeltaNs > kMaxDeltaNs ) iDeltaNs = kMaxDeltaNs;
|
||||
fFrameScale = static_cast<float>(iDeltaNs) / static_cast<float>(kRefFrameNs);
|
||||
}
|
||||
m_iLastMouseTickTimeNs = iNowNs;
|
||||
|
||||
Minecraft *pMinecraft = Minecraft::GetInstance();
|
||||
if( pMinecraft->localgameModes[getPad()] != nullptr)
|
||||
{
|
||||
|
|
@ -467,10 +483,10 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
|
|||
// The SD/splitscreen scenes are approximately 0.6 times the size of the fullscreen on
|
||||
if(!RenderManager.IsHiDef() || app.GetLocalPlayerCount() > 1) fInputScale *= 0.6f;
|
||||
|
||||
fInputX *= fInputScale;
|
||||
fInputY *= fInputScale;
|
||||
fInputX *= fInputScale * fFrameScale;
|
||||
fInputY *= fInputScale * fFrameScale;
|
||||
|
||||
#ifdef USE_POINTER_ACCEL
|
||||
#ifdef USE_POINTER_ACCEL
|
||||
m_fPointerAccelX += fInputX / 50.0f;
|
||||
m_fPointerAccelY += fInputY / 50.0f;
|
||||
|
||||
|
|
@ -1317,36 +1333,8 @@ void IUIScene_AbstractContainerMenu::onMouseTick()
|
|||
vPointerPos.x -= m_fPointerImageOffsetX;
|
||||
vPointerPos.y -= m_fPointerImageOffsetY;
|
||||
|
||||
// Update pointer position.
|
||||
// 4J-PB - do not allow sub pixel positions or we get broken lines in box edges
|
||||
|
||||
// problem here when sensitivity is low - we'll be moving a sub pixel size, so it'll clamp, and we'll never move. In that case, move 1 pixel
|
||||
if(fInputDirX!=0.0f)
|
||||
{
|
||||
if(fInputDirX==1.0f)
|
||||
{
|
||||
vPointerPos.x+=0.999999f;
|
||||
}
|
||||
else
|
||||
{
|
||||
vPointerPos.x-=0.999999f;
|
||||
}
|
||||
}
|
||||
|
||||
if(fInputDirY!=0.0f)
|
||||
{
|
||||
if(fInputDirY==1.0f)
|
||||
{
|
||||
vPointerPos.y+=0.999999f;
|
||||
}
|
||||
else
|
||||
{
|
||||
vPointerPos.y-=0.999999f;
|
||||
}
|
||||
}
|
||||
|
||||
vPointerPos.x = static_cast<float>(floor(vPointerPos.x + 0.5f));
|
||||
vPointerPos.y = static_cast<float>(floor(vPointerPos.y + 0.5f));
|
||||
// Keep sub-pixel float state so deltas <1px accumulate across frames; the renderer
|
||||
// truncates to integer pixels when emitting the Iggy mouse event.
|
||||
m_pointerPos = vPointerPos;
|
||||
|
||||
adjustPointerForSafeZone();
|
||||
|
|
|
|||
|
|
@ -146,6 +146,8 @@ protected:
|
|||
|
||||
int m_iConsectiveInputTicks;
|
||||
|
||||
int64_t m_iLastMouseTickTimeNs;
|
||||
|
||||
// Used for detecting quick "taps" in a direction, should jump cursor to next slot.
|
||||
enum ETapState
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include "UIController.h"
|
||||
#include <ChatScreen.h>
|
||||
#include "UI.h"
|
||||
#include "UIScene.h"
|
||||
#include "UIControl_Slider.h"
|
||||
|
|
@ -1459,6 +1460,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
|
||||
|
|
|
|||
|
|
@ -490,18 +490,21 @@ SCreditTextItemDef UIScene_Credits::gs_aCreditDefs[MAX_CREDIT_STRINGS] =
|
|||
#endif
|
||||
{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"LCE-Revelations", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eExtraLargeText},
|
||||
{L"", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
|
||||
{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"mattsumi", NO_TRANSLATED_STRING, NO_TRANSLATED_STRING, eSmallText},
|
||||
{L"itsRevela", 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"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"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},
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "../../EnderDragonRenderer.h"
|
||||
#include "../../../Minecraft.World/net.minecraft.world.inventory.h"
|
||||
#include "../../../Minecraft.World/StringHelpers.h"
|
||||
#include <ChatScreen.h>
|
||||
|
||||
UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
|
||||
{
|
||||
|
|
@ -23,8 +24,10 @@ UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UISce
|
|||
for(unsigned int i = 0; i < CHAT_LINES_COUNT; ++i)
|
||||
{
|
||||
m_labelChatText[i].init(L"");
|
||||
IggyValueSetBooleanRS(m_labelChatText[i].getIggyValuePath(), 0, "m_bUseHtmlText", true);
|
||||
}
|
||||
m_labelJukebox.init(L"");
|
||||
IggyValueSetBooleanRS(m_labelJukebox.getIggyValuePath(), 0, "m_bUseHtmlText", true);
|
||||
|
||||
addTimer(0, 100);
|
||||
}
|
||||
|
|
@ -787,16 +790,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<ChatScreen*>(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.
|
||||
|
|
@ -804,9 +822,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ private:
|
|||
bool m_bSplitscreen;
|
||||
|
||||
protected:
|
||||
UIControl_Label m_labelChatText[CHAT_LINES_COUNT];
|
||||
UIControl_HTMLLabel m_labelChatText[CHAT_LINES_COUNT];
|
||||
UIControl_Label m_labelJukebox;
|
||||
UIControl m_controlLabelBackground[CHAT_LINES_COUNT];
|
||||
UIControl_Label m_labelDisplayName;
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ void EntityTracker::addEntity(shared_ptr<Entity> e, int range, int updateInterva
|
|||
{
|
||||
assert(false); // Entity already tracked
|
||||
}
|
||||
if( e->entityId >= 2048 )
|
||||
if( e->entityId >= 16384 )
|
||||
{
|
||||
__debugbreak();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -404,6 +404,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<int>(cleanStr.length()); ++i)
|
||||
{
|
||||
// Map character
|
||||
|
|
@ -481,6 +483,8 @@ void Font::draw(const wstring &str, bool dropShadow, int initialColor)
|
|||
}
|
||||
}
|
||||
|
||||
t->setMipmapEnable(prev); //Reinstates previously used enabled value - Botch
|
||||
|
||||
t->end();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1209,7 +1209,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)
|
||||
|
|
@ -1218,6 +1231,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);
|
||||
|
||||
|
|
@ -1579,6 +1595,13 @@ float Gui::getOpacity(int iPad, DWORD index)
|
|||
return opacityPercentage;
|
||||
}
|
||||
|
||||
//just like java functionality it overwrites the jukebox label
|
||||
void Gui::setActionBarMessage(wstring message)
|
||||
{
|
||||
overlayMessageString = message;
|
||||
overlayMessageTime = 20 * 4; //idk how long it should last, need to check java usage
|
||||
}
|
||||
|
||||
float Gui::getJukeboxOpacity(int iPad)
|
||||
{
|
||||
float t = overlayMessageTime - lastTickA;
|
||||
|
|
@ -1594,7 +1617,7 @@ void Gui::setNowPlaying(const wstring& string)
|
|||
// overlayMessageString = L"Now playing: " + string;
|
||||
overlayMessageString = app.GetString(IDS_NOWPLAYING) + string;
|
||||
overlayMessageTime = 20 * 3;
|
||||
animateOverlayMessageColor = true;
|
||||
animateOverlayMessageColor = true; //appears to be unused, @DrPerkyLegit plans to add in later pr
|
||||
}
|
||||
|
||||
void Gui::displayClientMessage(int messageId, int iPad)
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ private:
|
|||
static const int m_iMaxMessageWidth = 280;
|
||||
static ItemRenderer *itemRenderer;
|
||||
vector<GuiMessage> guiMessages[XUSER_MAX_COUNT];
|
||||
int chatIndex = 0;
|
||||
Random *random;
|
||||
|
||||
Minecraft *minecraft;
|
||||
|
|
@ -63,6 +64,8 @@ public:
|
|||
wstring getMessage(int iPad, DWORD index) { return guiMessages[iPad].at(index).string; }
|
||||
float getOpacity(int iPad, DWORD index);
|
||||
|
||||
void setActionBarMessage(wstring message); //uses jukebox label
|
||||
|
||||
wstring getJukeboxMessage(int iPad) { return overlayMessageString; }
|
||||
float getJukeboxOpacity(int iPad);
|
||||
|
||||
|
|
|
|||
|
|
@ -1544,8 +1544,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<<MINECRAFT_ACTION_PAUSEMENU;
|
||||
app.DebugPrintf("PAUSE PRESSED (keyboard) - ipad = %d\n",i);
|
||||
if (dynamic_cast<ChatScreen*>(getScreen()) != nullptr) {
|
||||
setScreen(nullptr);
|
||||
} else {
|
||||
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_PAUSEMENU;
|
||||
app.DebugPrintf("PAUSE PRESSED (keyboard) - ipad = %d\n",i);
|
||||
}
|
||||
}
|
||||
|
||||
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_THIRD_PERSON))
|
||||
|
|
|
|||
|
|
@ -972,7 +972,7 @@ void PlayerConnection::handleChat(shared_ptr<ChatPacket> packet)
|
|||
}
|
||||
#else
|
||||
wstring formatted = L"<" + player->name + L"> " + message;
|
||||
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(formatted)));
|
||||
server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(app.FormatChatMessage(formatted, false))));
|
||||
#endif
|
||||
chatSpamTickCount += SharedConstants::TICKS_PER_SECOND;
|
||||
if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10)
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ void Screen::updateEvents()
|
|||
static bool s_arrowFirstRepeat[2] = { false, false };
|
||||
const DWORD ARROW_REPEAT_DELAY_MS = 250;
|
||||
const DWORD ARROW_REPEAT_INTERVAL_MS = 50;
|
||||
DWORD now = GetTickCount();
|
||||
DWORD now = GetTickCount64();
|
||||
|
||||
// Poll keyboard events (special keys that may not come through WM_CHAR, e.g. Escape, arrows)
|
||||
for (int vk = 0; vk < 256; vk++)
|
||||
|
|
|
|||
|
|
@ -295,12 +295,12 @@ void ServerPlayer::flagEntitiesToBeRemoved(unsigned int *flags, bool *removedFou
|
|||
{
|
||||
*removedFound = true;
|
||||
// before this left 192 bytes uninitialized!!!!!
|
||||
memset(flags, 0, (2048 / 32) * sizeof(unsigned int));
|
||||
memset(flags, 0, (16384 / 32) * sizeof(unsigned int));
|
||||
}
|
||||
|
||||
for(int index : entitiesToRemove)
|
||||
{
|
||||
if( index < 2048 )
|
||||
if( index < 16384 )
|
||||
{
|
||||
unsigned int i = index / 32;
|
||||
unsigned int j = index % 32;
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ void Settings::saveProperties()
|
|||
if (!stream.is_open())
|
||||
return;
|
||||
|
||||
stream << "# MinecraftConsoles dedicated server properties\r\n";
|
||||
stream << "# LCE-Revelations dedicated server properties\r\n";
|
||||
for (unordered_map<wstring, wstring>::const_iterator it = properties.begin(); it != properties.end(); ++it)
|
||||
{
|
||||
string key = string(wstringtochararray(it->first));
|
||||
|
|
|
|||
|
|
@ -13,11 +13,10 @@ SheepRenderer::SheepRenderer(Model *model, Model *armor, float shadow) : MobRend
|
|||
|
||||
int SheepRenderer::prepareArmor(shared_ptr<LivingEntity> _sheep, int layer, float a)
|
||||
{
|
||||
// 4J - dynamic cast required because we aren't using templates/generics in our version
|
||||
shared_ptr<Sheep> sheep = dynamic_pointer_cast<Sheep>(_sheep);
|
||||
|
||||
if (layer == 0 && !sheep->isSheared() &&
|
||||
!sheep->isInvisibleTo(Minecraft::GetInstance()->player)) // 4J-JEV: Todo, merge with java fix (for invisible sheep armour) in '1.7.5'.
|
||||
!sheep->isInvisibleTo(Minecraft::GetInstance()->player))
|
||||
{
|
||||
MemSect(31);
|
||||
bindTexture(&SHEEP_FUR_LOCATION);
|
||||
|
|
@ -25,9 +24,8 @@ int SheepRenderer::prepareArmor(shared_ptr<LivingEntity> _sheep, int layer, floa
|
|||
|
||||
if (sheep->hasCustomName() && sheep->getCustomName().compare(L"jeb_") == 0)
|
||||
{
|
||||
// easter egg...
|
||||
int colorDuration = 25;
|
||||
int value = (sheep->tickCount / colorDuration);
|
||||
int value = (sheep->tickCount / colorDuration) + sheep->entityId;
|
||||
int c1 = value % Sheep::COLOR_LENGTH;
|
||||
int c2 = (value + 1) % Sheep::COLOR_LENGTH;
|
||||
float subStep = ((sheep->tickCount % colorDuration) + a) / static_cast<float>(colorDuration);
|
||||
|
|
@ -64,4 +62,4 @@ void SheepRenderer::render(shared_ptr<Entity> mob, double x, double y, double z,
|
|||
ResourceLocation *SheepRenderer::getTextureLocation(shared_ptr<Entity> mob)
|
||||
{
|
||||
return &SHEEP_LOCATION;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include <dxgi1_4.h> // IDXGISwapChain3 for SetColorSpace1
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <ShellScalingApi.h>
|
||||
|
|
@ -58,6 +60,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
|
||||
|
|
@ -471,7 +480,6 @@ ID3D11Device* g_pd3dDevice = nullptr;
|
|||
ID3D11DeviceContext* g_pImmediateContext = nullptr;
|
||||
IDXGISwapChain* g_pSwapChain = nullptr;
|
||||
bool g_bVSync = false;
|
||||
static bool g_bTearingSupported = false;
|
||||
static bool g_bPendingExclusiveFullscreen = false;
|
||||
static bool g_bPendingExclusiveFullscreenValue = false;
|
||||
|
||||
|
|
@ -546,50 +554,15 @@ static bool TakeScreenshot(wstring& outFilename)
|
|||
return success;
|
||||
}
|
||||
|
||||
// COM proxy for IDXGISwapChain — delegates all calls to the real swap chain,
|
||||
// but overrides Present() to set SyncInterval=1 when VSync is enabled.
|
||||
// Avoids vtable patching, which conflicts with the D3D11 debug layer.
|
||||
static class SwapChainVSyncProxy : public IDXGISwapChain
|
||||
{
|
||||
public:
|
||||
void SetTarget(IDXGISwapChain* pReal) { m_pReal = pReal; }
|
||||
|
||||
// IUnknown
|
||||
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject) override { return m_pReal->QueryInterface(riid, ppvObject); }
|
||||
ULONG STDMETHODCALLTYPE AddRef() override { return m_pReal->AddRef(); }
|
||||
ULONG STDMETHODCALLTYPE Release() override { return m_pReal->Release(); }
|
||||
|
||||
// IDXGIObject
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateData(REFGUID Name, UINT DataSize, const void* pData) override { return m_pReal->SetPrivateData(Name, DataSize, pData); }
|
||||
HRESULT STDMETHODCALLTYPE SetPrivateDataInterface(REFGUID Name, const IUnknown* pUnknown) override { return m_pReal->SetPrivateDataInterface(Name, pUnknown); }
|
||||
HRESULT STDMETHODCALLTYPE GetPrivateData(REFGUID Name, UINT* pDataSize, void* pData) override { return m_pReal->GetPrivateData(Name, pDataSize, pData); }
|
||||
HRESULT STDMETHODCALLTYPE GetParent(REFIID riid, void** ppParent) override { return m_pReal->GetParent(riid, ppParent); }
|
||||
|
||||
// IDXGIDeviceSubObject
|
||||
HRESULT STDMETHODCALLTYPE GetDevice(REFIID riid, void** ppDevice) override { return m_pReal->GetDevice(riid, ppDevice); }
|
||||
|
||||
// IDXGISwapChain
|
||||
// NOTE: The 4J RenderManager library hardcodes SyncInterval=1 and does NOT
|
||||
// dispatch Present through this proxy's vtable. VSync control is handled
|
||||
// directly in the main loop (see the Present-the-frame block) instead.
|
||||
HRESULT STDMETHODCALLTYPE Present(UINT SyncInterval, UINT Flags) override { return m_pReal->Present(SyncInterval, Flags); }
|
||||
HRESULT STDMETHODCALLTYPE GetBuffer(UINT Buffer, REFIID riid, void** ppSurface) override { return m_pReal->GetBuffer(Buffer, riid, ppSurface); }
|
||||
HRESULT STDMETHODCALLTYPE SetFullscreenState(BOOL Fullscreen, IDXGIOutput* pTarget) override { return m_pReal->SetFullscreenState(Fullscreen, pTarget); }
|
||||
HRESULT STDMETHODCALLTYPE GetFullscreenState(BOOL* pFullscreen, IDXGIOutput** ppTarget) override { return m_pReal->GetFullscreenState(pFullscreen, ppTarget); }
|
||||
HRESULT STDMETHODCALLTYPE GetDesc(DXGI_SWAP_CHAIN_DESC* pDesc) override { return m_pReal->GetDesc(pDesc); }
|
||||
HRESULT STDMETHODCALLTYPE ResizeBuffers(UINT BufferCount, UINT Width, UINT Height, DXGI_FORMAT NewFormat, UINT SwapChainFlags) override { return m_pReal->ResizeBuffers(BufferCount, Width, Height, NewFormat, SwapChainFlags); }
|
||||
HRESULT STDMETHODCALLTYPE ResizeTarget(const DXGI_MODE_DESC* pNewTargetParameters) override { return m_pReal->ResizeTarget(pNewTargetParameters); }
|
||||
HRESULT STDMETHODCALLTYPE GetContainingOutput(IDXGIOutput** ppOutput) override { return m_pReal->GetContainingOutput(ppOutput); }
|
||||
HRESULT STDMETHODCALLTYPE GetFrameStatistics(DXGI_FRAME_STATISTICS* pStats) override { return m_pReal->GetFrameStatistics(pStats); }
|
||||
HRESULT STDMETHODCALLTYPE GetLastPresentCount(UINT* pLastPresentCount) override { return m_pReal->GetLastPresentCount(pLastPresentCount); }
|
||||
|
||||
private:
|
||||
IDXGISwapChain* m_pReal = nullptr;
|
||||
} g_swapChainProxy;
|
||||
|
||||
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 };
|
||||
|
||||
// True when the swap chain is in DXGI exclusive fullscreen. Lets ResizeD3D
|
||||
// skip its destroy-and-recreate path, which would break exclusive ownership.
|
||||
static bool g_bDxgiExclusiveFullscreen = false;
|
||||
|
||||
//
|
||||
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
|
||||
|
|
@ -937,33 +910,30 @@ HRESULT InitDevice()
|
|||
};
|
||||
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
|
||||
|
||||
// Check tearing support before device/swap chain creation
|
||||
{
|
||||
IDXGIFactory5* factory5 = nullptr;
|
||||
if (SUCCEEDED(CreateDXGIFactory1(__uuidof(IDXGIFactory5), (void**)&factory5)))
|
||||
{
|
||||
BOOL allowTearing = FALSE;
|
||||
if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing))))
|
||||
g_bTearingSupported = (allowTearing == TRUE);
|
||||
factory5->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// Use the legacy bitblt DISCARD swap model (SwapEffect left as default 0).
|
||||
// DXGI_SWAP_EFFECT_FLIP_DISCARD gives lower latency and tearing support, but
|
||||
// takes exclusive ownership of the HWND — which makes window resize via
|
||||
// CreateSwapChain fail with E_ACCESSDENIED and ResizeBuffers fail with
|
||||
// DXGI_ERROR_INVALID_CALL (the closed-source 4J Renderer holds hidden
|
||||
// backbuffer refs we can't release). Bitblt DISCARD has no HWND lock, so
|
||||
// the "destroy old, create new" resize path in ResizeD3D() works cleanly.
|
||||
// VSync toggle still works via the SyncInterval parameter on Present().
|
||||
// RefreshRate=0/0 so DXGI matches the current display mode. Hardcoding a
|
||||
// rate would force a mode switch on SetFullscreenState, which can produce
|
||||
// "input signal out of range" errors on high-refresh monitors.
|
||||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory( &sd, sizeof( sd ) );
|
||||
sd.BufferCount = 2;
|
||||
sd.BufferCount = 1;
|
||||
sd.BufferDesc.Width = width;
|
||||
sd.BufferDesc.Height = height;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 0;
|
||||
sd.BufferDesc.RefreshRate.Denominator = 0;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
|
||||
sd.OutputWindow = g_hWnd;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.Windowed = TRUE;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
sd.Flags = g_bTearingSupported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
|
||||
|
||||
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
|
||||
{
|
||||
|
|
@ -1024,8 +994,7 @@ HRESULT InitDevice()
|
|||
vp.TopLeftY = 0;
|
||||
g_pImmediateContext->RSSetViewports( 1, &vp );
|
||||
|
||||
g_swapChainProxy.SetTarget(g_pSwapChain);
|
||||
RenderManager.Initialise(g_pd3dDevice, &g_swapChainProxy);
|
||||
RenderManager.Initialise(g_pd3dDevice, g_pSwapChain);
|
||||
|
||||
PostProcesser::GetInstance().Init();
|
||||
|
||||
|
|
@ -1041,7 +1010,7 @@ void Render()
|
|||
const float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; //red,green,blue,alpha
|
||||
|
||||
g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
|
||||
g_pSwapChain->Present(0, g_bTearingSupported ? DXGI_PRESENT_ALLOW_TEARING : 0);
|
||||
g_pSwapChain->Present(0, 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
|
@ -1052,6 +1021,9 @@ static bool ResizeD3D(int newW, int newH)
|
|||
if (newW <= 0 || newH <= 0) return false;
|
||||
if (!g_pSwapChain) return false;
|
||||
if (!g_bResizeReady) return false;
|
||||
// In exclusive fullscreen the swap chain must not be recreated.
|
||||
if (g_bDxgiExclusiveFullscreen)
|
||||
return false;
|
||||
|
||||
int bbW = newW;
|
||||
int bbH = newH;
|
||||
|
|
@ -1081,11 +1053,11 @@ static bool ResizeD3D(int newW, int newH)
|
|||
|
||||
// Verify offsets by checking device and swap chain pointers
|
||||
ID3D11Device** ppRM_Device = (ID3D11Device**)(pRM + 0x10);
|
||||
if (*ppRM_Device != g_pd3dDevice || *ppRM_SC != (IDXGISwapChain*)&g_swapChainProxy)
|
||||
if (*ppRM_Device != g_pd3dDevice || *ppRM_SC != g_pSwapChain)
|
||||
{
|
||||
app.DebugPrintf("[RESIZE] ERROR: RenderManager offset verification failed! "
|
||||
"device=%p (expected %p) swapchain=%p (expected %p)\n",
|
||||
*ppRM_Device, g_pd3dDevice, *ppRM_SC, (IDXGISwapChain*)&g_swapChainProxy);
|
||||
*ppRM_Device, g_pd3dDevice, *ppRM_SC, g_pSwapChain);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1116,61 +1088,63 @@ static bool ResizeD3D(int newW, int newH)
|
|||
|
||||
gdraw_D3D11_PreReset();
|
||||
|
||||
// Get IDXGIFactory from the existing device BEFORE destroying the old swap
|
||||
// chain. If anything fails before we have a new swap chain, we abort
|
||||
// without destroying the old one — leaving the Renderer in a valid
|
||||
// (old-size) state.
|
||||
IDXGISwapChain* pOldSwapChain = g_pSwapChain;
|
||||
bool success = false;
|
||||
HRESULT hr;
|
||||
|
||||
// Create a brand-new swap chain instead of ResizeBuffers.
|
||||
// ResizeBuffers requires ALL backbuffer refs released, but the closed-source
|
||||
// Renderer holds hidden refs we can't track — causing DXGI_ERROR_INVALID_CALL
|
||||
// and leaving the Renderer with NULL views (black screen).
|
||||
// Creating a new swap chain orphans the old backbuffer (tiny leak) but avoids
|
||||
// the need to release every hidden reference.
|
||||
{
|
||||
IDXGIDevice* dxgiDevice = NULL;
|
||||
IDXGIAdapter* dxgiAdapter = NULL;
|
||||
IDXGIFactory* dxgiFactory = NULL;
|
||||
hr = g_pd3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
|
||||
if (FAILED(hr)) goto postReset;
|
||||
hr = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter);
|
||||
dxgiDevice->Release();
|
||||
if (FAILED(hr)) goto postReset;
|
||||
hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory);
|
||||
dxgiAdapter->Release();
|
||||
if (FAILED(hr)) goto postReset;
|
||||
IDXGIDevice* dxgiDevice = NULL;
|
||||
IDXGIAdapter* dxgiAdapter = NULL;
|
||||
IDXGIFactory* dxgiFactory = NULL;
|
||||
hr = g_pd3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
|
||||
if (FAILED(hr)) goto postReset;
|
||||
hr = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter);
|
||||
if (FAILED(hr)) { dxgiDevice->Release(); goto postReset; }
|
||||
hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory);
|
||||
dxgiAdapter->Release();
|
||||
dxgiDevice->Release();
|
||||
if (FAILED(hr)) goto postReset;
|
||||
|
||||
// Create a brand-new swap chain at the target size and swap it in.
|
||||
// Must use the SAME swap-chain config as InitDevice (legacy bitblt
|
||||
// DISCARD model), otherwise DXGI may return E_ACCESSDENIED. The
|
||||
// Renderer's old RTV/SRV/DSV are intentionally NOT released here — they
|
||||
// become orphaned with the old swap chain (tiny leak, but avoids
|
||||
// fighting unknown refs inside the closed-source Renderer library).
|
||||
{
|
||||
DXGI_SWAP_CHAIN_DESC sd = {};
|
||||
sd.BufferCount = 2;
|
||||
sd.BufferCount = 1;
|
||||
sd.BufferDesc.Width = bbW;
|
||||
sd.BufferDesc.Height = bbH;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
// RefreshRate=0/0 matches InitDevice; see comment there.
|
||||
sd.BufferDesc.RefreshRate.Numerator = 0;
|
||||
sd.BufferDesc.RefreshRate.Denominator = 0;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
|
||||
sd.OutputWindow = g_hWnd;
|
||||
sd.SampleDesc.Count = 1;
|
||||
sd.SampleDesc.Quality = 0;
|
||||
sd.Windowed = TRUE;
|
||||
sd.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
sd.Flags = g_bTearingSupported ? DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING : 0;
|
||||
|
||||
IDXGISwapChain* pNewSwapChain = NULL;
|
||||
hr = dxgiFactory->CreateSwapChain(g_pd3dDevice, &sd, &pNewSwapChain);
|
||||
dxgiFactory->Release();
|
||||
if (FAILED(hr))
|
||||
if (FAILED(hr) || pNewSwapChain == NULL)
|
||||
{
|
||||
app.DebugPrintf("[RESIZE] CreateSwapChain FAILED hr=0x%08X\n", (unsigned)hr);
|
||||
app.DebugPrintf("[RESIZE] CreateSwapChain FAILED hr=0x%08X — keeping old swap chain\n", (unsigned)hr);
|
||||
goto postReset;
|
||||
}
|
||||
|
||||
// Destroy old, install new
|
||||
// New swap chain created successfully — NOW destroy the old one.
|
||||
pOldSwapChain->Release();
|
||||
g_pSwapChain = pNewSwapChain;
|
||||
g_swapChainProxy.SetTarget(g_pSwapChain);
|
||||
}
|
||||
|
||||
// Patch Renderer's swap chain pointer (use proxy so VSync override stays active)
|
||||
*ppRM_SC = &g_swapChainProxy;
|
||||
// Patch Renderer's swap chain pointer to the new raw swap chain.
|
||||
*ppRM_SC = g_pSwapChain;
|
||||
|
||||
// Create render target views from new backbuffer
|
||||
{
|
||||
|
|
@ -1364,18 +1338,99 @@ void SetExclusiveFullscreen(bool enabled)
|
|||
g_bPendingExclusiveFullscreenValue = enabled;
|
||||
}
|
||||
|
||||
// Uses borderless fullscreen (ToggleFullscreen) rather than DXGI SetFullscreenState.
|
||||
// With DXGI_SWAP_EFFECT_FLIP_DISCARD + DXGI_PRESENT_ALLOW_TEARING, borderless
|
||||
// fullscreen gets the same direct-flip path as exclusive fullscreen on Windows 10+ —
|
||||
// identical latency and uncapped FPS. True DXGI exclusive fullscreen is blocked by
|
||||
// the 4J Renderer holding hidden backbuffer references that prevent ResizeBuffers.
|
||||
// Enter or leave true DXGI exclusive fullscreen. With our bitblt swap chain,
|
||||
// Present(SyncInterval=0) in exclusive mode produces real screen tearing via
|
||||
// direct scanout (DWM is out of the pipeline). Flip mode with ALLOW_TEARING
|
||||
// would also work but is blocked by the 4J Renderer's deferred context refs
|
||||
// on the backbuffer, which DXGI's ResizeBuffers cannot release.
|
||||
static void ApplyExclusiveFullscreen(bool enabled)
|
||||
{
|
||||
// Toggle into/out of borderless fullscreen if state doesn't match
|
||||
if (enabled && !g_isFullscreen)
|
||||
ToggleFullscreen();
|
||||
else if (!enabled && g_isFullscreen)
|
||||
ToggleFullscreen();
|
||||
if (!g_pSwapChain)
|
||||
return;
|
||||
|
||||
LONG styleBefore = GetWindowLong(g_hWnd, GWL_STYLE);
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
// Grow the window to cover the monitor first. This fires WM_SIZE which
|
||||
// runs ResizeD3D and recreates the backbuffer at monitor-native size.
|
||||
// Otherwise a small windowed backbuffer would enter exclusive fullscreen
|
||||
// at that smaller size and DXGI would scale it to fill the monitor,
|
||||
// producing a filtered / washed-out look.
|
||||
HMONITOR hMon = MonitorFromWindow(g_hWnd, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFO mi = {};
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (GetMonitorInfo(hMon, &mi))
|
||||
{
|
||||
int monW = mi.rcMonitor.right - mi.rcMonitor.left;
|
||||
int monH = mi.rcMonitor.bottom - mi.rcMonitor.top;
|
||||
SetWindowLong(g_hWnd, GWL_STYLE, (styleBefore & ~WS_OVERLAPPEDWINDOW) | WS_VISIBLE);
|
||||
SetWindowPos(g_hWnd, HWND_TOP,
|
||||
mi.rcMonitor.left, mi.rcMonitor.top, monW, monH,
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
|
||||
// ResizeTarget pins the display mode to the backbuffer size with
|
||||
// no scaling. Microsoft's pattern is ResizeTarget then
|
||||
// SetFullscreenState then ResizeTarget again (see below).
|
||||
DXGI_MODE_DESC targetMode = {};
|
||||
targetMode.Width = monW;
|
||||
targetMode.Height = monH;
|
||||
targetMode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
targetMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
||||
targetMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||
g_pSwapChain->ResizeTarget(&targetMode);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr = g_pSwapChain->SetFullscreenState(enabled ? TRUE : FALSE, nullptr);
|
||||
if (FAILED(hr))
|
||||
return;
|
||||
|
||||
g_bDxgiExclusiveFullscreen = enabled;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
// Explicitly declare sRGB. Default for R8G8B8A8_UNORM but some drivers
|
||||
// behave differently if the color space is never set.
|
||||
IDXGISwapChain3* pSwapChain3 = nullptr;
|
||||
if (SUCCEEDED(g_pSwapChain->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&pSwapChain3)) && pSwapChain3)
|
||||
{
|
||||
UINT colorSpaceSupport = 0;
|
||||
pSwapChain3->CheckColorSpaceSupport(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, &colorSpaceSupport);
|
||||
if (colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)
|
||||
pSwapChain3->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
|
||||
pSwapChain3->Release();
|
||||
}
|
||||
|
||||
// Second ResizeTarget per Microsoft's recommendation to make the mode stick.
|
||||
HMONITOR hMon2 = MonitorFromWindow(g_hWnd, MONITOR_DEFAULTTOPRIMARY);
|
||||
MONITORINFO mi2 = {};
|
||||
mi2.cbSize = sizeof(mi2);
|
||||
if (GetMonitorInfo(hMon2, &mi2))
|
||||
{
|
||||
DXGI_MODE_DESC targetMode2 = {};
|
||||
targetMode2.Width = mi2.rcMonitor.right - mi2.rcMonitor.left;
|
||||
targetMode2.Height = mi2.rcMonitor.bottom - mi2.rcMonitor.top;
|
||||
targetMode2.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
targetMode2.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
||||
targetMode2.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||
g_pSwapChain->ResizeTarget(&targetMode2);
|
||||
}
|
||||
g_isFullscreen = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Force a real decorated windowed state on exit. DXGI would otherwise
|
||||
// restore whatever state the window had before SetFullscreenState,
|
||||
// which may still be borderless.
|
||||
SetWindowLong(g_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
|
||||
const int w = 1280, h = 720;
|
||||
const int sw = GetSystemMetrics(SM_CXSCREEN);
|
||||
const int sh = GetSystemMetrics(SM_CYSCREEN);
|
||||
SetWindowPos(g_hWnd, HWND_TOP, (sw - w) / 2, (sh - h) / 2, w, h,
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
g_isFullscreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
|
@ -1610,10 +1665,13 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Restore fullscreen state from previous session
|
||||
if (LoadFullscreenOption() && !g_isFullscreen || launchOptions.fullscreen)
|
||||
// Restore fullscreen state from previous session. Route through the
|
||||
// deferred exclusive fullscreen path so the main loop applies it on the
|
||||
// first tick (safer than transitioning during init).
|
||||
if ((LoadFullscreenOption() && !g_isFullscreen) || launchOptions.fullscreen)
|
||||
{
|
||||
ToggleFullscreen();
|
||||
g_bPendingExclusiveFullscreen = true;
|
||||
g_bPendingExclusiveFullscreenValue = true;
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
|
@ -1722,7 +1780,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() &&
|
||||
|
|
@ -1904,13 +1969,13 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
|
||||
RenderManager.Set_matrixDirty();
|
||||
#endif
|
||||
// Present the frame.
|
||||
// RenderManager.Present() hardcodes SyncInterval=1 internally.
|
||||
// When VSync is off, bypass it and call the swap chain directly.
|
||||
if (!g_bVSync && g_bTearingSupported && g_pSwapChain)
|
||||
// Present the frame. RenderManager.Present() hardcodes SyncInterval=1,
|
||||
// so when VSync is off we bypass it for uncapped frames. In DXGI
|
||||
// exclusive fullscreen this produces real tearing via direct scanout.
|
||||
if (!g_bVSync && g_pSwapChain)
|
||||
{
|
||||
HRESULT hrPresent = g_pSwapChain->Present(0, DXGI_PRESENT_ALLOW_TEARING);
|
||||
// If tearing Present fails (e.g. during fullscreen transition),
|
||||
HRESULT hrPresent = g_pSwapChain->Present(0, 0);
|
||||
// If the direct Present fails (e.g. during fullscreen transition),
|
||||
// fall back to the library's VSync'd Present for this frame.
|
||||
if (FAILED(hrPresent))
|
||||
RenderManager.Present();
|
||||
|
|
@ -2008,11 +2073,11 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|||
}
|
||||
#endif
|
||||
|
||||
// toggle fullscreen
|
||||
// toggle fullscreen (DXGI exclusive via ApplyExclusiveFullscreen)
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_FULLSCREEN))
|
||||
{
|
||||
ToggleFullscreen();
|
||||
app.SetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_ExclusiveFullscreen, g_isFullscreen ? 1 : 0);
|
||||
ApplyExclusiveFullscreen(!g_bDxgiExclusiveFullscreen);
|
||||
app.SetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_ExclusiveFullscreen, g_bDxgiExclusiveFullscreen ? 1 : 0);
|
||||
}
|
||||
|
||||
// Apply deferred exclusive fullscreen toggle
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,12 +1,5 @@
|
|||
set(BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Windows64/")
|
||||
|
||||
set(_MINECRAFT_CLIENT_WINDOWS_COMMON_RES_AUDIO
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Common/res/audio/minecraft.xsb"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Common/res/audio/resident.xwb"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Common/res/audio/streamed.xwb"
|
||||
)
|
||||
source_group("Common/res/audio" FILES ${_MINECRAFT_CLIENT_WINDOWS_COMMON_RES_AUDIO})
|
||||
|
||||
set(_MINECRAFT_CLIENT_WINDOWS_COMMON_AUDIO
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/Common/Audio/SoundEngine.cpp"
|
||||
)
|
||||
|
|
@ -479,7 +472,6 @@ set(_MINECRAFT_CLIENT_WINDOWS_NET_MINECRAFT_STATS
|
|||
source_group("net/minecraft/stats" FILES ${_MINECRAFT_CLIENT_WINDOWS_NET_MINECRAFT_STATS})
|
||||
|
||||
set(MINECRAFT_CLIENT_WINDOWS
|
||||
${_MINECRAFT_CLIENT_WINDOWS_COMMON_RES_AUDIO}
|
||||
${_MINECRAFT_CLIENT_WINDOWS_COMMON_AUDIO}
|
||||
${_MINECRAFT_CLIENT_WINDOWS_COMMON_NETWORK}
|
||||
${_MINECRAFT_CLIENT_WINDOWS_COMMON_UI}
|
||||
|
|
|
|||
|
|
@ -735,7 +735,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;
|
||||
|
|
@ -749,7 +749,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);
|
||||
|
|
@ -768,16 +768,18 @@ 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())
|
||||
|
|
|
|||
|
|
@ -515,6 +515,7 @@ set(_MINECRAFT_SERVER_COMMON_ROOT
|
|||
"${_MS_SRC}/../Minecraft.Client/iob_shim.asm"
|
||||
"${_MS_SRC}/../Minecraft.Client/stdafx.cpp"
|
||||
"${_MS_SRC}/../Minecraft.Client/stubs.cpp"
|
||||
"${_MS_SRC}/../Minecraft.World/Entity.cpp"
|
||||
"${_MS_SRC}/../Minecraft.World/AbstractContainerMenu.cpp"
|
||||
"${_MS_SRC}/../Minecraft.World/CompoundContainer.h"
|
||||
"${_MS_SRC}/../Minecraft.World/ItemEntity.cpp"
|
||||
|
|
|
|||
|
|
@ -98,6 +98,7 @@ public:
|
|||
e_ChatCommandTeleportMe,
|
||||
e_ChatCommandTeleportToMe,
|
||||
|
||||
e_ChatActionBar,
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ DamageSource::DamageSource(ChatPacket::EChatPacketMessage msgId, ChatPacket::ECh
|
|||
_isProjectile = false;
|
||||
_isMagic = false;
|
||||
_isExplosion = false;
|
||||
_isCritical = false;
|
||||
|
||||
//this->msgId = msgId;
|
||||
m_msgId = msgId;
|
||||
|
|
@ -153,7 +154,15 @@ DamageSource *DamageSource::bypassInvul()
|
|||
_bypassInvul = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
bool DamageSource::isCritical()
|
||||
{
|
||||
return _isCritical;
|
||||
}
|
||||
DamageSource *DamageSource::setIsCritical()
|
||||
{
|
||||
_isCritical = true;
|
||||
return this;
|
||||
}
|
||||
DamageSource *DamageSource::setIsFire()
|
||||
{
|
||||
isFireSource = true;
|
||||
|
|
|
|||
|
|
@ -47,8 +47,11 @@ private:
|
|||
bool _scalesWithDifficulty;
|
||||
bool _isMagic;
|
||||
bool _isExplosion;
|
||||
bool _isCritical;
|
||||
|
||||
public:
|
||||
bool isCritical();
|
||||
DamageSource *setIsCritical();
|
||||
bool isProjectile();
|
||||
DamageSource *setProjectile();
|
||||
bool isExplosion();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ class EntityEvent
|
|||
public:
|
||||
static const BYTE JUMP = 1;
|
||||
static const BYTE HURT = 2;
|
||||
//New
|
||||
static const BYTE HURT_CRITICAL = 19;
|
||||
static const BYTE DEATH_CRITICAL = 20;
|
||||
static const BYTE DEATH = 3;
|
||||
static const BYTE START_ATTACKING = 4;
|
||||
static const BYTE STOP_ATTACKING = 5;
|
||||
|
|
|
|||
|
|
@ -881,7 +881,12 @@ bool LivingEntity::hurt(DamageSource *source, float dmg)
|
|||
|
||||
if (sound)
|
||||
{
|
||||
level->broadcastEntityEvent(shared_from_this(), EntityEvent::HURT);
|
||||
if (source->isCritical()) {
|
||||
level->broadcastEntityEvent(shared_from_this(), EntityEvent::HURT_CRITICAL);
|
||||
}
|
||||
else {
|
||||
level->broadcastEntityEvent(shared_from_this(), EntityEvent::HURT);
|
||||
}
|
||||
if (source != DamageSource::drown) markHurt();
|
||||
if (sourceEntity != nullptr)
|
||||
{
|
||||
|
|
@ -904,12 +909,19 @@ bool LivingEntity::hurt(DamageSource *source, float dmg)
|
|||
MemSect(31);
|
||||
if (getHealth() <= 0)
|
||||
{
|
||||
if (sound) playSound(getDeathSound(), getSoundVolume(), getVoicePitch());
|
||||
if (sound) {
|
||||
//New: both death AND hurt sounds should play critical sound as well.
|
||||
if (source->isCritical()) playSound(getCriticalSound(), getSoundVolume(), getVoicePitch());
|
||||
playSound(getDeathSound(), getSoundVolume(), getVoicePitch());
|
||||
};
|
||||
die(source);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sound) playSound(getHurtSound(), getSoundVolume(), getVoicePitch());
|
||||
if (sound) {
|
||||
if (source->isCritical()) playSound(getCriticalSound(), getSoundVolume(), getVoicePitch());
|
||||
playSound(getHurtSound(), getSoundVolume(), getVoicePitch());
|
||||
}
|
||||
}
|
||||
MemSect(0);
|
||||
|
||||
|
|
@ -988,7 +1000,11 @@ void LivingEntity::die(DamageSource *source)
|
|||
}
|
||||
}
|
||||
|
||||
level->broadcastEntityEvent(shared_from_this(), EntityEvent::DEATH);
|
||||
if (source->isCritical()) {
|
||||
level->broadcastEntityEvent(shared_from_this(), EntityEvent::DEATH_CRITICAL);
|
||||
} else {
|
||||
level->broadcastEntityEvent(shared_from_this(), EntityEvent::DEATH);
|
||||
}
|
||||
}
|
||||
|
||||
void LivingEntity::dropEquipment(bool byPlayer, int playerBonusLevel)
|
||||
|
|
@ -1021,7 +1037,10 @@ int LivingEntity::getHurtSound()
|
|||
{
|
||||
return eSoundType_DAMAGE_HURT;
|
||||
}
|
||||
|
||||
int LivingEntity::getCriticalSound()
|
||||
{
|
||||
return eSoundType_DAMAGE_CRITICAL;
|
||||
}
|
||||
int LivingEntity::getDeathSound()
|
||||
{
|
||||
return eSoundType_DAMAGE_HURT;
|
||||
|
|
@ -1265,7 +1284,8 @@ void LivingEntity::swing()
|
|||
|
||||
void LivingEntity::handleEntityEvent(byte id)
|
||||
{
|
||||
if (id == EntityEvent::HURT)
|
||||
//These gotta be in parentheses
|
||||
if ((id == EntityEvent::HURT) || (id == EntityEvent::HURT_CRITICAL))
|
||||
{
|
||||
walkAnimSpeed = 1.5f;
|
||||
|
||||
|
|
@ -1275,19 +1295,30 @@ void LivingEntity::handleEntityEvent(byte id)
|
|||
|
||||
MemSect(31);
|
||||
// 4J-PB -added because villagers have no sounds
|
||||
int iHurtSound=getHurtSound();
|
||||
int iHurtSound = getHurtSound();
|
||||
int iCritSound = getCriticalSound();
|
||||
if(iHurtSound!=-1)
|
||||
{
|
||||
playSound(iHurtSound, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f);
|
||||
}
|
||||
if(iCritSound!=-1 && (id == EntityEvent::HURT_CRITICAL))
|
||||
{
|
||||
playSound(iCritSound, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f);
|
||||
}
|
||||
MemSect(0);
|
||||
hurt(DamageSource::genericSource, 0);
|
||||
}
|
||||
else if (id == EntityEvent::DEATH)
|
||||
else if ((id == EntityEvent::DEATH) || (id == EntityEvent::DEATH_CRITICAL))
|
||||
{
|
||||
MemSect(31);
|
||||
// 4J-PB -added because villagers have no sounds
|
||||
int iDeathSound=getDeathSound();
|
||||
int iCritSound = getCriticalSound();
|
||||
|
||||
if (iCritSound != -1 && (id == EntityEvent::DEATH_CRITICAL))
|
||||
{
|
||||
playSound(iCritSound, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f);
|
||||
}
|
||||
if(iDeathSound!=-1)
|
||||
{
|
||||
playSound(iDeathSound, getSoundVolume(), (random->nextFloat() - random->nextFloat()) * 0.2f + 1.0f);
|
||||
|
|
|
|||
|
|
@ -190,6 +190,7 @@ public:
|
|||
virtual void knockback(shared_ptr<Entity> source, float dmg, double xd, double zd);
|
||||
|
||||
protected:
|
||||
virtual int getCriticalSound();
|
||||
virtual int getHurtSound();
|
||||
virtual int getDeathSound();
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -1635,6 +1635,10 @@ void Player::attack(shared_ptr<Entity> entity)
|
|||
}
|
||||
|
||||
DamageSource *damageSource = DamageSource::playerAttack(dynamic_pointer_cast<Player>(shared_from_this()));
|
||||
|
||||
if (bCrit) {
|
||||
damageSource->setIsCritical();
|
||||
}
|
||||
bool wasHurt = entity->hurt(damageSource, dmg);
|
||||
delete damageSource;
|
||||
if (wasHurt)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ class SharedConstants
|
|||
static wstring readAcceptableChars();
|
||||
|
||||
public:
|
||||
static const int maxChatLength = 100;
|
||||
static const int maxChatLength = 255;
|
||||
static const int maxVisibleLength = 100; //to be changed
|
||||
static wstring acceptableLetters;
|
||||
|
||||
static const int ILLEGAL_FILE_CHARACTERS_LENGTH = 15;
|
||||
|
|
|
|||
|
|
@ -493,6 +493,10 @@ void Socket::SocketOutputStreamNetwork::writeWithFlags(byteArray b, unsigned int
|
|||
}
|
||||
else
|
||||
{
|
||||
// Don't write on a closing socket: an orphan whose smallId has been
|
||||
// recycled would otherwise leak a packet onto the new client.
|
||||
if( m_socket->isClosing() ) return;
|
||||
|
||||
XRNM_SEND_BUFFER buffer;
|
||||
buffer.pbyData = &b[offset];
|
||||
buffer.dwDataSize = length;
|
||||
|
|
|
|||
|
|
@ -260,6 +260,8 @@ enum eSOUND_TYPE
|
|||
eSoundType_ITEM_ARMOR_equipGeneric5,
|
||||
eSoundType_ITEM_ARMOR_equipGeneric6,
|
||||
|
||||
eSoundType_DAMAGE_CRITICAL,
|
||||
|
||||
eSoundType_MAX
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ $ErrorActionPreference = "Stop"
|
|||
|
||||
# --- Configuration ---
|
||||
$RepoOwner = "itsRevela"
|
||||
$RepoName = "MinecraftConsoles"
|
||||
$RepoName = "LCE-Revelations"
|
||||
$ReleaseTag = "Nightly"
|
||||
$ReleaseDir = Join-Path $PSScriptRoot "build\Minecraft.Client\Release"
|
||||
$ZipName = "LCREWindows64.zip"
|
||||
|
|
|
|||
|
|
@ -7,16 +7,19 @@ function(setup_asset_folder_copy TARGET_NAME ASSET_FOLDER_PAIRS)
|
|||
"*.xml" "*.lang"
|
||||
"*.bat" "*.cmd"
|
||||
"*.msscmp" "*.binka" # Old audio formats
|
||||
#"*.swf" # These are built into the .arc
|
||||
"*.swf"
|
||||
"*.resx" #"*.loc"
|
||||
"*.wav" # Unsupported audio format
|
||||
"*.xui"
|
||||
"*.xui" "*.xgs"
|
||||
"*.xwb" "*.xsb"
|
||||
"*.xap" "*.xzp"
|
||||
)
|
||||
|
||||
# Global folder exclusions applied to every folder copy
|
||||
# set(ASSET_EXCLUDE_FOLDERS
|
||||
# "Graphics"
|
||||
# )
|
||||
set(ASSET_EXCLUDE_FOLDERS
|
||||
#"Graphics"
|
||||
"Gamerules"
|
||||
)
|
||||
|
||||
# Exclude platform-specific media folders
|
||||
set(PLATFORM_MEDIA_FOLDERS
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
services:
|
||||
lce-revelations-dedicated-server:
|
||||
image: ghcr.io/lce-hub/lce-revelations-dedicated-server:nightly
|
||||
image: ghcr.io/itsrevela/lce-revelations-dedicated-server:nightly
|
||||
container_name: lce-revelations-dedicated-server
|
||||
restart: unless-stopped
|
||||
tty: true
|
||||
|
|
|
|||
|
|
@ -1,180 +0,0 @@
|
|||
# FourKit Port Reconnaissance
|
||||
|
||||
Phase 1 deliverable for porting the FourKit plugin system into LCE-Revelations. This document is the source of truth for what needs to change, where, and how risky each change is. Phases 2-3 of the port consume this document directly.
|
||||
|
||||
## Source repos referenced
|
||||
|
||||
| Role | Path |
|
||||
|---|---|
|
||||
| Vanilla baseline | `C:\Users\revela\Documents\Minecraft\itsRevela` |
|
||||
| Donor (has FourKit) | `C:\Users\revela\Documents\Minecraft\FourKit\MinecraftConsoles` |
|
||||
| Target (this repo) | `C:\Users\revela\Documents\Minecraft\LCE-Hub\LCE-Revelations` |
|
||||
|
||||
Vanilla and donor were forked from upstream at similar points; the donor adds FourKit on top. The target is a more recent independent fork that has its own divergence (Security subsystem, OpManager, revoke-token command, additional ServerProperties fields).
|
||||
|
||||
## Executive summary
|
||||
|
||||
- **27 files** in the donor are FourKit-bearing across `Minecraft.Server/`, `Minecraft.World/`, and `Minecraft.Client/`. Of those, **23 are clean patches** (target identical to vanilla in those files), and **only 4 require manual merge work** (all in `Minecraft.Server/`).
|
||||
- **7 pure-add native files** drop in unmodified.
|
||||
- **1 entire managed project** (`Minecraft.Server.FourKit/`) drops in unmodified.
|
||||
- **No blockers identified.** Every Fire* hook site exists in target at vanilla content; the conflicts are concentrated in build files and a small set of `Minecraft.Server/` source files where target diverged.
|
||||
- **Native callback ABI is intact.** Spot-checks of player/world/inventory subsystem APIs that FourKitNatives.cpp depends on all match between donor and target.
|
||||
|
||||
## A. File diff matrix
|
||||
|
||||
### A.1 Pure adds (drop in verbatim)
|
||||
|
||||
| File | Notes |
|
||||
|---|---|
|
||||
| `Minecraft.Server/FourKitBridge.cpp` | Event firing + callback registry |
|
||||
| `Minecraft.Server/FourKitBridge.h` | Public Fire* and Handle* surface |
|
||||
| `Minecraft.Server/FourKitNatives.cpp` | C# → C++ callback implementations (~80 functions) |
|
||||
| `Minecraft.Server/FourKitNatives.h` | Native function declarations |
|
||||
| `Minecraft.Server/FourKitRuntime.cpp` | hostfxr load + .NET 10 bootstrap |
|
||||
| `Minecraft.Server/FourKitRuntime.h` | Runtime init API |
|
||||
| `Minecraft.Server/FourKitMappers.cpp` | Type/enum mapping helpers |
|
||||
| `Minecraft.Server.FourKit/` (entire project) | Managed plugin host, Bukkit-style API, ~54 events |
|
||||
|
||||
### A.2 Modified files in `Minecraft.Server/` (the merge work)
|
||||
|
||||
| File | Donor delta | Target diverges from vanilla? | Merge class |
|
||||
|---|---|---|---|
|
||||
| `CMakeLists.txt` | +24 lines (FourKit dep + post-build copy) | No | CLEAN_PATCH |
|
||||
| `cmake/sources/Common.cmake` | +7 FourKit sources, donor also strips OpManager/Security (donor lacks those) | No | **SELECTIVE_MERGE**: add donor's FourKit sources only; preserve target's OpManager/Security entries |
|
||||
| `Windows64/ServerMain.cpp` | FourKit init/shutdown + 1 inline FireWorldSave | No | CLEAN_PATCH |
|
||||
| `Console/ServerCliEngine.cpp` | HandleConsoleCommand hook + GetPluginCommandHelp integration | No | CLEAN_PATCH |
|
||||
| `Console/commands/help/CliCommandHelp.cpp` | Plugin command help integration | Unknown: check before merge | LIKELY_CLEAN |
|
||||
| `Console/commands/whitelist/CliCommandWhitelist.cpp` | Unknown delta | Unknown | LIKELY_CLEAN |
|
||||
| `Access/Access.cpp` | Donor delta unrelated to FourKit hooks per grep | No | CLEAN_PATCH (verify) |
|
||||
| `Access/Access.h` | Same | No | CLEAN_PATCH (verify) |
|
||||
| `ServerLogManager.cpp` | Logger plumbing for FourKit log routing | No | CLEAN_PATCH |
|
||||
| `ServerLogManager.h` | Same | No | CLEAN_PATCH |
|
||||
| `ServerLogger.cpp` | Same | No | CLEAN_PATCH |
|
||||
| `ServerProperties.cpp` | Donor REMOVES fields target relies on | **Yes** | **CONFLICT: KEEP TARGET** |
|
||||
| `ServerProperties.h` | Same | **Yes** | **CONFLICT: KEEP TARGET** |
|
||||
|
||||
### A.3 Modified files in `Minecraft.World/` and `Minecraft.Client/`
|
||||
|
||||
The donor changed 53 files in `Minecraft.World/` and 95 files in `Minecraft.Client/` overall, but most of those are upstream churn unrelated to FourKit. The FourKit-specific subset is identified by `grep "FourKit"` and yields **23 files**, all of which are identical between vanilla and target: i.e., every single one is CLEAN_PATCH.
|
||||
|
||||
#### `Minecraft.World/` FourKit hook files (17, all CLEAN_PATCH)
|
||||
|
||||
`AbstractContainerMenu.cpp`, `CactusTile.cpp`, `CocoaTile.cpp`, `CropTile.cpp`, `EggTile.cpp`, `FireTile.cpp`, `GrassTile.cpp`, `ItemEntity.cpp`, `LiquidTileDynamic.cpp`, `LivingEntity.cpp`, `Mushroom.cpp`, `NetherWartTile.cpp`, `PistonBaseTile.cpp`, `ReedTile.cpp`, `Sapling.cpp`, `StemTile.cpp`, `ThrownEnderpearl.cpp`
|
||||
|
||||
#### `Minecraft.Client/` FourKit hook files (6, all CLEAN_PATCH)
|
||||
|
||||
`PendingConnection.cpp`, `PlayerConnection.cpp`, `ServerLevel.cpp`, `ServerPlayer.cpp`, `ServerPlayerGameMode.cpp`, `TeleportCommand.cpp`
|
||||
|
||||
> **Note on naming:** Despite the `Minecraft.Client/` folder name, several of these files (`PlayerConnection`, `ServerPlayer`, `ServerLevel`, etc.) are shared engine code that the dedicated server also compiles. They are valid hook sites for a server-side plugin system.
|
||||
|
||||
#### Build files in `Minecraft.World/` and `Minecraft.Client/`
|
||||
|
||||
The donor also modifies `Minecraft.World/cmake/sources/Common.cmake`, `Minecraft.Client/cmake/sources/Common.cmake`, `Minecraft.Client/cmake/sources/Windows.cmake`, and `Minecraft.Client/CMakeLists.txt`, but none of these contain FourKit references: they are upstream churn and should NOT be touched as part of the FourKit port.
|
||||
|
||||
## B. Fire* hook site inventory
|
||||
|
||||
Donor exposes Fire*/Handle* via `FourKitBridge::` (see `Minecraft.Server/FourKitBridge.h`). Hook calls appear in 26 source files across the three subprojects.
|
||||
|
||||
### B.1 Hook sites by subsystem
|
||||
|
||||
| Subsystem | Files (in donor) |
|
||||
|---|---|
|
||||
| Server lifecycle | `Minecraft.Server/Windows64/ServerMain.cpp` (init, shutdown, FireWorldSave) |
|
||||
| Console / commands | `Minecraft.Server/Console/ServerCliEngine.cpp` (HandleConsoleCommand, GetPluginCommandHelp), `Minecraft.Server/Console/commands/help/CliCommandHelp.cpp` |
|
||||
| Player connection / login | `Minecraft.Client/PlayerConnection.cpp`, `Minecraft.Client/PendingConnection.cpp` |
|
||||
| Player gameplay | `Minecraft.Client/ServerPlayer.cpp`, `Minecraft.Client/ServerPlayerGameMode.cpp`, `Minecraft.Client/TeleportCommand.cpp` |
|
||||
| World / level | `Minecraft.Client/ServerLevel.cpp` |
|
||||
| Living entities & damage | `Minecraft.World/LivingEntity.cpp`, `Minecraft.World/ItemEntity.cpp`, `Minecraft.World/ThrownEnderpearl.cpp` |
|
||||
| Block / tile (growth, burn, spread, ignite, piston) | `Minecraft.World/CactusTile.cpp`, `CocoaTile.cpp`, `CropTile.cpp`, `EggTile.cpp`, `FireTile.cpp`, `GrassTile.cpp`, `LiquidTileDynamic.cpp`, `Mushroom.cpp`, `NetherWartTile.cpp`, `PistonBaseTile.cpp`, `ReedTile.cpp`, `Sapling.cpp`, `StemTile.cpp` |
|
||||
| Inventory / containers | `Minecraft.World/AbstractContainerMenu.cpp` |
|
||||
|
||||
### B.2 Hook insertion-site safety
|
||||
|
||||
Per A.3, **every file in B.1 outside of `Minecraft.Server/` is byte-identical between vanilla and target**. That means donor's hook insertions can be applied as a straight patch without adapting around target-side refactors.
|
||||
|
||||
In `Minecraft.Server/`, the hook-bearing files (`ServerMain.cpp`, `ServerCliEngine.cpp`, `CliCommandHelp.cpp`) are also identical or near-identical to vanilla per A.2. Net result: **the locked Phase 3 hook adaptation policy ("adapt to LCE-Revelations refactors") will not need to fire** for any hook site in the current state of the target. If the user pulls upstream changes between now and Phase 3, this assumption must be re-validated.
|
||||
|
||||
### B.3 Three concrete hook sites verified end-to-end (others follow same pattern)
|
||||
|
||||
1. **`Minecraft.Server/Windows64/ServerMain.cpp:681`**: `FourKitBridge::FireWorldSave()` inside the autosave trigger block. Target file is byte-identical to vanilla → clean insertion.
|
||||
2. **`Minecraft.Server/Console/ServerCliEngine.cpp:165`**: `if (FourKitBridge::HandleConsoleCommand(normalizedLine)) return true;` early return for plugin command preprocessing. Target file byte-identical → clean insertion.
|
||||
3. **`Minecraft.Server/Console/ServerCliEngine.cpp:215-246`**: `FourKitBridge::GetPluginCommandHelp(...)` integration into the help printer. Same file, clean insertion.
|
||||
|
||||
## C. Native callback surface (FourKitNatives.cpp ↔ engine APIs)
|
||||
|
||||
`FourKitNatives.cpp` implements ~80 functions that wrap engine APIs and expose them to managed code. Spot-check of the highest-risk subsystems:
|
||||
|
||||
| Native function | Engine API called | Target has it? | Signature drift? |
|
||||
|---|---|---|---|
|
||||
| `NativeSetPlayerHealth(int, float)` | `ServerPlayer::setHealth(float)` | Yes | None |
|
||||
| `NativeTeleportPlayer(int, double, double, double)` | `PlayerConnection::teleport(...)` | Yes | None |
|
||||
| `NativeSetTile(int, int, int, int, int, int)` | `ServerLevel::setBlock(...)` | Yes | None |
|
||||
| `NativeGetPlayerAddress(int, char*, int, int*)` | `PlayerConnection` accessors | Yes | None |
|
||||
| `NativeGetPlayerLatency(int)` | `PlayerConnection::latency` | Yes (field) | None |
|
||||
| `NativeBanPlayer(int, char*, int)` | `Access::AddPlayerBan(...)` | Yes | None |
|
||||
| `NativeSetItemMeta(int, int, char*, int)` | `ItemInstance` serialization | Yes | None |
|
||||
| `NativeGetContainerContents(int, int*, int)` | `AbstractContainerMenu` traversal | Yes | None |
|
||||
|
||||
**Verdict:** No drift detected in critical subsystems. Phase 2's native bridge build is expected to compile against target's headers without shimming. Any drift discovered at compile time will be a Phase 2.3 finding, not a known risk.
|
||||
|
||||
## D. Critical hot files
|
||||
|
||||
| File | Vanilla LOC | Donor LOC | Target LOC | Status |
|
||||
|---|---|---|---|---|
|
||||
| `Minecraft.Server/Windows64/ServerMain.cpp` | 1,257 | 1,257 | 1,257 | Identical across all three. Donor's FourKit additions sit on the vanilla baseline; target has not touched it. |
|
||||
| `Minecraft.Server/CMakeLists.txt` | 86 | 110 (+24) | 86 | Target is vanilla. Donor adds FourKit deps and a post-build copy step. Clean apply. |
|
||||
| `Minecraft.Server/cmake/sources/Common.cmake` | 628 | 640 (+12 net; donor also strips ~16 lines of OpManager/Security) | 628 | Target is vanilla. **Selective merge:** apply donor's `FourKit*.cpp` additions, do NOT apply donor's removals. |
|
||||
| `Minecraft.Server/ServerProperties.cpp` | 965 | 930 (-35) | 965 | Donor is older / leaner; target carries hardcore + security fields donor never had. **Keep target version unchanged**, do not merge donor's deletions. |
|
||||
| `Minecraft.Server/ServerProperties.h` | n/a | n/a | n/a | Same logic: keep target. |
|
||||
| `Minecraft.Server/Console/commands/` | 20 subdirs | 18 subdirs (no `revoketoken`) | 20 subdirs (has `revoketoken`) | Donor predates `revoketoken`; target has it. Keep target's command set. |
|
||||
|
||||
## E. Top-level structure of the target
|
||||
|
||||
| Item | Status |
|
||||
|---|---|
|
||||
| `samples/` at repo root | NOT FOUND: Phase 7 will create it |
|
||||
| `docs/` at repo root | NOT FOUND: created by this document |
|
||||
| `docker/` | EXISTS: contains `dedicated-server/{Dockerfile,entrypoint.sh}`. Phase 5 must inspect to decide whether the image builds the server from source or consumes the release zip |
|
||||
| `Minecraft.Server.FourKit/` | NOT FOUND (as expected) |
|
||||
|
||||
## Merge strategy summary (input to Phase 2 and Phase 3)
|
||||
|
||||
1. **Phase 2 source drop:** Copy the 7 PURE_ADD files into `Minecraft.Server/` verbatim. Copy the entire `Minecraft.Server.FourKit/` project to repo root verbatim.
|
||||
2. **Phase 2 build files:**
|
||||
- `Minecraft.Server/CMakeLists.txt`: apply donor's diff verbatim (target is vanilla).
|
||||
- `Minecraft.Server/cmake/sources/Common.cmake`: apply ONLY the donor's additions of `FourKit*.cpp`. Do not delete OpManager or Security entries.
|
||||
3. **Phase 3 hooks (the entire surface, all CLEAN_PATCH):**
|
||||
- 3 sites in `Minecraft.Server/` (`ServerMain.cpp`, `ServerCliEngine.cpp`, `CliCommandHelp.cpp`)
|
||||
- 17 sites in `Minecraft.World/` (block/entity/container)
|
||||
- 6 sites in `Minecraft.Client/` (player/level/connection)
|
||||
- 1 lifecycle hook pair in `ServerMain.cpp` for `FourKitRuntime::Initialize` / shutdown
|
||||
- Logger plumbing in `ServerLogManager.{cpp,h}` and `ServerLogger.cpp`
|
||||
4. **Phase 3 conflicts to leave alone:**
|
||||
- `ServerProperties.{cpp,h}`: keep target version, do not merge donor.
|
||||
- `Console/commands/revoketoken/`: keep target version, donor lacks it.
|
||||
- `Access/OpManager.{cpp,h}`: keep target version, donor lacks it.
|
||||
- `Security/`: keep target version, donor lacks it.
|
||||
5. **Spot-checks needed before merge:**
|
||||
- `Console/commands/help/CliCommandHelp.cpp`: verify donor's delta is purely the plugin help integration and not entangled with anything target changed.
|
||||
- `Console/commands/whitelist/CliCommandWhitelist.cpp`: confirm scope of donor's edit.
|
||||
- `Access/Access.{cpp,h}`: confirm donor's delta is not security-related.
|
||||
|
||||
## Risks updated post-recon
|
||||
|
||||
| Risk | Original severity | Post-recon severity | Reason |
|
||||
|---|---|---|---|
|
||||
| LCE-Revelations divergence at hook sites | HIGH | **LOW** | All 26 hook-bearing source files are byte-identical between vanilla and target. |
|
||||
| CMake structural divergence | HIGH | **LOW** | Target's `CMakeLists.txt` and `Common.cmake` are byte-identical to vanilla. |
|
||||
| ServerMain.cpp init-order conflicts | MEDIUM | **LOW** | File is identical to vanilla. |
|
||||
| ServerProperties conflict | NEW | **MEDIUM** | Donor strips fields target relies on. Mitigation: do not merge donor's version. |
|
||||
| Native ABI drift in subsystem APIs | MEDIUM | **LOW** | Spot-checks all clean. Compile-time will catch any miss. |
|
||||
| Donor predates target features (revoketoken, OpManager, Security) | NEW | **LOW** | Easy to preserve target's additions; donor doesn't depend on their absence. |
|
||||
| Self-contained .NET 10 publish size | MEDIUM | **MEDIUM** | Unchanged. ~70-100 MB release zip growth. |
|
||||
| Hot-reload absent | LOW | **LOW** | Inherited limitation, documented. |
|
||||
|
||||
## Open follow-ups for Phase 2
|
||||
|
||||
1. Confirm `Console/commands/help/CliCommandHelp.cpp` and `Console/commands/whitelist/CliCommandWhitelist.cpp` deltas are FourKit-related (currently marked LIKELY_CLEAN, not verified).
|
||||
2. Confirm `Access/Access.{cpp,h}` delta scope.
|
||||
3. Decide whether the donor's changes to `ServerLogManager` and `ServerLogger` are strictly additive (capture for FourKit log routing) or entangled with other refactoring.
|
||||
4. Confirm during Phase 2.3 that `FourKitRuntime.cpp`'s hostfxr loader handles the case where `hostfxr.dll` is absent gracefully (server should warn and continue, not crash): this matters because the self-contained publish puts hostfxr next to the server exe, so the failure mode only fires if a user deletes it.
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
description = "MinecraftConsoles - Minecraft Legacy Console Edition recreation";
|
||||
description = "LCE-Revelations - Minecraft Legacy Console Edition recreation";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||
|
|
@ -503,7 +503,7 @@
|
|||
XWIN_CACHE = "$HOME/.cache/xwin";
|
||||
|
||||
shellHook = ''
|
||||
echo "MinecraftConsoles development shell"
|
||||
echo "LCE-Revelations development shell"
|
||||
echo ""
|
||||
echo "Quick build (uses cached SDK):"
|
||||
echo " nix build .#client # Build client package"
|
||||
|
|
|
|||
Loading…
Reference in a new issue