mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-03-26 23:02:00 +02:00
Compare commits
21 Commits
ecb3f00bd6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f370c45e3 | ||
|
|
c96a8ee524 | ||
|
|
1a50770647 | ||
|
|
dee559bd16 | ||
|
|
a24318eedc | ||
|
|
993052409a | ||
|
|
ed9cbae3f7 | ||
|
|
daed75b8a1 | ||
|
|
9e715cb3bc | ||
|
|
127465b0eb | ||
|
|
77433dbd86 | ||
|
|
9a6d126ae1 | ||
|
|
39e46751bf | ||
|
|
ebab3ec40f | ||
|
|
c1ce97f7be | ||
|
|
603c6ba7cb | ||
|
|
b6e25415ca | ||
|
|
dac073605f | ||
|
|
be7e2ca91d | ||
|
|
250accd40b | ||
|
|
33b008c96a |
@@ -4036,6 +4036,8 @@ void ClientConnection::handleSetPlayerTeamPacket(shared_ptr<SetPlayerTeamPacket>
|
||||
|
||||
void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> packet)
|
||||
{
|
||||
ePARTICLE_TYPE particleId = (ePARTICLE_TYPE)Integer::parseInt(packet->getName());
|
||||
|
||||
for (int i = 0; i < packet->getCount(); i++)
|
||||
{
|
||||
double xVarience = random->nextGaussian() * packet->getXDist();
|
||||
@@ -4045,10 +4047,6 @@ void ClientConnection::handleParticleEvent(shared_ptr<LevelParticlesPacket> pack
|
||||
double ya = random->nextGaussian() * packet->getMaxSpeed();
|
||||
double za = random->nextGaussian() * packet->getMaxSpeed();
|
||||
|
||||
// TODO: determine particle ID from name
|
||||
assert(0);
|
||||
ePARTICLE_TYPE particleId = eParticleType_heart;
|
||||
|
||||
level->addParticle(particleId, packet->getX() + xVarience, packet->getY() + yVarience, packet->getZ() + zVarience, xa, ya, za);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -47,7 +47,8 @@ public:
|
||||
{
|
||||
JOINGAME_SUCCESS,
|
||||
JOINGAME_FAIL_GENERAL,
|
||||
JOINGAME_FAIL_SERVER_FULL
|
||||
JOINGAME_FAIL_SERVER_FULL,
|
||||
JOINGAME_PENDING
|
||||
} eJoinGameResult;
|
||||
|
||||
void Initialise();
|
||||
|
||||
@@ -173,6 +173,11 @@ bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkMa
|
||||
m_bSearchPending = false;
|
||||
|
||||
m_bIsOfflineGame = false;
|
||||
#ifdef _WINDOWS64
|
||||
m_bJoinPending = false;
|
||||
m_joinLocalUsersMask = 0;
|
||||
m_joinHostName[0] = 0;
|
||||
#endif
|
||||
m_pSearchParam = nullptr;
|
||||
m_SessionsUpdatedCallback = nullptr;
|
||||
|
||||
@@ -282,6 +287,38 @@ void CPlatformNetworkManagerStub::DoWork()
|
||||
m_bLeaveGameOnTick = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bJoinPending)
|
||||
{
|
||||
WinsockNetLayer::eJoinState state = WinsockNetLayer::GetJoinState();
|
||||
if (state == WinsockNetLayer::eJoinState_Success)
|
||||
{
|
||||
WinsockNetLayer::FinalizeJoin();
|
||||
|
||||
BYTE localSmallId = WinsockNetLayer::GetLocalSmallId();
|
||||
|
||||
IQNet::m_player[localSmallId].m_smallId = localSmallId;
|
||||
IQNet::m_player[localSmallId].m_isRemote = false;
|
||||
IQNet::m_player[localSmallId].m_isHostPlayer = false;
|
||||
IQNet::m_player[localSmallId].m_resolvedXuid = Win64Xuid::ResolvePersistentXuid();
|
||||
|
||||
Minecraft* pMinecraft = Minecraft::GetInstance();
|
||||
wcscpy_s(IQNet::m_player[localSmallId].m_gamertag, 32, pMinecraft->user->name.c_str());
|
||||
IQNet::s_playerCount = localSmallId + 1;
|
||||
|
||||
NotifyPlayerJoined(&IQNet::m_player[0]);
|
||||
NotifyPlayerJoined(&IQNet::m_player[localSmallId]);
|
||||
|
||||
m_pGameNetworkManager->StateChange_AnyToStarting();
|
||||
m_bJoinPending = false;
|
||||
}
|
||||
else if (state == WinsockNetLayer::eJoinState_Failed ||
|
||||
state == WinsockNetLayer::eJoinState_Rejected ||
|
||||
state == WinsockNetLayer::eJoinState_Cancelled)
|
||||
{
|
||||
m_bJoinPending = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -511,36 +548,22 @@ int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo* searchResult, int l
|
||||
IQNet::m_player[0].m_smallId = 0;
|
||||
IQNet::m_player[0].m_isRemote = true;
|
||||
IQNet::m_player[0].m_isHostPlayer = true;
|
||||
// Remote host still maps to legacy host XUID in mixed old/new sessions.
|
||||
IQNet::m_player[0].m_resolvedXuid = Win64Xuid::GetLegacyEmbeddedHostXuid();
|
||||
wcsncpy_s(IQNet::m_player[0].m_gamertag, 32, searchResult->data.hostName, _TRUNCATE);
|
||||
|
||||
WinsockNetLayer::StopDiscovery();
|
||||
|
||||
if (!WinsockNetLayer::JoinGame(hostIP, hostPort))
|
||||
wcsncpy_s(m_joinHostName, 32, searchResult->data.hostName, _TRUNCATE);
|
||||
m_joinLocalUsersMask = localUsersMask;
|
||||
|
||||
if (!WinsockNetLayer::BeginJoinGame(hostIP, hostPort))
|
||||
{
|
||||
app.DebugPrintf("Win64 LAN: Failed to connect to %s:%d\n", hostIP, hostPort);
|
||||
return CGameNetworkManager::JOINGAME_FAIL_GENERAL;
|
||||
}
|
||||
|
||||
BYTE localSmallId = WinsockNetLayer::GetLocalSmallId();
|
||||
|
||||
IQNet::m_player[localSmallId].m_smallId = localSmallId;
|
||||
IQNet::m_player[localSmallId].m_isRemote = false;
|
||||
IQNet::m_player[localSmallId].m_isHostPlayer = false;
|
||||
// Local non-host identity is the persistent uid.dat XUID.
|
||||
IQNet::m_player[localSmallId].m_resolvedXuid = Win64Xuid::ResolvePersistentXuid();
|
||||
|
||||
Minecraft* pMinecraft = Minecraft::GetInstance();
|
||||
wcscpy_s(IQNet::m_player[localSmallId].m_gamertag, 32, pMinecraft->user->name.c_str());
|
||||
IQNet::s_playerCount = localSmallId + 1;
|
||||
|
||||
NotifyPlayerJoined(&IQNet::m_player[0]);
|
||||
NotifyPlayerJoined(&IQNet::m_player[localSmallId]);
|
||||
|
||||
m_pGameNetworkManager->StateChange_AnyToStarting();
|
||||
|
||||
return CGameNetworkManager::JOINGAME_SUCCESS;
|
||||
m_bJoinPending = true;
|
||||
return CGameNetworkManager::JOINGAME_PENDING;
|
||||
#else
|
||||
return CGameNetworkManager::JOINGAME_SUCCESS;
|
||||
#endif
|
||||
|
||||
@@ -77,6 +77,12 @@ private:
|
||||
bool m_bIsPrivateGame;
|
||||
int m_flagIndexSize;
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
bool m_bJoinPending;
|
||||
int m_joinLocalUsersMask;
|
||||
wchar_t m_joinHostName[32];
|
||||
#endif
|
||||
|
||||
// This is only maintained by the host, and is not valid on client machines
|
||||
GameSessionData m_hostGameSessionData;
|
||||
CGameNetworkManager *m_pGameNetworkManager;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h"
|
||||
#include "..\..\MultiplayerLocalPlayer.h"
|
||||
#include "..\..\Minecraft.h"
|
||||
#include "..\..\Options.h"
|
||||
|
||||
#ifdef __ORBIS__
|
||||
#include <pad.h>
|
||||
@@ -16,8 +17,6 @@
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
#include "..\..\Windows64\KeyboardMouseInput.h"
|
||||
|
||||
SavedInventoryCursorPos g_savedInventoryCursorPos = { 0.0f, 0.0f, false };
|
||||
#endif
|
||||
|
||||
IUIScene_AbstractContainerMenu::IUIScene_AbstractContainerMenu()
|
||||
@@ -1677,7 +1676,13 @@ vector<HtmlString> *IUIScene_AbstractContainerMenu::GetItemDescription(Slot *slo
|
||||
{
|
||||
if(slot == nullptr) return nullptr;
|
||||
|
||||
vector<HtmlString> *lines = slot->getItem()->getHoverText(nullptr, false);
|
||||
bool advanced = false;
|
||||
if (const Minecraft* pMinecraft = Minecraft::GetInstance())
|
||||
{
|
||||
if (pMinecraft->options)
|
||||
advanced = pMinecraft->options->advancedTooltips;
|
||||
}
|
||||
vector<HtmlString> *lines = slot->getItem()->getHoverText(nullptr, advanced);
|
||||
|
||||
// Add rarity to first line
|
||||
if (lines->size() > 0)
|
||||
|
||||
@@ -1,15 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
struct SavedInventoryCursorPos
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
bool hasSavedPos;
|
||||
};
|
||||
extern SavedInventoryCursorPos g_savedInventoryCursorPos;
|
||||
#endif
|
||||
|
||||
// Uncomment to enable tap input detection to jump 1 slot. Doesn't work particularly well yet, and I feel the system does not need it.
|
||||
// Would probably be required if we decide to slow down the pointer movement.
|
||||
// 4J Stu - There was a request to be able to navigate the scenes with the dpad, so I have used much of the TAP_DETECTION
|
||||
|
||||
@@ -20,9 +20,9 @@ protected:
|
||||
eGroupTab_Right
|
||||
};
|
||||
|
||||
static const int m_iMaxHSlotC = 12;
|
||||
static const int m_iMaxHCraftingSlotC = 10;
|
||||
static const int m_iMaxVSlotC = 17;
|
||||
static const int m_iMaxHSlotC = 40;
|
||||
static const int m_iMaxHCraftingSlotC = 40;
|
||||
static const int m_iMaxVSlotC = 99;
|
||||
static const int m_iMaxDisplayedVSlotC = 3;
|
||||
static const int m_iIngredients3x3SlotC = 9;
|
||||
static const int m_iIngredients2x2SlotC = 4;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.world.item.h"
|
||||
#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h"
|
||||
#include "..\..\Minecraft.h"
|
||||
#include "..\..\Options.h"
|
||||
#include "..\..\MultiPlayerLocalPlayer.h"
|
||||
#include "..\..\ClientConnection.h"
|
||||
#include "IUIScene_TradingMenu.h"
|
||||
@@ -368,7 +369,13 @@ void IUIScene_TradingMenu::setTradeItem(int index, shared_ptr<ItemInstance> item
|
||||
|
||||
vector<HtmlString> *IUIScene_TradingMenu::GetItemDescription(shared_ptr<ItemInstance> item)
|
||||
{
|
||||
vector<HtmlString> *lines = item->getHoverText(nullptr, false);
|
||||
bool advanced = false;
|
||||
if (const Minecraft* pMinecraft = Minecraft::GetInstance())
|
||||
{
|
||||
if (pMinecraft->options)
|
||||
advanced = pMinecraft->options->advancedTooltips;
|
||||
}
|
||||
vector<HtmlString> *lines = item->getHoverText(nullptr, advanced);
|
||||
|
||||
// Add rarity to first line
|
||||
if (lines->size() > 0)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "UI.h"
|
||||
#include "UIControl_TextInput.h"
|
||||
#include "..\..\Screen.h"
|
||||
|
||||
UIControl_TextInput::UIControl_TextInput()
|
||||
{
|
||||
@@ -211,6 +212,31 @@ UIControl_TextInput::EDirectEditResult UIControl_TextInput::tickDirectEdit()
|
||||
}
|
||||
}
|
||||
|
||||
// Paste from clipboard
|
||||
if (g_KBMInput.IsKeyPressed('V') && g_KBMInput.IsKeyDown(VK_CONTROL))
|
||||
{
|
||||
wstring pasted = Screen::getClipboard();
|
||||
wstring sanitized;
|
||||
sanitized.reserve(pasted.length());
|
||||
|
||||
for (wchar_t pc : pasted)
|
||||
{
|
||||
if (pc >= 0x20) // Keep printable characters
|
||||
{
|
||||
if (m_iCharLimit > 0 && (m_editBuffer.length() + sanitized.length()) >= (size_t)m_iCharLimit)
|
||||
break;
|
||||
sanitized += pc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sanitized.empty())
|
||||
{
|
||||
m_editBuffer.insert(m_iCursorPos, sanitized);
|
||||
m_iCursorPos += (int)sanitized.length();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Arrow keys, Home, End, Delete for cursor movement
|
||||
if (g_KBMInput.IsKeyPressed(VK_LEFT) && m_iCursorPos > 0)
|
||||
{
|
||||
|
||||
@@ -41,10 +41,6 @@ void UIScene_AbstractContainerMenu::handleDestroy()
|
||||
app.DebugPrintf("UIScene_AbstractContainerMenu::handleDestroy\n");
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
g_savedInventoryCursorPos.x = m_pointerPos.x;
|
||||
g_savedInventoryCursorPos.y = m_pointerPos.y;
|
||||
g_savedInventoryCursorPos.hasSavedPos = true;
|
||||
|
||||
g_KBMInput.SetScreenCursorHidden(false);
|
||||
g_KBMInput.SetCursorHiddenForUI(false);
|
||||
#endif
|
||||
@@ -173,16 +169,16 @@ void UIScene_AbstractContainerMenu::PlatformInitialize(int iPad, int startIndex)
|
||||
m_pointerPos = vPointerPos;
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
if (g_savedInventoryCursorPos.hasSavedPos)
|
||||
if ((iPad == 0) && g_KBMInput.IsKBMActive())
|
||||
{
|
||||
m_pointerPos.x = g_savedInventoryCursorPos.x;
|
||||
m_pointerPos.y = g_savedInventoryCursorPos.y;
|
||||
|
||||
if (m_pointerPos.x < m_fPointerMinX) m_pointerPos.x = m_fPointerMinX;
|
||||
if (m_pointerPos.x > m_fPointerMaxX) m_pointerPos.x = m_fPointerMaxX;
|
||||
if (m_pointerPos.y < m_fPointerMinY) m_pointerPos.y = m_fPointerMinY;
|
||||
if (m_pointerPos.y > m_fPointerMaxY) m_pointerPos.y = m_fPointerMaxY;
|
||||
m_pointerPos.x = ((m_fPanelMinX + m_fPanelMaxX) * 0.5f) - m_fPointerImageOffsetX;
|
||||
m_pointerPos.y = ((m_fPanelMinY + m_fPanelMaxY) * 0.5f) - m_fPointerImageOffsetY;
|
||||
}
|
||||
|
||||
if (m_pointerPos.x < m_fPointerMinX) m_pointerPos.x = m_fPointerMinX;
|
||||
if (m_pointerPos.x > m_fPointerMaxX) m_pointerPos.x = m_fPointerMaxX;
|
||||
if (m_pointerPos.y < m_fPointerMinY) m_pointerPos.y = m_fPointerMinY;
|
||||
if (m_pointerPos.y > m_fPointerMaxY) m_pointerPos.y = m_fPointerMaxY;
|
||||
#endif
|
||||
|
||||
IggyEvent mouseEvent;
|
||||
|
||||
@@ -2,6 +2,16 @@
|
||||
#include "UI.h"
|
||||
#include "UIScene_ConnectingProgress.h"
|
||||
#include "..\..\Minecraft.h"
|
||||
#ifdef _WINDOWS64
|
||||
#include "..\..\Windows64\Network\WinsockNetLayer.h"
|
||||
#include "..\..\..\Minecraft.World\DisconnectPacket.h"
|
||||
|
||||
static int ConnectingProgress_OnRejectedDialogOK(LPVOID, int iPad, const C4JStorage::EMessageResult)
|
||||
{
|
||||
ui.NavigateBack(iPad);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
UIScene_ConnectingProgress::UIScene_ConnectingProgress(int iPad, void *_initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
|
||||
{
|
||||
@@ -43,6 +53,12 @@ UIScene_ConnectingProgress::UIScene_ConnectingProgress(int iPad, void *_initData
|
||||
m_cancelFuncParam = param->cancelFuncParam;
|
||||
m_removeLocalPlayer = false;
|
||||
m_showingButton = false;
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
WinsockNetLayer::eJoinState initState = WinsockNetLayer::GetJoinState();
|
||||
m_asyncJoinActive = (initState != WinsockNetLayer::eJoinState_Idle && initState != WinsockNetLayer::eJoinState_Cancelled);
|
||||
m_asyncJoinFailed = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
UIScene_ConnectingProgress::~UIScene_ConnectingProgress()
|
||||
@@ -53,6 +69,18 @@ UIScene_ConnectingProgress::~UIScene_ConnectingProgress()
|
||||
|
||||
void UIScene_ConnectingProgress::updateTooltips()
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
if (m_asyncJoinActive)
|
||||
{
|
||||
ui.SetTooltips( m_iPad, -1, IDS_TOOLTIPS_BACK);
|
||||
return;
|
||||
}
|
||||
if (m_asyncJoinFailed)
|
||||
{
|
||||
ui.SetTooltips( m_iPad, IDS_TOOLTIPS_SELECT, -1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// 4J-PB - removing the option of cancel join, since it didn't work anyway
|
||||
//ui.SetTooltips( m_iPad, -1, m_showTooltips?IDS_TOOLTIPS_CANCEL_JOIN:-1);
|
||||
ui.SetTooltips( m_iPad, -1, -1);
|
||||
@@ -62,6 +90,85 @@ void UIScene_ConnectingProgress::tick()
|
||||
{
|
||||
UIScene::tick();
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
if (m_asyncJoinActive)
|
||||
{
|
||||
WinsockNetLayer::eJoinState state = WinsockNetLayer::GetJoinState();
|
||||
if (state == WinsockNetLayer::eJoinState_Connecting)
|
||||
{
|
||||
// connecting.............
|
||||
int attempt = WinsockNetLayer::GetJoinAttempt();
|
||||
int maxAttempts = WinsockNetLayer::GetJoinMaxAttempts();
|
||||
char buf[128];
|
||||
if (attempt <= 1)
|
||||
sprintf_s(buf, "Connecting...");
|
||||
else
|
||||
sprintf_s(buf, "Connecting failed, trying again (%d/%d)", attempt, maxAttempts);
|
||||
wchar_t wbuf[128];
|
||||
mbstowcs(wbuf, buf, 128);
|
||||
m_labelTitle.setLabel(wstring(wbuf));
|
||||
}
|
||||
else if (state == WinsockNetLayer::eJoinState_Success)
|
||||
{
|
||||
m_asyncJoinActive = false;
|
||||
// go go go
|
||||
}
|
||||
else if (state == WinsockNetLayer::eJoinState_Cancelled)
|
||||
{
|
||||
// cancel
|
||||
m_asyncJoinActive = false;
|
||||
navigateBack();
|
||||
}
|
||||
else if (state == WinsockNetLayer::eJoinState_Rejected)
|
||||
{
|
||||
// server full and banned are passed differently compared to other disconnects it seems
|
||||
m_asyncJoinActive = false;
|
||||
DisconnectPacket::eDisconnectReason reason = WinsockNetLayer::GetJoinRejectReason();
|
||||
int exitReasonStringId;
|
||||
switch (reason)
|
||||
{
|
||||
case DisconnectPacket::eDisconnect_ServerFull:
|
||||
exitReasonStringId = IDS_DISCONNECTED_SERVER_FULL;
|
||||
break;
|
||||
case DisconnectPacket::eDisconnect_Banned:
|
||||
exitReasonStringId = IDS_DISCONNECTED_KICKED;
|
||||
break;
|
||||
default:
|
||||
exitReasonStringId = IDS_CONNECTION_LOST_SERVER;
|
||||
break;
|
||||
}
|
||||
UINT uiIDA[1];
|
||||
uiIDA[0] = IDS_CONFIRM_OK;
|
||||
ui.RequestErrorMessage(IDS_CONNECTION_FAILED, exitReasonStringId, uiIDA, 1, ProfileManager.GetPrimaryPad(), ConnectingProgress_OnRejectedDialogOK, nullptr, nullptr);
|
||||
}
|
||||
else if (state == WinsockNetLayer::eJoinState_Failed)
|
||||
{
|
||||
// FAIL
|
||||
m_asyncJoinActive = false;
|
||||
m_asyncJoinFailed = true;
|
||||
|
||||
int maxAttempts = WinsockNetLayer::GetJoinMaxAttempts();
|
||||
char buf[256];
|
||||
sprintf_s(buf, "Failed to connect after %d attempts. The server may be unavailable.", maxAttempts);
|
||||
wchar_t wbuf[256];
|
||||
mbstowcs(wbuf, buf, 256);
|
||||
|
||||
// TIL that these exist
|
||||
// not going to use a actual popup due to it requiring messing with strings which can really mess things up
|
||||
// i dont trust myself with that
|
||||
// these need to be touched up later as teh button is a bit offset
|
||||
m_labelTitle.setLabel(L"Unable to connect to server");
|
||||
m_progressBar.setLabel(wstring(wbuf));
|
||||
m_progressBar.showBar(false);
|
||||
m_progressBar.setVisible(true);
|
||||
m_buttonConfirm.setVisible(true);
|
||||
m_showingButton = true;
|
||||
m_controlTimer.setVisible(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( m_removeLocalPlayer )
|
||||
{
|
||||
m_removeLocalPlayer = false;
|
||||
@@ -94,6 +201,8 @@ void UIScene_ConnectingProgress::handleGainFocus(bool navBack)
|
||||
|
||||
void UIScene_ConnectingProgress::handleLoseFocus()
|
||||
{
|
||||
if (!m_runFailTimer) return;
|
||||
|
||||
int millisecsLeft = getTimer(0)->targetTime - System::currentTimeMillis();
|
||||
int millisecsTaken = getTimer(0)->duration - millisecsLeft;
|
||||
app.DebugPrintf("\n");
|
||||
@@ -208,6 +317,17 @@ void UIScene_ConnectingProgress::handleInput(int iPad, int key, bool repeat, boo
|
||||
switch(key)
|
||||
{
|
||||
// 4J-PB - Removed the option to cancel join - it didn't work anyway
|
||||
#ifdef _WINDOWS64
|
||||
case ACTION_MENU_CANCEL:
|
||||
if (pressed && m_asyncJoinActive)
|
||||
{
|
||||
m_asyncJoinActive = false;
|
||||
WinsockNetLayer::CancelJoinGame();
|
||||
navigateBack();
|
||||
handled = true;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
// case ACTION_MENU_CANCEL:
|
||||
// {
|
||||
// if(m_cancelFunc != nullptr)
|
||||
@@ -250,6 +370,13 @@ void UIScene_ConnectingProgress::handlePress(F64 controlId, F64 childId)
|
||||
case eControl_Confirm:
|
||||
if(m_showingButton)
|
||||
{
|
||||
#ifdef _WINDOWS64
|
||||
if (m_asyncJoinFailed)
|
||||
{
|
||||
navigateBack();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if( m_iPad != ProfileManager.GetPrimaryPad() && g_NetworkManager.IsInSession() )
|
||||
{
|
||||
// The connection failed if we see the button, so the temp player should be removed and the viewports updated again
|
||||
|
||||
@@ -13,6 +13,11 @@ private:
|
||||
void (*m_cancelFunc)(LPVOID param);
|
||||
LPVOID m_cancelFuncParam;
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
bool m_asyncJoinActive;
|
||||
bool m_asyncJoinFailed;
|
||||
#endif
|
||||
|
||||
enum EControls
|
||||
{
|
||||
eControl_Confirm
|
||||
|
||||
@@ -583,6 +583,24 @@ void UIScene_JoinMenu::JoinGame(UIScene_JoinMenu* pClass)
|
||||
// Alert the app the we no longer want to be informed of ethernet connections
|
||||
app.SetLiveLinkRequired( false );
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
if (result == CGameNetworkManager::JOINGAME_PENDING)
|
||||
{
|
||||
pClass->m_bIgnoreInput = false;
|
||||
|
||||
ConnectionProgressParams *param = new ConnectionProgressParams();
|
||||
param->iPad = ProfileManager.GetPrimaryPad();
|
||||
param->stringId = -1;
|
||||
param->showTooltips = true;
|
||||
param->setFailTimer = false;
|
||||
param->timerTime = 0;
|
||||
param->cancelFunc = nullptr;
|
||||
param->cancelFuncParam = nullptr;
|
||||
ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_ConnectingProgress, param);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( result != CGameNetworkManager::JOINGAME_SUCCESS )
|
||||
{
|
||||
int exitReasonStringId = -1;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "stdafx.h"
|
||||
#include "UI.h"
|
||||
#include "UIScene_Keyboard.h"
|
||||
#include "..\..\Screen.h"
|
||||
|
||||
#ifdef _WINDOWS64
|
||||
// Global buffer that stores the text entered in the native keyboard scene.
|
||||
@@ -224,6 +225,38 @@ void UIScene_Keyboard::tick()
|
||||
}
|
||||
}
|
||||
|
||||
// Paste from clipboard
|
||||
if (g_KBMInput.IsKeyPressed('V') && g_KBMInput.IsKeyDown(VK_CONTROL))
|
||||
{
|
||||
wstring pasted = Screen::getClipboard();
|
||||
wstring sanitized;
|
||||
sanitized.reserve(pasted.length());
|
||||
|
||||
for (wchar_t pc : pasted)
|
||||
{
|
||||
if (pc >= 0x20) // Keep printable characters
|
||||
{
|
||||
if (static_cast<int>(m_win64TextBuffer.length() + sanitized.length()) >= m_win64MaxChars)
|
||||
break;
|
||||
sanitized += pc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sanitized.empty())
|
||||
{
|
||||
if (m_bPCMode)
|
||||
{
|
||||
m_win64TextBuffer.insert(m_iCursorPos, sanitized);
|
||||
m_iCursorPos += (int)sanitized.length();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_win64TextBuffer += sanitized;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bPCMode)
|
||||
{
|
||||
// Arrow keys, Home, End, Delete for cursor movement
|
||||
|
||||
@@ -222,9 +222,8 @@ void UIScene_SettingsGraphicsMenu::handleSliderMove(F64 sliderId, F64 currentVal
|
||||
const int fovValue = sliderValueToFov(value);
|
||||
pMinecraft->gameRenderer->SetFovVal(static_cast<float>(fovValue));
|
||||
app.SetGameSettings(m_iPad, eGameSetting_FOV, value);
|
||||
WCHAR tempString[256];
|
||||
swprintf(tempString, 256, L"FOV: %d", fovValue);
|
||||
m_sliderFOV.setLabel(tempString);
|
||||
swprintf(TempString, 256, L"FOV: %d", fovValue);
|
||||
m_sliderFOV.setLabel(TempString);
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -45,46 +45,46 @@ Font::Font(Options *options, const wstring& name, Textures* textures, bool enfor
|
||||
random = new Random();
|
||||
|
||||
// Load the image
|
||||
BufferedImage *img = textures->readImage(textureLocation->getTexture(), name);
|
||||
BufferedImage *img = textures->readImage(textureLocation->getTexture(), name);
|
||||
|
||||
/* - 4J - TODO
|
||||
try {
|
||||
img = ImageIO.read(Textures.class.getResourceAsStream(name));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
img = ImageIO.read(Textures.class.getResourceAsStream(name));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
*/
|
||||
|
||||
int w = img->getWidth();
|
||||
int h = img->getHeight();
|
||||
intArray rawPixels(w * h);
|
||||
img->getRGB(0, 0, w, h, rawPixels, 0, w);
|
||||
int w = img->getWidth();
|
||||
int h = img->getHeight();
|
||||
intArray rawPixels(w * h);
|
||||
img->getRGB(0, 0, w, h, rawPixels, 0, w);
|
||||
|
||||
for (int i = 0; i < charC; i++)
|
||||
for (int i = 0; i < charC; i++)
|
||||
{
|
||||
int xt = i % m_cols;
|
||||
int yt = i / m_cols;
|
||||
int xt = i % m_cols;
|
||||
int yt = i / m_cols;
|
||||
|
||||
int x = 7;
|
||||
for (; x >= 0; x--)
|
||||
int x = 7;
|
||||
for (; x >= 0; x--)
|
||||
{
|
||||
int xPixel = xt * 8 + x;
|
||||
bool emptyColumn = true;
|
||||
for (int y = 0; y < 8 && emptyColumn; y++)
|
||||
int xPixel = xt * 8 + x;
|
||||
bool emptyColumn = true;
|
||||
for (int y = 0; y < 8 && emptyColumn; y++)
|
||||
{
|
||||
int yPixel = (yt * 8 + y) * w;
|
||||
int yPixel = (yt * 8 + y) * w;
|
||||
bool emptyPixel = (rawPixels[xPixel + yPixel] >> 24) == 0; // Check the alpha value
|
||||
if (!emptyPixel) emptyColumn = false;
|
||||
}
|
||||
if (!emptyColumn)
|
||||
if (!emptyPixel) emptyColumn = false;
|
||||
}
|
||||
if (!emptyColumn)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ' ') x = 4 - 2;
|
||||
charWidths[i] = x + 2;
|
||||
}
|
||||
if (i == ' ') x = 4 - 2;
|
||||
charWidths[i] = x + 2;
|
||||
}
|
||||
|
||||
delete img;
|
||||
|
||||
@@ -130,6 +130,7 @@ Font::~Font()
|
||||
}
|
||||
#endif
|
||||
|
||||
// Legacy helper used by renderCharacter() only.
|
||||
void Font::renderStyleLine(float x0, float y0, float x1, float y1)
|
||||
{
|
||||
Tesselator* t = Tesselator::getInstance();
|
||||
@@ -146,7 +147,20 @@ void Font::renderStyleLine(float x0, float y0, float x1, float y1)
|
||||
t->end();
|
||||
}
|
||||
|
||||
void Font::addCharacterQuad(wchar_t c)
|
||||
void Font::addSolidQuad(float x0, float y0, float x1, float y1)
|
||||
{
|
||||
Tesselator *t = Tesselator::getInstance();
|
||||
t->tex(0.0f, 0.0f);
|
||||
t->vertex(x0, y1, 0.0f);
|
||||
t->tex(0.0f, 0.0f);
|
||||
t->vertex(x1, y1, 0.0f);
|
||||
t->tex(0.0f, 0.0f);
|
||||
t->vertex(x1, y0, 0.0f);
|
||||
t->tex(0.0f, 0.0f);
|
||||
t->vertex(x0, y0, 0.0f);
|
||||
}
|
||||
|
||||
void Font::emitCharacterGeometry(wchar_t c)
|
||||
{
|
||||
float xOff = c % m_cols * m_charWidth;
|
||||
float yOff = c / m_cols * m_charHeight; // was m_charWidth — wrong when glyphs aren't square
|
||||
@@ -180,52 +194,45 @@ void Font::addCharacterQuad(wchar_t c)
|
||||
t->tex(xOff / fontWidth, yOff / fontHeight);
|
||||
t->vertex(x0 + dx, y0, 0.0f);
|
||||
}
|
||||
|
||||
xPos += static_cast<float>(charWidths[c]);
|
||||
}
|
||||
|
||||
void Font::addCharacterQuad(wchar_t c)
|
||||
{
|
||||
float height = m_charHeight - .01f;
|
||||
float x0 = xPos;
|
||||
float y0 = yPos;
|
||||
float y1 = yPos + height;
|
||||
float advance = static_cast<float>(charWidths[c]);
|
||||
|
||||
emitCharacterGeometry(c);
|
||||
|
||||
if (m_underline)
|
||||
{
|
||||
addSolidQuad(x0, y1 - 1.0f, xPos + advance, y1);
|
||||
}
|
||||
|
||||
if (m_strikethrough)
|
||||
{
|
||||
float mid = y0 + height * 0.5f;
|
||||
addSolidQuad(x0, mid - 0.5f, xPos + advance, mid + 0.5f);
|
||||
}
|
||||
|
||||
xPos += advance;
|
||||
}
|
||||
|
||||
// Legacy helper used by drawLiteral() only.
|
||||
void Font::renderCharacter(wchar_t c)
|
||||
{
|
||||
float xOff = c % m_cols * m_charWidth;
|
||||
float yOff = c / m_cols * m_charHeight; // was m_charWidth — wrong when glyphs aren't square
|
||||
|
||||
float width = charWidths[c] - .01f;
|
||||
float height = m_charHeight - .01f;
|
||||
|
||||
float fontWidth = m_cols * m_charWidth;
|
||||
float fontHeight = m_rows * m_charHeight;
|
||||
|
||||
const float shear = m_italic ? (height * 0.25f) : 0.0f;
|
||||
float x0 = xPos, x1 = xPos + width + shear;
|
||||
float y0 = yPos, y1 = yPos + height;
|
||||
float x0 = xPos;
|
||||
float y0 = yPos;
|
||||
float y1 = yPos + height;
|
||||
|
||||
Tesselator *t = Tesselator::getInstance();
|
||||
t->begin();
|
||||
t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight);
|
||||
t->vertex(x0, y1, 0.0f);
|
||||
t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight);
|
||||
t->vertex(x1, y1, 0.0f);
|
||||
t->tex((xOff + width) / fontWidth, yOff / fontHeight);
|
||||
t->vertex(x1, y0, 0.0f);
|
||||
t->tex(xOff / fontWidth, yOff / fontHeight);
|
||||
t->vertex(x0, y0, 0.0f);
|
||||
emitCharacterGeometry(c);
|
||||
t->end();
|
||||
|
||||
if (m_bold)
|
||||
{
|
||||
float dx = 1.0f;
|
||||
t->begin();
|
||||
t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight);
|
||||
t->vertex(x0 + dx, y1, 0.0f);
|
||||
t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight);
|
||||
t->vertex(x1 + dx, y1, 0.0f);
|
||||
t->tex((xOff + width) / fontWidth, yOff / fontHeight);
|
||||
t->vertex(x1 + dx, y0, 0.0f);
|
||||
t->tex(xOff / fontWidth, yOff / fontHeight);
|
||||
t->vertex(x0 + dx, y0, 0.0f);
|
||||
t->end();
|
||||
}
|
||||
|
||||
if (m_underline)
|
||||
renderStyleLine(x0, y1 - 1.0f, xPos + static_cast<float>(charWidths[c]), y1);
|
||||
|
||||
@@ -240,8 +247,8 @@ void Font::renderCharacter(wchar_t c)
|
||||
|
||||
void Font::drawShadow(const wstring& str, int x, int y, int color)
|
||||
{
|
||||
draw(str, x + 1, y + 1, color, true);
|
||||
draw(str, x, y, color, false);
|
||||
draw(str, x + 1, y + 1, color, true);
|
||||
draw(str, x, y, color, false);
|
||||
}
|
||||
|
||||
void Font::drawShadowLiteral(const wstring& str, int x, int y, int color)
|
||||
@@ -289,7 +296,7 @@ static bool isSectionFormatCode(wchar_t ca)
|
||||
return l == L'l' || l == L'o' || l == L'n' || l == L'm' || l == L'r' || l == L'k';
|
||||
}
|
||||
|
||||
void Font::draw(const wstring &str, bool dropShadow)
|
||||
void Font::draw(const wstring &str, bool dropShadow, int initialColor)
|
||||
{
|
||||
// Bind the texture
|
||||
textures->bindTexture(m_textureLocation);
|
||||
@@ -297,8 +304,11 @@ void Font::draw(const wstring &str, bool dropShadow)
|
||||
m_bold = m_italic = m_underline = m_strikethrough = false;
|
||||
wstring cleanStr = sanitize(str);
|
||||
|
||||
int currentColor = initialColor;
|
||||
|
||||
Tesselator *t = Tesselator::getInstance();
|
||||
t->begin();
|
||||
t->color(currentColor & 0x00ffffff, (currentColor >> 24) & 255);
|
||||
|
||||
for (int i = 0; i < static_cast<int>(cleanStr.length()); ++i)
|
||||
{
|
||||
@@ -310,10 +320,8 @@ void Font::draw(const wstring &str, bool dropShadow)
|
||||
wchar_t ca = cleanStr[i+1];
|
||||
if (!isSectionFormatCode(ca))
|
||||
{
|
||||
t->end();
|
||||
renderCharacter(167);
|
||||
renderCharacter(ca);
|
||||
t->begin();
|
||||
addCharacterQuad(167);
|
||||
addCharacterQuad(ca);
|
||||
i += 1;
|
||||
continue;
|
||||
}
|
||||
@@ -329,7 +337,12 @@ void Font::draw(const wstring &str, bool dropShadow)
|
||||
else if (l == L'o') m_italic = true;
|
||||
else if (l == L'n') m_underline = true;
|
||||
else if (l == L'm') m_strikethrough = true;
|
||||
else if (l == L'r') m_bold = m_italic = m_underline = m_strikethrough = noise = false;
|
||||
else if (l == L'r')
|
||||
{
|
||||
m_bold = m_italic = m_underline = m_strikethrough = noise = false;
|
||||
currentColor = initialColor;
|
||||
t->color(currentColor & 0x00ffffff, (currentColor >> 24) & 255);
|
||||
}
|
||||
else if (l == L'k') noise = true;
|
||||
}
|
||||
else
|
||||
@@ -337,8 +350,8 @@ void Font::draw(const wstring &str, bool dropShadow)
|
||||
noise = false;
|
||||
if (colorN < 0 || colorN > 15) colorN = 15;
|
||||
if (dropShadow) colorN += 16;
|
||||
int color = colors[colorN];
|
||||
glColor3f((color >> 16) / 255.0F, ((color >> 8) & 255) / 255.0F, (color & 255) / 255.0F);
|
||||
currentColor = (initialColor & 0xff000000) | colors[colorN];
|
||||
t->color(currentColor & 0x00ffffff, (currentColor >> 24) & 255);
|
||||
}
|
||||
i += 1;
|
||||
continue;
|
||||
@@ -371,11 +384,11 @@ void Font::draw(const wstring& str, int x, int y, int color, bool dropShadow)
|
||||
if (dropShadow) // divide RGB by 4, preserve alpha
|
||||
color = (color & 0xfcfcfc) >> 2 | (color & (-1 << 24));
|
||||
|
||||
glColor4f((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, (color & 255) / 255.0F, (color >> 24 & 255) / 255.0F);
|
||||
glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
|
||||
xPos = x;
|
||||
yPos = y;
|
||||
draw(str, dropShadow);
|
||||
draw(str, dropShadow, color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -422,9 +435,9 @@ wstring Font::sanitize(const wstring& str)
|
||||
{
|
||||
wstring sb = str;
|
||||
|
||||
for (unsigned int i = 0; i < sb.length(); i++)
|
||||
for (unsigned int i = 0; i < sb.length(); i++)
|
||||
{
|
||||
if (CharacterExists(sb[i]))
|
||||
if (CharacterExists(sb[i]))
|
||||
{
|
||||
sb[i] = MapCharacter(sb[i]);
|
||||
}
|
||||
@@ -433,8 +446,8 @@ wstring Font::sanitize(const wstring& str)
|
||||
// If this character isn't supported, just show the first character (empty square box character)
|
||||
sb[i] = 0;
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
|
||||
int Font::MapCharacter(wchar_t c)
|
||||
@@ -487,95 +500,95 @@ void Font::drawWordWrap(const wstring &string, int x, int y, int w, int col, boo
|
||||
|
||||
void Font::drawWordWrapInternal(const wstring& string, int x, int y, int w, int col, bool darken, int h)
|
||||
{
|
||||
vector<wstring>lines = stringSplit(string,L'\n');
|
||||
if (lines.size() > 1)
|
||||
vector<wstring>lines = stringSplit(string,L'\n');
|
||||
if (lines.size() > 1)
|
||||
{
|
||||
for ( auto& it : lines )
|
||||
{
|
||||
for ( auto& it : lines )
|
||||
{
|
||||
// 4J Stu - Don't draw text that will be partially cutoff/overlap something it shouldn't
|
||||
if( (y + this->wordWrapHeight(it, w)) > h) break;
|
||||
drawWordWrapInternal(it, x, y, w, col, h);
|
||||
y += this->wordWrapHeight(it, w);
|
||||
}
|
||||
return;
|
||||
}
|
||||
vector<wstring> words = stringSplit(string,L' ');
|
||||
unsigned int pos = 0;
|
||||
while (pos < words.size())
|
||||
drawWordWrapInternal(it, x, y, w, col, h);
|
||||
y += this->wordWrapHeight(it, w);
|
||||
}
|
||||
return;
|
||||
}
|
||||
vector<wstring> words = stringSplit(string,L' ');
|
||||
unsigned int pos = 0;
|
||||
while (pos < words.size())
|
||||
{
|
||||
wstring line = words[pos++] + L" ";
|
||||
while (pos < words.size() && width(line + words[pos]) < w)
|
||||
wstring line = words[pos++] + L" ";
|
||||
while (pos < words.size() && width(line + words[pos]) < w)
|
||||
{
|
||||
line += words[pos++] + L" ";
|
||||
}
|
||||
while (width(line) > w)
|
||||
line += words[pos++] + L" ";
|
||||
}
|
||||
while (width(line) > w)
|
||||
{
|
||||
int l = 0;
|
||||
while (width(line.substr(0, l + 1)) <= w)
|
||||
int l = 0;
|
||||
while (width(line.substr(0, l + 1)) <= w)
|
||||
{
|
||||
l++;
|
||||
}
|
||||
if (trimString(line.substr(0, l)).length() > 0)
|
||||
l++;
|
||||
}
|
||||
if (trimString(line.substr(0, l)).length() > 0)
|
||||
{
|
||||
draw(line.substr(0, l), x, y, col);
|
||||
y += 8;
|
||||
}
|
||||
line = line.substr(l);
|
||||
draw(line.substr(0, l), x, y, col);
|
||||
y += 8;
|
||||
}
|
||||
line = line.substr(l);
|
||||
|
||||
// 4J Stu - Don't draw text that will be partially cutoff/overlap something it shouldn't
|
||||
if( (y + 8) > h) break;
|
||||
}
|
||||
}
|
||||
// 4J Stu - Don't draw text that will be partially cutoff/overlap something it shouldn't
|
||||
if (trimString(line).length() > 0 && !( (y + 8) > h) )
|
||||
if (trimString(line).length() > 0 && !( (y + 8) > h) )
|
||||
{
|
||||
draw(line, x, y, col);
|
||||
y += 8;
|
||||
}
|
||||
}
|
||||
draw(line, x, y, col);
|
||||
y += 8;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int Font::wordWrapHeight(const wstring& string, int w)
|
||||
{
|
||||
vector<wstring> lines = stringSplit(string,L'\n');
|
||||
if (lines.size() > 1)
|
||||
vector<wstring> lines = stringSplit(string,L'\n');
|
||||
if (lines.size() > 1)
|
||||
{
|
||||
int h = 0;
|
||||
for ( auto& it : lines )
|
||||
{
|
||||
h += this->wordWrapHeight(it, w);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
int h = 0;
|
||||
for ( auto& it : lines )
|
||||
{
|
||||
h += this->wordWrapHeight(it, w);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
vector<wstring> words = stringSplit(string,L' ');
|
||||
unsigned int pos = 0;
|
||||
int y = 0;
|
||||
while (pos < words.size())
|
||||
unsigned int pos = 0;
|
||||
int y = 0;
|
||||
while (pos < words.size())
|
||||
{
|
||||
wstring line = words[pos++] + L" ";
|
||||
while (pos < words.size() && width(line + words[pos]) < w)
|
||||
wstring line = words[pos++] + L" ";
|
||||
while (pos < words.size() && width(line + words[pos]) < w)
|
||||
{
|
||||
line += words[pos++] + L" ";
|
||||
}
|
||||
while (width(line) > w)
|
||||
line += words[pos++] + L" ";
|
||||
}
|
||||
while (width(line) > w)
|
||||
{
|
||||
int l = 0;
|
||||
int l = 0;
|
||||
while (width(line.substr(0, l + 1)) <= w)
|
||||
{
|
||||
l++;
|
||||
}
|
||||
if (trimString(line.substr(0, l)).length() > 0)
|
||||
l++;
|
||||
}
|
||||
if (trimString(line.substr(0, l)).length() > 0)
|
||||
{
|
||||
y += 8;
|
||||
}
|
||||
line = line.substr(l);
|
||||
}
|
||||
if (trimString(line).length() > 0) {
|
||||
y += 8;
|
||||
}
|
||||
}
|
||||
if (y < 8) y += 8;
|
||||
return y;
|
||||
y += 8;
|
||||
}
|
||||
line = line.substr(l);
|
||||
}
|
||||
if (trimString(line).length() > 0) {
|
||||
y += 8;
|
||||
}
|
||||
}
|
||||
if (y < 8) y += 8;
|
||||
return y;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ private:
|
||||
std::map<int, int> m_charMap;
|
||||
|
||||
public:
|
||||
Font(Options *options, const wstring& name, Textures* textures, bool enforceUnicode, ResourceLocation *textureLocation, int cols, int rows, int charWidth, int charHeight, unsigned short charMap[] = nullptr);
|
||||
Font(Options *options, const wstring& name, Textures* textures, bool enforceUnicode, ResourceLocation *textureLocation, int cols, int rows, int charWidth, int charHeight, unsigned short charMap[] = nullptr);
|
||||
#ifndef _XBOX
|
||||
// 4J Stu - This dtor clashes with one in xui! We never delete these anyway so take it out for now. Can go back when we have got rid of XUI
|
||||
~Font();
|
||||
@@ -48,6 +48,8 @@ public:
|
||||
private:
|
||||
void renderCharacter(wchar_t c); // 4J added
|
||||
void addCharacterQuad(wchar_t c);
|
||||
void addSolidQuad(float x0, float y0, float x1, float y1);
|
||||
void emitCharacterGeometry(wchar_t c);
|
||||
void renderStyleLine(float x0, float y0, float x1, float y1); // solid line for underline/strikethrough
|
||||
|
||||
public:
|
||||
@@ -65,7 +67,7 @@ public:
|
||||
private:
|
||||
wstring reorderBidi(const wstring &str);
|
||||
|
||||
void draw(const wstring &str, bool dropShadow);
|
||||
void draw(const wstring &str, bool dropShadow, int baseColor);
|
||||
void draw(const wstring& str, int x, int y, int color, bool dropShadow);
|
||||
void drawLiteral(const wstring& str, int x, int y, int color); // no § parsing
|
||||
int MapCharacter(wchar_t c); // 4J added
|
||||
|
||||
@@ -1070,111 +1070,146 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
|
||||
lines.push_back(ClientConstants::VERSION_STRING);
|
||||
lines.push_back(ClientConstants::BRANCH_STRING);
|
||||
}
|
||||
|
||||
if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr)
|
||||
{
|
||||
lines.push_back(minecraft->fpsString);
|
||||
lines.push_back(L"E: " + std::to_wstring(minecraft->level->getAllEntities().size()));
|
||||
int renderDistance = app.GetGameSettings(iPad, eGameSetting_RenderDistance);
|
||||
// Calculate the chunk sections using 16 * (2n + 1)^2
|
||||
lines.push_back(L"C: " + std::to_wstring(16 * (2 * renderDistance + 1) * (2 * renderDistance + 1)) + L" D: " + std::to_wstring(renderDistance));
|
||||
lines.push_back(minecraft->gatherStats4());
|
||||
|
||||
// Dimension
|
||||
wstring dimension = L"unknown";
|
||||
switch (minecraft->player->dimension)
|
||||
{
|
||||
case -1: dimension = L"minecraft:the_nether"; break;
|
||||
case 0: dimension = L"minecraft:overworld"; break;
|
||||
case 1: dimension = L"minecraft:the_end"; break;
|
||||
case -1:
|
||||
dimension = L"minecraft:the_nether";
|
||||
break;
|
||||
case 0:
|
||||
dimension = L"minecraft:overworld";
|
||||
break;
|
||||
case 1:
|
||||
dimension = L"minecraft:the_end";
|
||||
break;
|
||||
}
|
||||
lines.push_back(dimension);
|
||||
lines.push_back(L"");
|
||||
|
||||
lines.push_back(L""); // Spacer
|
||||
|
||||
// Players block pos
|
||||
int xBlockPos = Mth::floor(minecraft->player->x);
|
||||
int yBlockPos = Mth::floor(minecraft->player->y);
|
||||
int zBlockPos = Mth::floor(minecraft->player->z);
|
||||
|
||||
// Chunk player is in
|
||||
int xChunkPos = xBlockPos >> 4;
|
||||
int yChunkPos = yBlockPos >> 4;
|
||||
int zChunkPos = zBlockPos >> 4;
|
||||
|
||||
// Players offset within the chunk
|
||||
int xChunkOffset = xBlockPos & 15;
|
||||
int yChunkOffset = yBlockPos & 15;
|
||||
int zChunkOffset = zBlockPos & 15;
|
||||
|
||||
WCHAR posString[44];
|
||||
// Format the position like java with limited decumal places
|
||||
WCHAR posString[44]; // Allows upto 7 digit positions (+-9_999_999)
|
||||
swprintf(posString, 44, L"%.3f / %.5f / %.3f", minecraft->player->x, minecraft->player->y, minecraft->player->z);
|
||||
|
||||
lines.push_back(L"XYZ: " + std::wstring(posString));
|
||||
lines.push_back(L"Block: " + std::to_wstring(xBlockPos) + L" " + std::to_wstring(yBlockPos) + L" " + std::to_wstring(zBlockPos));
|
||||
lines.push_back(L"Chunk: " + std::to_wstring(xChunkOffset) + L" " + std::to_wstring(yChunkOffset) + L" " + std::to_wstring(zChunkOffset) + L" in " + std::to_wstring(xChunkPos) + L" " + std::to_wstring(yChunkPos) + L" " + std::to_wstring(zChunkPos));
|
||||
|
||||
// Wrap the yRot to 360 then adjust to (-180 to 180) range to match java
|
||||
float yRotDisplay = fmod(minecraft->player->yRot, 360.0f);
|
||||
if (yRotDisplay > 180.0f) yRotDisplay -= 360.0f;
|
||||
if (yRotDisplay < -180.0f) yRotDisplay += 360.0f;
|
||||
// Generate the angle string in the format "yRot / xRot" with one decimal place, similar to java edition
|
||||
WCHAR angleString[16];
|
||||
swprintf(angleString, 16, L"%.1f / %.1f", yRotDisplay, minecraft->player->xRot);
|
||||
|
||||
// Work out the named direction
|
||||
int direction = Mth::floor(minecraft->player->yRot * 4.0f / 360.0f + 0.5) & 0x3;
|
||||
const wchar_t* cardinals[] = { L"south", L"west", L"north", L"east" };
|
||||
lines.push_back(L"Facing: " + std::wstring(cardinals[direction]) + L" (" + angleString + L")");
|
||||
|
||||
// We have to limit y to 256 as we don't get any information past that
|
||||
if (minecraft->level != NULL && minecraft->level->hasChunkAt(xBlockPos, fmod(yBlockPos, 256), zBlockPos))
|
||||
{
|
||||
LevelChunk *chunkAt = minecraft->level->getChunkAt(xBlockPos, zBlockPos);
|
||||
if (chunkAt != NULL)
|
||||
{
|
||||
int skyLight = chunkAt->getBrightness(LightLayer::Sky, xChunkOffset, yChunkOffset, zChunkOffset);
|
||||
int skyLight = chunkAt->getBrightness(LightLayer::Sky, xChunkOffset, yChunkOffset, zChunkOffset);
|
||||
int blockLight = chunkAt->getBrightness(LightLayer::Block, xChunkOffset, yChunkOffset, zChunkOffset);
|
||||
int maxLight = fmax(skyLight, blockLight);
|
||||
int maxLight = fmax(skyLight, blockLight);
|
||||
lines.push_back(L"Light: " + std::to_wstring(maxLight) + L" (" + std::to_wstring(skyLight) + L" sky, " + std::to_wstring(blockLight) + L" block)");
|
||||
|
||||
lines.push_back(L"CH S: " + std::to_wstring(chunkAt->getHeightmap(xChunkOffset, zChunkOffset)));
|
||||
|
||||
Biome *biome = chunkAt->getBiome(xChunkOffset, zChunkOffset, minecraft->level->getBiomeSource());
|
||||
lines.push_back(L"Biome: " + biome->m_name + L" (" + std::to_wstring(biome->id) + L")");
|
||||
|
||||
lines.push_back(L"Difficulty: " + std::to_wstring(minecraft->level->difficulty) + L" (Day " + std::to_wstring(minecraft->level->getGameTime() / Level::TICKS_PER_DAY) + L")");
|
||||
}
|
||||
}
|
||||
|
||||
lines.push_back(L"");
|
||||
// This is all LCE only stuff, it was never on java
|
||||
lines.push_back(L""); // Spacer
|
||||
lines.push_back(L"Seed: " + std::to_wstring(minecraft->level->getLevelData()->getSeed()));
|
||||
lines.push_back(minecraft->gatherStats1());
|
||||
lines.push_back(minecraft->gatherStats2());
|
||||
lines.push_back(minecraft->gatherStats3());
|
||||
}
|
||||
lines.push_back(minecraft->gatherStats1()); // Time to autosave
|
||||
lines.push_back(minecraft->gatherStats2()); // Empty currently - CPlatformNetworkManagerStub::GatherStats()
|
||||
lines.push_back(minecraft->gatherStats3()); // RTT
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (minecraft->options->renderDebug && minecraft->player != nullptr && minecraft->level != nullptr && minecraft->level->dimension->id == 0)
|
||||
{
|
||||
wstring wfeature[eTerrainFeature_Count];
|
||||
wfeature[eTerrainFeature_Stronghold] = L"Stronghold: ";
|
||||
wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: ";
|
||||
wfeature[eTerrainFeature_Village] = L"Village: ";
|
||||
wfeature[eTerrainFeature_Ravine] = L"Ravine: ";
|
||||
|
||||
// maxW in font units: physical width divided by font scale
|
||||
float maxW = (static_cast<float>(g_rScreenWidth) - debugLeft - 8) / fontScale;
|
||||
float maxWForContent = maxW - static_cast<float>(font->width(L"..."));
|
||||
bool truncated[eTerrainFeature_Count] = {};
|
||||
|
||||
for (size_t i = 0; i < app.m_vTerrainFeatures.size(); i++)
|
||||
#ifdef _DEBUG // Only show terrain features in debug builds not release
|
||||
|
||||
// No point trying to render this when not in the overworld
|
||||
if (minecraft->level->dimension->id == 0)
|
||||
{
|
||||
FEATURE_DATA *pFeatureData = app.m_vTerrainFeatures[i];
|
||||
int type = pFeatureData->eTerrainFeature;
|
||||
if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine) continue;
|
||||
if (truncated[type]) continue;
|
||||
wstring itemInfo = L"[" + std::to_wstring(pFeatureData->x * 16) + L", " + std::to_wstring(pFeatureData->z * 16) + L"] ";
|
||||
if (font->width(wfeature[type] + itemInfo) <= maxWForContent)
|
||||
wfeature[type] += itemInfo;
|
||||
else
|
||||
wstring wfeature[eTerrainFeature_Count];
|
||||
wfeature[eTerrainFeature_Stronghold] = L"Stronghold: ";
|
||||
wfeature[eTerrainFeature_Mineshaft] = L"Mineshaft: ";
|
||||
wfeature[eTerrainFeature_Village] = L"Village: ";
|
||||
wfeature[eTerrainFeature_Ravine] = L"Ravine: ";
|
||||
|
||||
// maxW in font units: physical width divided by font scale
|
||||
float maxW = (static_cast<float>(g_rScreenWidth) - debugLeft - 8) / fontScale;
|
||||
float maxWForContent = maxW - static_cast<float>(font->width(L"..."));
|
||||
bool truncated[eTerrainFeature_Count] = {};
|
||||
|
||||
for (size_t i = 0; i < app.m_vTerrainFeatures.size(); i++)
|
||||
{
|
||||
wfeature[type] += L"...";
|
||||
truncated[type] = true;
|
||||
FEATURE_DATA *pFeatureData = app.m_vTerrainFeatures[i];
|
||||
int type = pFeatureData->eTerrainFeature;
|
||||
if (type < eTerrainFeature_Stronghold || type > eTerrainFeature_Ravine) continue;
|
||||
if (truncated[type]) continue;
|
||||
|
||||
wstring itemInfo = L"[" + std::to_wstring(pFeatureData->x * 16) + L", " + std::to_wstring(pFeatureData->z * 16) + L"] ";
|
||||
if (font->width(wfeature[type] + itemInfo) <= maxWForContent)
|
||||
{
|
||||
wfeature[type] += itemInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
wfeature[type] += L"...";
|
||||
truncated[type] = true;
|
||||
}
|
||||
}
|
||||
|
||||
lines.push_back(L""); // Spacer
|
||||
for (int i = eTerrainFeature_Stronghold; i <= static_cast<int>(eTerrainFeature_Ravine); i++)
|
||||
{
|
||||
lines.push_back(wfeature[i]);
|
||||
}
|
||||
lines.push_back(L""); // Spacer
|
||||
}
|
||||
|
||||
lines.push_back(L"");
|
||||
for (int i = eTerrainFeature_Stronghold; i <= static_cast<int>(eTerrainFeature_Ravine); i++)
|
||||
lines.push_back(wfeature[i]);
|
||||
lines.push_back(L"");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Disable the depth test so the text shows on top of the paperdoll
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
// Loop through the lines and draw them all on screen
|
||||
int yPos = debugTop;
|
||||
for (const auto &line : lines)
|
||||
{
|
||||
@@ -1182,6 +1217,9 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
|
||||
yPos += 10;
|
||||
}
|
||||
|
||||
// Restore the depth test
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
|
||||
@@ -170,6 +170,7 @@ void Options::init()
|
||||
particles = 0;
|
||||
fov = 0;
|
||||
gamma = 0;
|
||||
advancedTooltips = false;
|
||||
}
|
||||
|
||||
Options::Options(Minecraft *minecraft, File workingDirectory)
|
||||
@@ -451,8 +452,9 @@ void Options::load()
|
||||
if (cmds[0] == L"fancyGraphics") fancyGraphics = cmds[1]==L"true";
|
||||
if (cmds[0] == L"ao") ambientOcclusion = cmds[1]==L"true";
|
||||
if (cmds[0] == L"clouds") renderClouds = cmds[1]==L"true";
|
||||
if (cmds[0] == L"skin") skin = cmds[1];
|
||||
if (cmds[0] == L"lastServer") lastMpIp = cmds[1];
|
||||
if (cmds[0] == L"advancedTooltips") advancedTooltips = cmds[1]==L"false";
|
||||
if (cmds[0] == L"skin") skin = cmds[1];
|
||||
if (cmds[0] == L"lastServer") lastMpIp = cmds[1];
|
||||
|
||||
for (int i = 0; i < keyMappings_length; i++)
|
||||
{
|
||||
@@ -508,7 +510,8 @@ void Options::save()
|
||||
dos.writeChars(L"fancyGraphics:" + wstring(fancyGraphics ? L"true" : L"false"));
|
||||
dos.writeChars(ambientOcclusion ? L"ao:true" : L"ao:false");
|
||||
dos.writeChars(renderClouds ? L"clouds:true" : L"clouds:false");
|
||||
dos.writeChars(L"skin:" + skin);
|
||||
dos.writeChars(advancedTooltips ? L"advancedTooltips:true" : L"advancedTooltips:false");
|
||||
dos.writeChars(L"skin:" + skin);
|
||||
dos.writeChars(L"lastServer:" + lastMpIp);
|
||||
|
||||
for (int i = 0; i < keyMappings_length; i++)
|
||||
|
||||
@@ -110,6 +110,7 @@ public:
|
||||
int particles; // 0 is all, 1 is decreased and 2 is minimal
|
||||
float fov;
|
||||
float gamma;
|
||||
bool advancedTooltips;
|
||||
|
||||
void init(); // 4J added
|
||||
Options(Minecraft *minecraft, File workingDirectory);
|
||||
|
||||
@@ -1631,8 +1631,10 @@ bool PlayerConnection::isDisconnected()
|
||||
|
||||
void PlayerConnection::handleDebugOptions(shared_ptr<DebugOptionsPacket> packet)
|
||||
{
|
||||
//Player player = dynamic_pointer_cast<Player>( player->shared_from_this() );
|
||||
player->SetDebugOptions(packet->m_uiVal);
|
||||
#ifdef _DEBUG
|
||||
// Player player = dynamic_pointer_cast<Player>( player->shared_from_this() );
|
||||
player->SetDebugOptions(packet->m_uiVal);
|
||||
#endif
|
||||
}
|
||||
|
||||
void PlayerConnection::handleCraftItem(shared_ptr<CraftItemPacket> packet)
|
||||
|
||||
@@ -653,11 +653,14 @@ shared_ptr<Packet> TrackedEntity::getAddEntityPacket()
|
||||
|
||||
PlayerUID xuid = INVALID_XUID;
|
||||
PlayerUID OnlineXuid = INVALID_XUID;
|
||||
// do not pass xuid/onlinexuid to clients if dedicated server
|
||||
#ifndef MINECRAFT_SERVER_BUILD
|
||||
if( player != nullptr )
|
||||
{
|
||||
xuid = player->getXuid();
|
||||
OnlineXuid = player->getOnlineXuid();
|
||||
}
|
||||
#endif
|
||||
// 4J Added yHeadRotp param to fix #102563 - TU12: Content: Gameplay: When one of the Players is idle for a few minutes his head turns 180 degrees.
|
||||
return std::make_shared<AddPlayerPacket>(player, xuid, OnlineXuid, xp, yp, zp, yRotp, xRotp, yHeadRotp);
|
||||
}
|
||||
|
||||
@@ -234,6 +234,13 @@ bool KeyboardMouseInput::IsKeyReleased(int vkCode) const
|
||||
return false;
|
||||
}
|
||||
|
||||
int KeyboardMouseInput::GetPressedKey() const
|
||||
{
|
||||
for (int i = 0; i < MAX_KEYS; ++i)
|
||||
if (m_keyPressed[i]) return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool KeyboardMouseInput::IsMouseButtonDown(int button) const
|
||||
{
|
||||
if (button >= 0 && button < MAX_MOUSE_BUTTONS)
|
||||
|
||||
@@ -56,6 +56,8 @@ public:
|
||||
bool IsKeyPressed(int vkCode) const;
|
||||
bool IsKeyReleased(int vkCode) const;
|
||||
|
||||
int GetPressedKey() const;
|
||||
|
||||
bool IsMouseButtonDown(int button) const;
|
||||
bool IsMouseButtonPressed(int button) const;
|
||||
bool IsMouseButtonReleased(int button) const;
|
||||
|
||||
@@ -67,6 +67,16 @@ SOCKET WinsockNetLayer::s_splitScreenSocket[XUSER_MAX_COUNT] = { INVALID_SOCKET,
|
||||
BYTE WinsockNetLayer::s_splitScreenSmallId[XUSER_MAX_COUNT] = { 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
HANDLE WinsockNetLayer::s_splitScreenRecvThread[XUSER_MAX_COUNT] = {nullptr, nullptr, nullptr, nullptr};
|
||||
|
||||
// async stuff
|
||||
HANDLE WinsockNetLayer::s_joinThread = nullptr;
|
||||
volatile WinsockNetLayer::eJoinState WinsockNetLayer::s_joinState = WinsockNetLayer::eJoinState_Idle;
|
||||
volatile int WinsockNetLayer::s_joinAttempt = 0;
|
||||
volatile bool WinsockNetLayer::s_joinCancel = false;
|
||||
char WinsockNetLayer::s_joinIP[256] = {};
|
||||
int WinsockNetLayer::s_joinPort = 0;
|
||||
BYTE WinsockNetLayer::s_joinAssignedSmallId = 0;
|
||||
DisconnectPacket::eDisconnectReason WinsockNetLayer::s_joinRejectReason = DisconnectPacket::eDisconnect_Quitting;
|
||||
|
||||
bool g_Win64MultiplayerHost = false;
|
||||
bool g_Win64MultiplayerJoin = false;
|
||||
int g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT;
|
||||
@@ -114,6 +124,15 @@ void WinsockNetLayer::Shutdown()
|
||||
StopAdvertising();
|
||||
StopDiscovery();
|
||||
|
||||
s_joinCancel = true;
|
||||
if (s_joinThread != nullptr)
|
||||
{
|
||||
WaitForSingleObject(s_joinThread, 5000);
|
||||
CloseHandle(s_joinThread);
|
||||
s_joinThread = nullptr;
|
||||
}
|
||||
s_joinState = eJoinState_Idle;
|
||||
|
||||
s_active = false;
|
||||
s_connected = false;
|
||||
|
||||
@@ -421,6 +440,215 @@ bool WinsockNetLayer::JoinGame(const char* ip, int port)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinsockNetLayer::BeginJoinGame(const char* ip, int port)
|
||||
{
|
||||
if (!s_initialized && !Initialize()) return false;
|
||||
|
||||
// if there isnt any cleanup it sometime caused issues. Oops
|
||||
CancelJoinGame();
|
||||
if (s_joinThread != nullptr)
|
||||
{
|
||||
WaitForSingleObject(s_joinThread, 5000);
|
||||
CloseHandle(s_joinThread);
|
||||
s_joinThread = nullptr;
|
||||
}
|
||||
|
||||
s_isHost = false;
|
||||
s_hostSmallId = 0;
|
||||
s_connected = false;
|
||||
s_active = false;
|
||||
|
||||
if (s_hostConnectionSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
if (s_clientRecvThread != nullptr)
|
||||
{
|
||||
WaitForSingleObject(s_clientRecvThread, 5000);
|
||||
CloseHandle(s_clientRecvThread);
|
||||
s_clientRecvThread = nullptr;
|
||||
}
|
||||
|
||||
strncpy_s(s_joinIP, sizeof(s_joinIP), ip, _TRUNCATE);
|
||||
s_joinPort = port;
|
||||
s_joinAttempt = 0;
|
||||
s_joinCancel = false;
|
||||
s_joinAssignedSmallId = 0;
|
||||
s_joinRejectReason = DisconnectPacket::eDisconnect_Quitting;
|
||||
s_joinState = eJoinState_Connecting;
|
||||
|
||||
s_joinThread = CreateThread(nullptr, 0, JoinThreadProc, nullptr, 0, nullptr);
|
||||
if (s_joinThread == nullptr)
|
||||
{
|
||||
s_joinState = eJoinState_Failed;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
DWORD WINAPI WinsockNetLayer::JoinThreadProc(LPVOID param)
|
||||
{
|
||||
struct addrinfo hints = {};
|
||||
struct addrinfo* result = nullptr;
|
||||
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
char portStr[16];
|
||||
sprintf_s(portStr, "%d", s_joinPort);
|
||||
|
||||
int iResult = getaddrinfo(s_joinIP, portStr, &hints, &result);
|
||||
if (iResult != 0)
|
||||
{
|
||||
app.DebugPrintf("getaddrinfo failed for %s:%d - %d\n", s_joinIP, s_joinPort, iResult);
|
||||
s_joinState = eJoinState_Failed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool connected = false;
|
||||
BYTE assignedSmallId = 0;
|
||||
SOCKET sock = INVALID_SOCKET;
|
||||
|
||||
for (int attempt = 0; attempt < JOIN_MAX_ATTEMPTS; ++attempt)
|
||||
{
|
||||
if (s_joinCancel)
|
||||
{
|
||||
freeaddrinfo(result);
|
||||
s_joinState = eJoinState_Cancelled;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s_joinAttempt = attempt + 1;
|
||||
|
||||
sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
|
||||
if (sock == INVALID_SOCKET)
|
||||
{
|
||||
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
|
||||
break;
|
||||
}
|
||||
|
||||
int noDelay = 1;
|
||||
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (const char*)&noDelay, sizeof(noDelay));
|
||||
|
||||
iResult = connect(sock, result->ai_addr, static_cast<int>(result->ai_addrlen));
|
||||
if (iResult == SOCKET_ERROR)
|
||||
{
|
||||
int err = WSAGetLastError();
|
||||
app.DebugPrintf("connect() to %s:%d failed (attempt %d/%d): %d\n", s_joinIP, s_joinPort, attempt + 1, JOIN_MAX_ATTEMPTS, err);
|
||||
closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
for (int w = 0; w < 4 && !s_joinCancel; w++)
|
||||
Sleep(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
BYTE assignBuf[1];
|
||||
int bytesRecv = recv(sock, (char*)assignBuf, 1, 0);
|
||||
if (bytesRecv != 1)
|
||||
{
|
||||
app.DebugPrintf("failed to receive small id assignment from host (attempt %d/%d)\n", attempt + 1, JOIN_MAX_ATTEMPTS);
|
||||
closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
for (int w = 0; w < 4 && !s_joinCancel; w++)
|
||||
Sleep(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assignBuf[0] == WIN64_SMALLID_REJECT)
|
||||
{
|
||||
BYTE rejectBuf[5];
|
||||
if (!RecvExact(sock, rejectBuf, 5))
|
||||
{
|
||||
app.DebugPrintf("failed to receive reject reason from host (?)\n");
|
||||
closesocket(sock);
|
||||
sock = INVALID_SOCKET;
|
||||
for (int w = 0; w < 4 && !s_joinCancel; w++)
|
||||
Sleep(50);
|
||||
continue;
|
||||
}
|
||||
int reason = ((rejectBuf[1] & 0xff) << 24) | ((rejectBuf[2] & 0xff) << 16) |
|
||||
((rejectBuf[3] & 0xff) << 8) | (rejectBuf[4] & 0xff);
|
||||
s_joinRejectReason = (DisconnectPacket::eDisconnectReason)reason;
|
||||
closesocket(sock);
|
||||
freeaddrinfo(result);
|
||||
s_joinState = eJoinState_Rejected;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assignedSmallId = assignBuf[0];
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
freeaddrinfo(result);
|
||||
|
||||
if (s_joinCancel)
|
||||
{
|
||||
if (sock != INVALID_SOCKET) closesocket(sock);
|
||||
s_joinState = eJoinState_Cancelled;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!connected)
|
||||
{
|
||||
s_joinState = eJoinState_Failed;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s_hostConnectionSocket = sock;
|
||||
s_joinAssignedSmallId = assignedSmallId;
|
||||
s_joinState = eJoinState_Success;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void WinsockNetLayer::CancelJoinGame()
|
||||
{
|
||||
if (s_joinState == eJoinState_Connecting)
|
||||
{
|
||||
s_joinCancel = true;
|
||||
}
|
||||
else if (s_joinState == eJoinState_Success)
|
||||
{
|
||||
// fix a race cond
|
||||
if (s_hostConnectionSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(s_hostConnectionSocket);
|
||||
s_hostConnectionSocket = INVALID_SOCKET;
|
||||
}
|
||||
s_joinState = eJoinState_Cancelled;
|
||||
}
|
||||
}
|
||||
|
||||
bool WinsockNetLayer::FinalizeJoin()
|
||||
{
|
||||
if (s_joinState != eJoinState_Success)
|
||||
return false;
|
||||
|
||||
s_localSmallId = s_joinAssignedSmallId;
|
||||
|
||||
strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), s_joinIP, _TRUNCATE);
|
||||
g_Win64MultiplayerPort = s_joinPort;
|
||||
|
||||
app.DebugPrintf("connected to %s:%d, assigned smallId=%d\n", s_joinIP, s_joinPort, s_localSmallId);
|
||||
|
||||
s_active = true;
|
||||
s_connected = true;
|
||||
|
||||
s_clientRecvThread = CreateThread(nullptr, 0, ClientRecvThreadProc, nullptr, 0, nullptr);
|
||||
|
||||
if (s_joinThread != nullptr)
|
||||
{
|
||||
WaitForSingleObject(s_joinThread, 2000);
|
||||
CloseHandle(s_joinThread);
|
||||
s_joinThread = nullptr;
|
||||
}
|
||||
|
||||
s_joinState = eJoinState_Idle;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void* data, int dataSize)
|
||||
{
|
||||
if (sock == INVALID_SOCKET || dataSize <= 0 || dataSize > WIN64_NET_MAX_PACKET_SIZE) return false;
|
||||
@@ -1334,4 +1562,25 @@ DWORD WINAPI WinsockNetLayer::DiscoveryThreadProc(LPVOID param)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// some lazy helper funcs
|
||||
WinsockNetLayer::eJoinState WinsockNetLayer::GetJoinState()
|
||||
{
|
||||
return s_joinState;
|
||||
}
|
||||
|
||||
int WinsockNetLayer::GetJoinAttempt()
|
||||
{
|
||||
return s_joinAttempt;
|
||||
}
|
||||
|
||||
int WinsockNetLayer::GetJoinMaxAttempts()
|
||||
{
|
||||
return JOIN_MAX_ATTEMPTS;
|
||||
}
|
||||
|
||||
DisconnectPacket::eDisconnectReason WinsockNetLayer::GetJoinRejectReason()
|
||||
{
|
||||
return s_joinRejectReason;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
class Socket;
|
||||
|
||||
#include "..\..\..\Minecraft.World\DisconnectPacket.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct Win64LANBroadcast
|
||||
{
|
||||
@@ -69,6 +71,23 @@ public:
|
||||
static bool HostGame(int port, const char* bindIp = nullptr);
|
||||
static bool JoinGame(const char* ip, int port);
|
||||
|
||||
enum eJoinState
|
||||
{
|
||||
eJoinState_Idle,
|
||||
eJoinState_Connecting,
|
||||
eJoinState_Success,
|
||||
eJoinState_Failed,
|
||||
eJoinState_Rejected,
|
||||
eJoinState_Cancelled
|
||||
};
|
||||
static bool BeginJoinGame(const char* ip, int port);
|
||||
static void CancelJoinGame();
|
||||
static eJoinState GetJoinState();
|
||||
static int GetJoinAttempt();
|
||||
static int GetJoinMaxAttempts();
|
||||
static DisconnectPacket::eDisconnectReason GetJoinRejectReason();
|
||||
static bool FinalizeJoin();
|
||||
|
||||
static bool SendToSmallId(BYTE targetSmallId, const void* data, int dataSize);
|
||||
static bool SendOnSocket(SOCKET sock, const void* data, int dataSize);
|
||||
|
||||
@@ -112,6 +131,17 @@ private:
|
||||
static DWORD WINAPI SplitScreenRecvThreadProc(LPVOID param);
|
||||
static DWORD WINAPI AdvertiseThreadProc(LPVOID param);
|
||||
static DWORD WINAPI DiscoveryThreadProc(LPVOID param);
|
||||
static DWORD WINAPI JoinThreadProc(LPVOID param);
|
||||
|
||||
static HANDLE s_joinThread;
|
||||
static volatile eJoinState s_joinState;
|
||||
static volatile int s_joinAttempt;
|
||||
static volatile bool s_joinCancel;
|
||||
static char s_joinIP[256];
|
||||
static int s_joinPort;
|
||||
static BYTE s_joinAssignedSmallId;
|
||||
static DisconnectPacket::eDisconnectReason s_joinRejectReason;
|
||||
static const int JOIN_MAX_ATTEMPTS = 4;
|
||||
|
||||
static SOCKET s_listenSocket;
|
||||
static SOCKET s_hostConnectionSocket;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
//#include "NetworkManager.h"
|
||||
#include "..\..\Minecraft.Client\Tesselator.h"
|
||||
#include "..\..\Minecraft.Client\Options.h"
|
||||
#include "..\Gui.h"
|
||||
#include "Sentient\SentientManager.h"
|
||||
#include "..\..\Minecraft.World\IntCache.h"
|
||||
#include "..\Textures.h"
|
||||
@@ -107,6 +108,7 @@ int g_iScreenHeight = 1080;
|
||||
// always matches the current window, even after a resize.
|
||||
int g_rScreenWidth = 1920;
|
||||
int g_rScreenHeight = 1080;
|
||||
static bool f3ComboUsed = false;
|
||||
|
||||
float g_iAspectRatio = static_cast<float>(g_iScreenWidth) / g_iScreenHeight;
|
||||
static bool g_bResizeReady = false;
|
||||
@@ -1774,17 +1776,37 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
||||
}
|
||||
|
||||
// F3 toggles onscreen debug info
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO))
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO)) f3ComboUsed = false;
|
||||
|
||||
// f3 combo
|
||||
if (g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_DEBUG_INFO))
|
||||
{
|
||||
if (const Minecraft* pMinecraft = Minecraft::GetInstance())
|
||||
switch (g_KBMInput.GetPressedKey())
|
||||
{
|
||||
if (pMinecraft->options)
|
||||
{
|
||||
pMinecraft->options->renderDebug = !pMinecraft->options->renderDebug;
|
||||
}
|
||||
// advanced tooltips
|
||||
case 'H':
|
||||
if (pMinecraft->options && app.GetGameStarted())
|
||||
{
|
||||
pMinecraft->options->advancedTooltips = !pMinecraft->options->advancedTooltips;
|
||||
pMinecraft->options->save();
|
||||
|
||||
const wstring msg = wstring(L"Advanced tooltips: ") + (pMinecraft->options->advancedTooltips ? L"shown" : L"hidden");
|
||||
const int primaryPad = ProfileManager.GetPrimaryPad();
|
||||
if (pMinecraft->gui) pMinecraft->gui->addMessage(msg, primaryPad);
|
||||
|
||||
f3ComboUsed = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// no combo
|
||||
if (g_KBMInput.IsKeyReleased(KeyboardMouseInput::KEY_DEBUG_INFO) && !f3ComboUsed)
|
||||
if (pMinecraft->options)
|
||||
pMinecraft->options->renderDebug = !pMinecraft->options->renderDebug;
|
||||
|
||||
|
||||
|
||||
#ifdef _DEBUG_MENUS_ENABLED
|
||||
// F6 Open debug console
|
||||
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_CONSOLE))
|
||||
|
||||
Binary file not shown.
@@ -157,7 +157,7 @@ shared_ptr<ItemInstance> AbstractContainerMenu::clicked(int slotIndex, int butto
|
||||
shared_ptr<ItemInstance> clickedEntity = nullptr;
|
||||
shared_ptr<Inventory> inventory = player->inventory;
|
||||
|
||||
if (slotIndex < 0 || slotIndex >= (int)slots.size())
|
||||
if ((slotIndex < 0 && slotIndex != SLOT_CLICKED_OUTSIDE) || slotIndex >= (int)slots.size())
|
||||
return nullptr;
|
||||
|
||||
if (clickType == CLICK_QUICK_CRAFT)
|
||||
|
||||
@@ -21,20 +21,20 @@ void ClothDyeRecipes::addRecipes(Recipes *r)
|
||||
L'#', new ItemInstance(Tile::clayHardened),
|
||||
L'X', new ItemInstance(Item::dye_powder, 1, i),L'D');
|
||||
|
||||
#if 0
|
||||
r->addShapedRecipy(new ItemInstance(Tile::stained_glass, 8, ColoredTile::getItemAuxValueForTileData(i)), //
|
||||
L"sssczczg",
|
||||
L"###",
|
||||
L"#X#",
|
||||
L"###",
|
||||
L'#', new ItemInstance(Tile::glass),
|
||||
L'X', new ItemInstance(Item::dye_powder, 1, i), L'D');
|
||||
r->addShapedRecipy(new ItemInstance(Tile::stained_glass_pane, 16, i), //
|
||||
L"ssczg",
|
||||
L"###",
|
||||
L"###",
|
||||
L'#', new ItemInstance(Tile::stained_glass, 1, i), L'D');
|
||||
#endif
|
||||
//#if 0
|
||||
// r->addShapedRecipy(new ItemInstance(Tile::stained_glass, 8, ColoredTile::getItemAuxValueForTileData(i)), //
|
||||
// L"sssczczg",
|
||||
// L"###",
|
||||
// L"#X#",
|
||||
// L"###",
|
||||
// L'#', new ItemInstance(Tile::glass),
|
||||
// L'X', new ItemInstance(Item::dye_powder, 1, i), L'D');
|
||||
// r->addShapedRecipy(new ItemInstance(Tile::stained_glass_pane, 16, i), //
|
||||
// L"ssczg",
|
||||
// L"###",
|
||||
// L"###",
|
||||
// L'#', new ItemInstance(Tile::stained_glass, 1, i), L'D');
|
||||
//#endif
|
||||
}
|
||||
|
||||
// some dye recipes
|
||||
|
||||
@@ -562,34 +562,27 @@ vector<HtmlString> *ItemInstance::getHoverText(shared_ptr<Player> player, bool a
|
||||
title.italics = true;
|
||||
}
|
||||
|
||||
// 4J: This is for showing aux values, not useful in console version
|
||||
/*
|
||||
if (advanced)
|
||||
{
|
||||
wstring suffix = L"";
|
||||
|
||||
if (title.length() > 0)
|
||||
if (title.text.length() > 0)
|
||||
{
|
||||
title += L" (";
|
||||
title.text += L" (";
|
||||
suffix = L")";
|
||||
}
|
||||
|
||||
wchar_t buf[64];
|
||||
if (isStackedByData())
|
||||
{
|
||||
title += String.format("#%04d/%d%s", id, auxValue, suffix);
|
||||
}
|
||||
swprintf_s(buf, 64, L"#%04d/%d%s", id, auxValue, suffix.c_str());
|
||||
else
|
||||
{
|
||||
title += String.format("#%04d%s", id, suffix);
|
||||
}
|
||||
swprintf_s(buf, 64, L"#%04d%s", id, suffix.c_str());
|
||||
title.text += buf;
|
||||
}
|
||||
else if (!hasCustomHoverName() && id == Item::map_Id)
|
||||
*/
|
||||
|
||||
/*if (!hasCustomHoverName() && id == Item::map_Id)
|
||||
{
|
||||
title.text += L" #" + std::to_wstring(auxValue);
|
||||
}*/
|
||||
}
|
||||
|
||||
lines->push_back(title);
|
||||
|
||||
@@ -615,7 +608,7 @@ vector<HtmlString> *ItemInstance::getHoverText(shared_ptr<Player> player, bool a
|
||||
|
||||
if (tag->contains(L"display"))
|
||||
{
|
||||
//CompoundTag *display = tag->getCompound(L"display");
|
||||
CompoundTag *display = tag->getCompound(L"display");
|
||||
|
||||
//if (display->contains(L"color"))
|
||||
//{
|
||||
@@ -631,8 +624,7 @@ vector<HtmlString> *ItemInstance::getHoverText(shared_ptr<Player> player, bool a
|
||||
// }
|
||||
//}
|
||||
|
||||
// 4J: Lore isn't in use in game
|
||||
/*if (display->contains(L"Lore"))
|
||||
if (display->contains(L"Lore"))
|
||||
{
|
||||
ListTag<StringTag> *lore = (ListTag<StringTag> *) display->getList(L"Lore");
|
||||
if (lore->size() > 0)
|
||||
@@ -643,7 +635,7 @@ vector<HtmlString> *ItemInstance::getHoverText(shared_ptr<Player> player, bool a
|
||||
lines->push_back(lore->get(i)->data);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,7 +666,7 @@ vector<HtmlString> *ItemInstance::getHoverText(shared_ptr<Player> player, bool a
|
||||
{
|
||||
if (isDamaged())
|
||||
{
|
||||
wstring damageStr = L"Durability: LOCALISE " + std::to_wstring((getMaxDamage()) - getDamageValue()) + L" / " + std::to_wstring(getMaxDamage());
|
||||
wstring damageStr = L"Durability: " + std::to_wstring((getMaxDamage()) - getDamageValue()) + L" / " + std::to_wstring(getMaxDamage());
|
||||
lines->push_back(HtmlString(damageStr));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,10 +63,10 @@ public:
|
||||
|
||||
|
||||
public:
|
||||
static const int MAX_XBOX_BOATS = 40; // Max number of boats
|
||||
static const int MAX_CONSOLE_MINECARTS = 40;
|
||||
static const int MAX_DISPENSABLE_FIREBALLS = 200;
|
||||
static const int MAX_DISPENSABLE_PROJECTILES = 300;
|
||||
static const int MAX_XBOX_BOATS = 60; // Max number of boats
|
||||
static const int MAX_CONSOLE_MINECARTS = 60;
|
||||
static const int MAX_DISPENSABLE_FIREBALLS = 300;
|
||||
static const int MAX_DISPENSABLE_PROJECTILES = 400;
|
||||
|
||||
static const int MAX_LEVEL_SIZE = 30000000;
|
||||
static const int maxMovementHeight = 512; // 4J added
|
||||
|
||||
@@ -218,10 +218,12 @@ bool PistonBaseTile::triggerEvent(Level *level, int x, int y, int z, int param1,
|
||||
if (extend && param1 == TRIGGER_CONTRACT)
|
||||
{
|
||||
level->setData(x, y, z, facing | EXTENDED_BIT, UPDATE_CLIENTS);
|
||||
ignoreUpdate(false);
|
||||
return false;
|
||||
}
|
||||
else if (!extend && param1 == TRIGGER_EXTEND)
|
||||
{
|
||||
ignoreUpdate(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -247,6 +249,7 @@ bool PistonBaseTile::triggerEvent(Level *level, int x, int y, int z, int param1,
|
||||
}
|
||||
else
|
||||
{
|
||||
ignoreUpdate(false);
|
||||
return false;
|
||||
}
|
||||
PIXEndNamedEvent();
|
||||
|
||||
@@ -299,6 +299,7 @@ Recipes::Recipes()
|
||||
pClothDyeRecipes->addRecipes(this);
|
||||
|
||||
|
||||
|
||||
addShapedRecipy(new ItemInstance(Tile::snow, 1), //
|
||||
L"sscig",
|
||||
L"##", //
|
||||
|
||||
@@ -115,6 +115,28 @@ void StructureRecipies::addRecipes(Recipes *r)
|
||||
|
||||
L'#', Tile::glass,
|
||||
L'D');
|
||||
|
||||
|
||||
|
||||
|
||||
// Stained Glass block + pane per color
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
r->addShapedRecipy(new ItemInstance(Tile::stained_glass, 8, ColoredTile::getItemAuxValueForTileData(i)),
|
||||
L"sssczczg",
|
||||
L"###",
|
||||
L"#X#",
|
||||
L"###",
|
||||
L'#', new ItemInstance(Tile::glass),
|
||||
L'X', new ItemInstance(Item::dye_powder, 1, i),
|
||||
L'D');
|
||||
r->addShapedRecipy(new ItemInstance(Tile::stained_glass_pane, 16, ColoredTile::getItemAuxValueForTileData(i)),
|
||||
L"ssczg",
|
||||
L"###",
|
||||
L"###",
|
||||
L'#', new ItemInstance(Tile::stained_glass, 1, ColoredTile::getItemAuxValueForTileData(i)),
|
||||
L'D');
|
||||
}
|
||||
|
||||
r->addShapedRecipy(new ItemInstance(Tile::netherBrick, 1), //
|
||||
L"sscig",
|
||||
|
||||
@@ -371,7 +371,12 @@ void Tile::staticCtor()
|
||||
|
||||
|
||||
Tile::ironFence = (new ThinFenceTile(101, L"iron_bars", L"iron_bars", Material::metal, true)) ->setBaseItemTypeAndMaterial(Item::eBaseItemType_fence, Item::eMaterial_iron)->setDestroyTime(5.0f)->setExplodeable(10)->setSoundType(SOUND_METAL)->setDescriptionId(IDS_TILE_IRON_FENCE)->setUseDescriptionId(IDS_DESC_IRON_FENCE);
|
||||
Tile::thinGlass = (new ThinFenceTile(102, L"glass", L"glass_pane_top", Material::glass, false)) ->setDestroyTime(0.3f)->setSoundType(SOUND_GLASS)->setDescriptionId(IDS_TILE_THIN_GLASS)->setUseDescriptionId(IDS_DESC_THIN_GLASS);
|
||||
Tile::thinGlass = (new ThinFenceTile(102, L"glass", L"glass_pane_top", Material::glass, false))
|
||||
->setBaseItemTypeAndMaterial(Item::eBaseItemType_glass, Item::eMaterial_glass)
|
||||
->setDestroyTime(0.3f)
|
||||
->setSoundType(SOUND_GLASS)
|
||||
->setDescriptionId(IDS_TILE_THIN_GLASS)
|
||||
->setUseDescriptionId(IDS_DESC_THIN_GLASS);
|
||||
Tile::melon = (new MelonTile(103)) ->setDestroyTime(1.0f)->setSoundType(SOUND_WOOD)->setIconName(L"melon")->setDescriptionId(IDS_TILE_MELON)->setUseDescriptionId(IDS_DESC_MELON_BLOCK);
|
||||
Tile::pumpkinStem = (new StemTile(104, Tile::pumpkin)) ->setDestroyTime(0.0f)->setSoundType(SOUND_WOOD)->setIconName(L"pumpkin_stem")->setDescriptionId(IDS_TILE_PUMPKIN_STEM)->sendTileData();
|
||||
Tile::melonStem = (new StemTile(105, Tile::melon)) ->setDestroyTime(0.0f)->setSoundType(SOUND_WOOD)->setIconName(L"melon_stem")->setDescriptionId(IDS_TILE_MELON_STEM)->sendTileData();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# Required:
|
||||
# COPY_SOURCE – pipe-separated list of source file paths
|
||||
# COPY_DEST – destination directory
|
||||
cmake_minimum_required(VERSION 3.24)
|
||||
|
||||
if(NOT COPY_SOURCE OR NOT COPY_DEST)
|
||||
message(FATAL_ERROR "COPY_SOURCE and COPY_DEST must be set.")
|
||||
|
||||
Reference in New Issue
Block a user