24 Commits

Author SHA1 Message Date
Alezito2008
6c842b2854 Disable flight state when riding entities (#368) 2026-03-04 13:21:21 +08:00
Mykey
c8a8f9dd6c Update crafting controls description (#359)
Clarified crafting controls in README.
2026-03-04 12:32:51 +08:00
rtm516
b1b622c303 Fix overlapping debug menus and screens (#294)
* Fix overlapping debug menus and screens

Also resolves a formatting issue with clang-format

* Update readme
2026-03-04 12:31:47 +08:00
4win
f216abca42 fix: properly offset the mouse position in containers (#327) 2026-03-04 12:30:14 +08:00
Alezito2008
d31d261ffd Prevent world input from affecting inventory (#354) 2026-03-04 12:29:29 +08:00
Zekken
f870ef2a10 Fix Texture Pack images in menu (#335) 2026-03-03 23:56:16 +00:00
Boom244
ac30f09085 #221: Fix menu glitch. (#254) 2026-03-04 05:43:06 +07:00
Slenderman
ac480f6745 Update username logic and implement latest LCEMP changes (#311)
* Update username logic and implement latest LCEMP changes

* Update old reference

* Fix tutorial world crash

* Restore deleted comment
2026-03-04 04:50:28 +07:00
Fin
30ecc80250 Add menu display check for sneak toggle in flying mode (#319)
Fixes being able to fly down while a menu is open.
2026-03-04 04:13:35 +07:00
rtm516
384b9f4445 Fix ender dragon hit not making left side red (#309) 2026-03-04 03:40:53 +07:00
TGS
31cc598b75 Remove duplicate elif from LevelRender.h (#296) 2026-03-03 20:22:31 +00:00
rtm516
9b5348113c Don't build when PR template is updated 2026-03-03 18:20:14 +00:00
rtm516
942ef7e99f Tidy up PR template 2026-03-03 18:17:33 +00:00
FancyEX
540e33d787 Separate _WINDOWS64 and _XBOX_ONE (#248)
The latter returning to the original 512 value.
2026-03-04 00:58:04 +07:00
DetectivEren
1b0e5df27e chunk optimization (#246)
makes chunks load a bit faster
2026-03-04 00:55:27 +07:00
Slenderman
515f91cad8 Fix player save data issue & multiple username implementations (#257)
* fix saving issue & multiple username implementations

* Update README.md

Updated the method for overriding in-game username from '-name' to 'username.txt'.

* remove unused include i forgot to get rid of while testing
2026-03-03 23:58:22 +07:00
slcyed
5c91c26086 shift + click for quickmove (#278)
* shift + click for quickmove

* shift click quick move in inventory
2026-03-03 23:27:23 +07:00
void_17
b44d29b2ff Ship the .pdb file in nightly builds too 2026-03-03 23:18:57 +07:00
void_17
a3095a7050 Ship updated binary alongside with the whole archive in nightly builds
Now ship both the entire .zip archive and the separate .exe binary updated on each commit.
2026-03-03 23:07:37 +07:00
Violet
42bb19d490 chore: add .clang-format based on the style 4J seemed to use (#30) (#273)
The style 4J used seems to be based on the Microsoft style (presumably the
default settings of whatever Visual Studio they used to write this). However,
the source files do not have much consistency so I highly doubt 4J cared too
much about styling, just going with whatever happened to be the default.

This style is therefore basically the Microsoft style (4-space indents,
C#/Allman style braces) with some settings set based on my observations
about the code.

Fixes: #30
2026-03-03 22:53:28 +07:00
daoge_cmd
1444581cb6 chore: remove duplicated /Ob3 flag from CMake Release optimization settings 2026-03-03 17:59:06 +08:00
daoge_cmd
a97ee4aab1 chore: sync VS Release warning-disable setting into CMake 2026-03-03 17:45:25 +08:00
daoge_cmd
2915044f95 chore: sync VS release optimization flags into CMake build 2026-03-03 17:40:21 +08:00
daoge_cmd
6d4ce5136c fix: fix executable icon when using cmake 2026-03-03 17:40:21 +08:00
23 changed files with 459 additions and 262 deletions

53
.clang-format Normal file
View File

@@ -0,0 +1,53 @@
---
BasedOnStyle: Microsoft
AccessModifierOffset: -2
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterExternBlock: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: false
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
ColumnLimit: 0
IncludeBlocks: Preserve
IndentAccessModifiers: false
IndentCaseBlocks: true
IndentCaseLabels: false
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: 4
InsertBraces: true
InsertNewlineAtEOF: true
NamespaceIndentation: None
PointerAlignment: Right
RemoveParentheses: Leave
RemoveSemicolon: false
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes: CaseSensitive
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InCStyleCasts: false
InConditionalStatements: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
TabWidth: 4
UseTab: Never

View File

@@ -1,23 +1,23 @@
# Pull Request <!--
Note: IF YOUR PR CHANGES THE GAME BEHAVIOR VISIBLY, REMEMBER TO ATTACH A GAMEPLAY FOOTAGE (or at least a screenshot) OF YOU *ACTUALLY* PLAYING THE GAME WITH YOUR CHANGES. Untested PRs are *NOT* welcome. Please don't forget to describe what did you do in each commit in your PR.
## Note: IF YOUR PR CHANGES THE GAME BEHAVIOR VISIBLY, REMEMBER TO ATTACH A GAMEPLAY FOOTAGE (or at least a screenshot) OF YOU *ACTUALLY* PLAYING THE GAME WITH YOUR CHANGES. Untested PRs are *NOT* welcome. Please don't forget to describe what did you do in each commit in your PR. -->
## Description ## Description
Briefly describe the changes this PR introduces. <!-- Briefly describe the changes this PR introduces. -->
## Changes ## Changes
### Previous Behavior ### Previous Behavior
*Describe how the code behaved before this change.* <!-- Describe how the code behaved before this change. -->
### Root Cause ### Root Cause
*Explain the core reason behind the erroneous/old behavior (e.g., bug, design flaw, missing edge case).* <!-- Explain the core reason behind the erroneous/old behavior (e.g., bug, design flaw, missing edge case). -->
### New Behavior ### New Behavior
*Describe how the code behaves after this change.* <!-- Describe how the code behaves after this change. -->
### Fix Implementation ### Fix Implementation
*Detail exactly how the issue was resolved (specific code changes, algorithms, logic flows).* <!-- Detail exactly how the issue was resolved (specific code changes, algorithms, logic flows). -->
## Related Issues ## Related Issues
- Fixes #[issue-number] - Fixes #[issue-number]

View File

@@ -8,6 +8,7 @@ on:
paths-ignore: paths-ignore:
- '.gitignore' - '.gitignore'
- '*.md' - '*.md'
- '.github/*.md'
jobs: jobs:
build: build:
@@ -35,5 +36,8 @@ jobs:
with: with:
tag_name: nightly tag_name: nightly
name: Nightly Release name: Nightly Release
body: Compiled with MSVC v14.44.35207 in Release mode with Whole Program Optimization, as well as `/O2 /Ot /Oi /Ob3 /GF`. (So far the floating point model is `/fp:strict` to avoid undefined behavior before we refactor for performance). Requires at least Windows 7 and DirectX 11 compatible GPU to run. body: Requires at least Windows 7 and DirectX 11 compatible GPU to run. Compiled with MSVC v14.44.35207 in Release mode with Whole Program Optimization, as well as `/O2 /Ot /Oi /Ob3 /GF /fp:precise`.
files: LCEWindows64.zip files: |
LCEWindows64.zip
./x64/Release/Minecraft.Client.exe
./x64/Release/Minecraft.Client.pdb

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.24) cmake_minimum_required(VERSION 3.24)
project(MinecraftConsoles LANGUAGES C CXX ASM_MASM) project(MinecraftConsoles LANGUAGES C CXX RC ASM_MASM)
if(NOT WIN32) if(NOT WIN32)
message(FATAL_ERROR "This CMake build currently supports Windows only.") message(FATAL_ERROR "This CMake build currently supports Windows only.")
@@ -12,11 +12,24 @@ endif()
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
function(configure_msvc_target target)
target_compile_options(${target} PRIVATE
$<$<AND:$<NOT:$<CONFIG:Release>>,$<COMPILE_LANGUAGE:C,CXX>>:/W3>
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/W0>
$<$<COMPILE_LANGUAGE:C,CXX>:/MP>
$<$<COMPILE_LANGUAGE:CXX>:/EHsc>
$<$<AND:$<CONFIG:Release>,$<COMPILE_LANGUAGE:C,CXX>>:/GL /O2 /Oi /GT /GF>
)
endfunction()
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/WorldSources.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/WorldSources.cmake")
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/ClientSources.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/ClientSources.cmake")
list(TRANSFORM MINECRAFT_WORLD_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/") list(TRANSFORM MINECRAFT_WORLD_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.World/")
list(TRANSFORM MINECRAFT_CLIENT_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/") list(TRANSFORM MINECRAFT_CLIENT_SOURCES PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/")
list(APPEND MINECRAFT_CLIENT_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/Minecraft.Client/Xbox/MinecraftWindows.rc"
)
add_library(MinecraftWorld STATIC ${MINECRAFT_WORLD_SOURCES}) add_library(MinecraftWorld STATIC ${MINECRAFT_WORLD_SOURCES})
target_include_directories(MinecraftWorld PRIVATE target_include_directories(MinecraftWorld PRIVATE
@@ -28,11 +41,7 @@ target_compile_definitions(MinecraftWorld PRIVATE
$<$<NOT:$<CONFIG:Debug>>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64> $<$<NOT:$<CONFIG:Debug>>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_LIB;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64>
) )
if(MSVC) if(MSVC)
target_compile_options(MinecraftWorld PRIVATE configure_msvc_target(MinecraftWorld)
$<$<COMPILE_LANGUAGE:C,CXX>:/W3>
$<$<COMPILE_LANGUAGE:C,CXX>:/MP>
$<$<COMPILE_LANGUAGE:CXX>:/EHsc>
)
endif() endif()
add_executable(MinecraftClient WIN32 ${MINECRAFT_CLIENT_SOURCES}) add_executable(MinecraftClient WIN32 ${MINECRAFT_CLIENT_SOURCES})
@@ -47,10 +56,9 @@ target_compile_definitions(MinecraftClient PRIVATE
$<$<NOT:$<CONFIG:Debug>>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64> $<$<NOT:$<CONFIG:Debug>>:_LARGE_WORLDS;_DEBUG_MENUS_ENABLED;_CRT_NON_CONFORMING_SWPRINTFS;_CRT_SECURE_NO_WARNINGS;_WINDOWS64>
) )
if(MSVC) if(MSVC)
target_compile_options(MinecraftClient PRIVATE configure_msvc_target(MinecraftClient)
$<$<COMPILE_LANGUAGE:C,CXX>:/W3> target_link_options(MinecraftClient PRIVATE
$<$<COMPILE_LANGUAGE:C,CXX>:/MP> $<$<CONFIG:Release>:/LTCG /INCREMENTAL:NO>
$<$<COMPILE_LANGUAGE:CXX>:/EHsc>
) )
endif() endif()

View File

@@ -55,6 +55,12 @@
#endif #endif
#include "DLCTexturePack.h" #include "DLCTexturePack.h"
#ifdef _WINDOWS64
#include "Xbox\Network\NetworkPlayerXbox.h"
#include "Common\Network\PlatformNetworkManagerStub.h"
#endif
#ifdef _DURANGO #ifdef _DURANGO
#include "..\Minecraft.World\DurangoStats.h" #include "..\Minecraft.World\DurangoStats.h"
#include "..\Minecraft.World\GenericStats.h" #include "..\Minecraft.World\GenericStats.h"
@@ -421,7 +427,6 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
{ {
case AddEntityPacket::MINECART: case AddEntityPacket::MINECART:
e = Minecart::createMinecart(level, x, y, z, packet->data); e = Minecart::createMinecart(level, x, y, z, packet->data);
break;
case AddEntityPacket::FISH_HOOK: case AddEntityPacket::FISH_HOOK:
{ {
// 4J Stu - Brought forward from 1.4 to be able to drop XP from fishing // 4J Stu - Brought forward from 1.4 to be able to drop XP from fishing
@@ -444,7 +449,7 @@ void ClientConnection::handleAddEntity(shared_ptr<AddEntityPacket> packet)
} }
} }
if (owner->instanceof(eTYPE_PLAYER)) if (owner != NULL && owner->instanceof(eTYPE_PLAYER))
{ {
shared_ptr<Player> player = dynamic_pointer_cast<Player>(owner); shared_ptr<Player> player = dynamic_pointer_cast<Player>(owner);
shared_ptr<FishingHook> hook = shared_ptr<FishingHook>( new FishingHook(level, x, y, z, player) ); shared_ptr<FishingHook> hook = shared_ptr<FishingHook>( new FishingHook(level, x, y, z, player) );
@@ -793,7 +798,28 @@ void ClientConnection::handleAddPlayer(shared_ptr<AddPlayerPacket> packet)
if (networkPlayer != NULL) player->m_displayName = networkPlayer->GetDisplayName(); if (networkPlayer != NULL) player->m_displayName = networkPlayer->GetDisplayName();
#else #else
// On all other platforms display name is just gamertag so don't check with the network manager // On all other platforms display name is just gamertag so don't check with the network manager
player->m_displayName = player->name; player->m_displayName = player->getName();
#endif
#ifdef _WINDOWS64
{
PlayerUID pktXuid = player->getXuid();
const PlayerUID WIN64_XUID_BASE = (PlayerUID)0xe000d45248242f2e;
if (pktXuid >= WIN64_XUID_BASE && pktXuid < WIN64_XUID_BASE + MINECRAFT_NET_MAX_PLAYERS)
{
BYTE smallId = (BYTE)(pktXuid - WIN64_XUID_BASE);
INetworkPlayer* np = g_NetworkManager.GetPlayerBySmallId(smallId);
if (np != NULL)
{
NetworkPlayerXbox* npx = (NetworkPlayerXbox*)np;
IQNetPlayer* qp = npx->GetQNetPlayer();
if (qp != NULL && qp->m_gamertag[0] == 0)
{
wcsncpy_s(qp->m_gamertag, 32, packet->name.c_str(), _TRUNCATE);
}
}
}
}
#endif #endif
// printf("\t\t\t\t%d: Add player\n",packet->id,packet->yRot); // printf("\t\t\t\t%d: Add player\n",packet->id,packet->yRot);
@@ -938,6 +964,39 @@ void ClientConnection::handleMoveEntitySmall(shared_ptr<MoveEntityPacketSmall> p
void ClientConnection::handleRemoveEntity(shared_ptr<RemoveEntitiesPacket> packet) void ClientConnection::handleRemoveEntity(shared_ptr<RemoveEntitiesPacket> packet)
{ {
#ifdef _WINDOWS64
if (!g_NetworkManager.IsHost())
{
for (int i = 0; i < packet->ids.length; i++)
{
shared_ptr<Entity> entity = getEntity(packet->ids[i]);
if (entity != NULL && entity->GetType() == eTYPE_PLAYER)
{
shared_ptr<Player> player = dynamic_pointer_cast<Player>(entity);
if (player != NULL)
{
PlayerUID xuid = player->getXuid();
INetworkPlayer* np = g_NetworkManager.GetPlayerByXuid(xuid);
if (np != NULL)
{
NetworkPlayerXbox* npx = (NetworkPlayerXbox*)np;
IQNetPlayer* qp = npx->GetQNetPlayer();
if (qp != NULL)
{
extern CPlatformNetworkManagerStub* g_pPlatformNetworkManager;
g_pPlatformNetworkManager->NotifyPlayerLeaving(qp);
qp->m_smallId = 0;
qp->m_isRemote = false;
qp->m_isHostPlayer = false;
qp->m_gamertag[0] = 0;
qp->SetCustomDataValue(0);
}
}
}
}
}
}
#endif
for (int i = 0; i < packet->ids.length; i++) for (int i = 0; i < packet->ids.length; i++)
{ {
level->removeEntity(packet->ids[i]); level->removeEntity(packet->ids[i]);

View File

@@ -829,6 +829,7 @@ enum EControllerActions
ACTION_MENU_OTHER_STICK_LEFT, ACTION_MENU_OTHER_STICK_LEFT,
ACTION_MENU_OTHER_STICK_RIGHT, ACTION_MENU_OTHER_STICK_RIGHT,
ACTION_MENU_PAUSEMENU, ACTION_MENU_PAUSEMENU,
ACTION_MENU_QUICK_MOVE,
#ifdef _DURANGO #ifdef _DURANGO
ACTION_MENU_GTC_PAUSE, ACTION_MENU_GTC_PAUSE,

View File

@@ -1978,7 +1978,7 @@ bool CGameNetworkManager::AllowedToPlayMultiplayer(int playerIdx)
return ProfileManager.AllowedToPlayMultiplayer(playerIdx); return ProfileManager.AllowedToPlayMultiplayer(playerIdx);
} }
char *CGameNetworkManager::GetOnlineName(int playerIdx) const char *CGameNetworkManager::GetOnlineName(int playerIdx)
{ {
return ProfileManager.GetGamertag(playerIdx); return ProfileManager.GetGamertag(playerIdx);
} }

View File

@@ -196,7 +196,7 @@ private:
int GetLockedProfile(); int GetLockedProfile();
bool IsSignedInLive(int playerIdx); bool IsSignedInLive(int playerIdx);
bool AllowedToPlayMultiplayer(int playerIdx); bool AllowedToPlayMultiplayer(int playerIdx);
char *GetOnlineName(int playerIdx); const char *GetOnlineName(int playerIdx);
C4JThread::Event* m_hServerStoppedEvent; C4JThread::Event* m_hServerStoppedEvent;
C4JThread::Event* m_hServerReadyEvent; C4JThread::Event* m_hServerReadyEvent;

View File

@@ -1304,42 +1304,60 @@ bool IUIScene_AbstractContainerMenu::handleKeyDown(int iPad, int iAction, bool b
#endif #endif
int buttonNum=0; // 0 = LeftMouse, 1 = RightMouse int buttonNum=0; // 0 = LeftMouse, 1 = RightMouse
BOOL quickKeyHeld=FALSE; // Represents shift key on PC BOOL quickKeyHeld=false; // Represents shift key on PC
BOOL quickKeyDown = false; // Represents shift key on PC
BOOL validKeyPress = FALSE; BOOL validKeyPress = false;
bool itemEditorKeyPress = false; bool itemEditorKeyPress = false;
// Ignore input from other players // Ignore input from other players
//if(pMinecraft->player->GetXboxPad()!=pInputData->UserIndex) return S_OK; //if(pMinecraft->player->GetXboxPad()!=pInputData->UserIndex) return S_OK;
switch(iAction) switch(iAction)
{ {
#ifdef _DEBUG_MENUS_ENABLED #ifdef _DEBUG_MENUS_ENABLED
case ACTION_MENU_OTHER_STICK_PRESS: case ACTION_MENU_OTHER_STICK_PRESS:
itemEditorKeyPress = TRUE; itemEditorKeyPress = TRUE;
break; break;
#endif #endif
case ACTION_MENU_A: case ACTION_MENU_A:
#ifdef __ORBIS__ #ifdef __ORBIS__
case ACTION_MENU_TOUCHPAD_PRESS: case ACTION_MENU_TOUCHPAD_PRESS:
#endif #endif
if(!bRepeat) if (!bRepeat)
{ {
validKeyPress = TRUE; validKeyPress = TRUE;
// Standard left click // Standard left click
buttonNum = 0; buttonNum = 0;
quickKeyHeld = FALSE; if (KMInput.IsKeyDown(VK_SHIFT))
if( IsSectionSlotList( m_eCurrSection ) )
{ {
int currentIndex = getCurrentIndex( m_eCurrSection ) - getSectionStartOffset(m_eCurrSection); {
validKeyPress = TRUE;
bool bSlotHasItem = !isSlotEmpty(m_eCurrSection, currentIndex); // Shift and left click
if ( bSlotHasItem ) buttonNum = 0;
ui.PlayUISFX(eSFX_Press); quickKeyHeld = TRUE;
if (IsSectionSlotList(m_eCurrSection))
{
int currentIndex = getCurrentIndex(m_eCurrSection) - getSectionStartOffset(m_eCurrSection);
bool bSlotHasItem = !isSlotEmpty(m_eCurrSection, currentIndex);
if (bSlotHasItem)
ui.PlayUISFX(eSFX_Press);
}
}
}
else {
if (IsSectionSlotList(m_eCurrSection))
{
int currentIndex = getCurrentIndex(m_eCurrSection) - getSectionStartOffset(m_eCurrSection);
bool bSlotHasItem = !isSlotEmpty(m_eCurrSection, currentIndex);
if (bSlotHasItem)
ui.PlayUISFX(eSFX_Press);
}
//
} }
//
} }
break; break;
case ACTION_MENU_X: case ACTION_MENU_X:
@@ -1361,6 +1379,7 @@ bool IUIScene_AbstractContainerMenu::handleKeyDown(int iPad, int iAction, bool b
} }
} }
break; break;
case ACTION_MENU_Y: case ACTION_MENU_Y:
if(!bRepeat) if(!bRepeat)
{ {

View File

@@ -1012,6 +1012,7 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
case ACTION_MENU_PAUSEMENU: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break; case ACTION_MENU_PAUSEMENU: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
case ACTION_MENU_LEFT_SCROLL: kbDown = KMInput.IsKeyDown('Q'); kbPressed = KMInput.IsKeyPressed('Q'); kbReleased = KMInput.IsKeyReleased('Q'); break; case ACTION_MENU_LEFT_SCROLL: kbDown = KMInput.IsKeyDown('Q'); kbPressed = KMInput.IsKeyPressed('Q'); kbReleased = KMInput.IsKeyReleased('Q'); break;
case ACTION_MENU_RIGHT_SCROLL: kbDown = KMInput.IsKeyDown('E'); kbPressed = KMInput.IsKeyPressed('E'); kbReleased = KMInput.IsKeyReleased('E'); break; case ACTION_MENU_RIGHT_SCROLL: kbDown = KMInput.IsKeyDown('E'); kbPressed = KMInput.IsKeyPressed('E'); kbReleased = KMInput.IsKeyReleased('E'); break;
case ACTION_MENU_QUICK_MOVE: kbDown = KMInput.IsKeyDown(VK_SHIFT); kbPressed = KMInput.IsKeyPressed(VK_SHIFT); kbReleased = KMInput.IsKeyReleased(VK_SHIFT); break;
} }
pressed = pressed || kbPressed; pressed = pressed || kbPressed;
released = released || kbReleased; released = released || kbReleased;
@@ -1444,7 +1445,7 @@ GDrawTexture * RADLINK UIController::TextureSubstitutionCreateCallback ( void *
// 4J Stu - All our flash controls that allow replacing textures use a special 64x64 symbol // 4J Stu - All our flash controls that allow replacing textures use a special 64x64 symbol
// Force this size here so that our images don't get scaled wildly // Force this size here so that our images don't get scaled wildly
#if (defined __ORBIS__ || defined _DURANGO ) #if (defined __ORBIS__ || defined _DURANGO || defined _WINDOWS64 )
*width = 96; *width = 96;
*height = 96; *height = 96;
#else #else

View File

@@ -33,6 +33,11 @@ UIScene_AbstractContainerMenu::UIScene_AbstractContainerMenu(int iPad, UILayer *
m_bHasMousePosition = false; m_bHasMousePosition = false;
m_lastMouseX = 0; m_lastMouseX = 0;
m_lastMouseY = 0; m_lastMouseY = 0;
for (int btn = 0; btn < 3; btn++)
{
KMInput.ConsumeMousePress(btn);
}
#endif #endif
} }
@@ -209,8 +214,8 @@ void UIScene_AbstractContainerMenu::tick()
scrollDelta = KMInput.ConsumeScrollDelta(); scrollDelta = KMInput.ConsumeScrollDelta();
// Convert mouse position to movie coordinates using the movie/client ratio // Convert mouse position to movie coordinates using the movie/client ratio
float mx = (float)mouseX * ((float)m_movieWidth / (float)clientWidth); float mx = (float)mouseX * ((float)m_movieWidth / (float)clientWidth) - (float)m_controlMainPanel.getXPos();
float my = (float)mouseY * ((float)m_movieHeight / (float)clientHeight); float my = (float)mouseY * ((float)m_movieHeight / (float)clientHeight) - (float)m_controlMainPanel.getYPos();
rawMouseMovieX = mx; rawMouseMovieX = mx;
rawMouseMovieY = my; rawMouseMovieY = my;
@@ -301,8 +306,13 @@ void UIScene_AbstractContainerMenu::tick()
// Scale mouse client coords to the Iggy display space (which was set to getRenderDimensions()) // Scale mouse client coords to the Iggy display space (which was set to getRenderDimensions())
RECT clientRect; RECT clientRect;
GetClientRect(KMInput.GetHWnd(), &clientRect); GetClientRect(KMInput.GetHWnd(), &clientRect);
x = (S32)((float)KMInput.GetMouseX() * ((float)width / (float)clientRect.right)); float mouseMovieX = (float)KMInput.GetMouseX() * ((float)m_movieWidth / (float)clientRect.right);
y = (S32)((float)KMInput.GetMouseY() * ((float)height / (float)clientRect.bottom)); float mouseMovieY = (float)KMInput.GetMouseY() * ((float)m_movieHeight / (float)clientRect.bottom);
float mouseLocalX = mouseMovieX - (float)m_controlMainPanel.getXPos();
float mouseLocalY = mouseMovieY - (float)m_controlMainPanel.getYPos();
x = (S32)(mouseLocalX * ((float)width / m_movieWidth));
y = (S32)(mouseLocalY * ((float)height / m_movieHeight));
} }
else else
{ {

View File

@@ -77,12 +77,7 @@ void EnderDragonRenderer::renderModel(shared_ptr<LivingEntity> _mob, float wp, f
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1, 0, 0, 0.5f); glColor4f(1, 0, 0, 0.5f);
#ifdef __PSVITA__
// AP - not sure that the usecompiled flag is supposed to be false. This makes it really slow on vita. Making it true still seems to look the same
model->render(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale, true); model->render(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale, true);
#else
model->render(mob, wp, ws, bob, headRotMinusBodyRot, headRotx, scale, false);
#endif
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glDepthFunc(GL_LEQUAL); glDepthFunc(GL_LEQUAL);

View File

@@ -199,11 +199,10 @@ DWORD IQNetPlayer::GetSendQueueSize(IQNetPlayer * player, DWORD dwFlags) { retur
DWORD IQNetPlayer::GetCurrentRtt() { return 0; } DWORD IQNetPlayer::GetCurrentRtt() { return 0; }
bool IQNetPlayer::IsHost() { return m_isHostPlayer; } bool IQNetPlayer::IsHost() { return m_isHostPlayer; }
bool IQNetPlayer::IsGuest() { return false; } bool IQNetPlayer::IsGuest() { return false; }
bool IQNetPlayer::IsLocal() { return true; } bool IQNetPlayer::IsLocal() { return !m_isRemote; }
PlayerUID IQNetPlayer::GetXuid() { return (PlayerUID)(0xe000d45248242f2e + m_smallId); } // todo: restore to INVALID_XUID once saves support this PlayerUID IQNetPlayer::GetXuid() { return (PlayerUID)(0xe000d45248242f2e + m_smallId); } // todo: restore to INVALID_XUID once saves support this
extern wstring g_playerName; LPCWSTR IQNetPlayer::GetGamertag() { return m_gamertag; }
LPCWSTR IQNetPlayer::GetGamertag() { return g_playerName.empty() ? L"Windows" : g_playerName.c_str(); } int IQNetPlayer::GetSessionIndex() { return m_smallId; }
int IQNetPlayer::GetSessionIndex() { return 0; }
bool IQNetPlayer::IsTalking() { return false; } bool IQNetPlayer::IsTalking() { return false; }
bool IQNetPlayer::IsMutedByLocalUser(DWORD dwUserIndex) { return false; } bool IQNetPlayer::IsMutedByLocalUser(DWORD dwUserIndex) { return false; }
bool IQNetPlayer::HasVoice() { return false; } bool IQNetPlayer::HasVoice() { return false; }
@@ -232,13 +231,17 @@ void Win64_SetupRemoteQNetPlayer(IQNetPlayer * player, BYTE smallId, bool isHost
IQNet::s_playerCount = smallId + 1; IQNet::s_playerCount = smallId + 1;
} }
static bool Win64_IsActivePlayer(IQNetPlayer* p, DWORD index);
HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex) { return S_OK; } HRESULT IQNet::AddLocalPlayerByUserIndex(DWORD dwUserIndex) { return S_OK; }
IQNetPlayer* IQNet::GetHostPlayer() { return &m_player[0]; } IQNetPlayer* IQNet::GetHostPlayer() { return &m_player[0]; }
IQNetPlayer* IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex) IQNetPlayer* IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
{ {
if (s_isHosting) if (s_isHosting)
{ {
if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS && !m_player[dwUserIndex].m_isRemote) if (dwUserIndex < MINECRAFT_NET_MAX_PLAYERS &&
!m_player[dwUserIndex].m_isRemote &&
Win64_IsActivePlayer(&m_player[dwUserIndex], dwUserIndex))
return &m_player[dwUserIndex]; return &m_player[dwUserIndex];
return NULL; return NULL;
} }
@@ -246,7 +249,7 @@ IQNetPlayer* IQNet::GetLocalPlayerByUserIndex(DWORD dwUserIndex)
return NULL; return NULL;
for (DWORD i = 0; i < s_playerCount; i++) for (DWORD i = 0; i < s_playerCount; i++)
{ {
if (!m_player[i].m_isRemote) if (!m_player[i].m_isRemote && Win64_IsActivePlayer(&m_player[i], i))
return &m_player[i]; return &m_player[i];
} }
return NULL; return NULL;
@@ -299,15 +302,28 @@ QNET_STATE IQNet::GetState() { return _iQNetStubState; }
bool IQNet::IsHost() { return s_isHosting; } bool IQNet::IsHost() { return s_isHosting; }
HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO * pInviteInfo) { return S_OK; } HRESULT IQNet::JoinGameFromInviteInfo(DWORD dwUserIndex, DWORD dwUserMask, const INVITE_INFO * pInviteInfo) { return S_OK; }
void IQNet::HostGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = true; } void IQNet::HostGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = true; }
void IQNet::ClientJoinGame() { _iQNetStubState = QNET_STATE_SESSION_STARTING; s_isHosting = false; } void IQNet::ClientJoinGame()
{
_iQNetStubState = QNET_STATE_SESSION_STARTING;
s_isHosting = false;
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
{
m_player[i].m_smallId = (BYTE)i;
m_player[i].m_isRemote = true;
m_player[i].m_isHostPlayer = false;
m_player[i].m_gamertag[0] = 0;
m_player[i].SetCustomDataValue(0);
}
}
void IQNet::EndGame() void IQNet::EndGame()
{ {
_iQNetStubState = QNET_STATE_IDLE; _iQNetStubState = QNET_STATE_IDLE;
s_isHosting = false; s_isHosting = false;
s_playerCount = 1; s_playerCount = 1;
for (int i = 1; i < MINECRAFT_NET_MAX_PLAYERS; i++) for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
{ {
m_player[i].m_smallId = 0; m_player[i].m_smallId = (BYTE)i;
m_player[i].m_isRemote = false; m_player[i].m_isRemote = false;
m_player[i].m_isHostPlayer = false; m_player[i].m_isHostPlayer = false;
m_player[i].m_gamertag[0] = 0; m_player[i].m_gamertag[0] = 0;
@@ -587,7 +603,6 @@ void C_4JProfile::SetPrimaryPad(int iPad) {}
#ifdef _DURANGO #ifdef _DURANGO
char fakeGamerTag[32] = "PlayerName"; char fakeGamerTag[32] = "PlayerName";
void SetFakeGamertag(char* name) { strcpy_s(fakeGamerTag, name); } void SetFakeGamertag(char* name) { strcpy_s(fakeGamerTag, name); }
char* C_4JProfile::GetGamertag(int iPad) { return fakeGamerTag; }
#else #else
char* C_4JProfile::GetGamertag(int iPad) { extern char g_Win64Username[17]; return g_Win64Username; } char* C_4JProfile::GetGamertag(int iPad) { extern char g_Win64Username[17]; return g_Win64Username; }
wstring C_4JProfile::GetDisplayName(int iPad) { extern wchar_t g_Win64UsernameW[17]; return g_Win64UsernameW; } wstring C_4JProfile::GetDisplayName(int iPad) { extern wchar_t g_Win64UsernameW[17]; return g_Win64UsernameW; }

View File

@@ -1964,8 +1964,8 @@ bool LevelRenderer::updateDirtyChunks()
{ {
if( (!onlyRebuild) || if( (!onlyRebuild) ||
globalChunkFlags[ pClipChunk->globalIdx ] & CHUNK_FLAG_COMPILED || globalChunkFlags[ pClipChunk->globalIdx ] & CHUNK_FLAG_COMPILED ||
( distSq < 20 * 20 ) ) // Always rebuild really near things or else building (say) at tower up into empty blocks when we are low on memory will not create render data ( distSq < 96 * 96 ) ) // Always rebuild really near things or else building (say) at tower up into empty blocks when we are low on memory will not create render data
{ { // distSq adjusted from 20 * 20 to 96 * 96 - updated by detectiveren
considered++; considered++;
// Is this chunk nearer than our nearest? // Is this chunk nearer than our nearest?
#ifdef _LARGE_WORLDS #ifdef _LARGE_WORLDS

View File

@@ -52,14 +52,16 @@ public:
static const int CHUNK_SIZE = 16; static const int CHUNK_SIZE = 16;
#endif #endif
static const int CHUNK_Y_COUNT = Level::maxBuildHeight / CHUNK_SIZE; static const int CHUNK_Y_COUNT = Level::maxBuildHeight / CHUNK_SIZE;
#if (defined _XBOX_ONE || defined _WINDOWS64) #if defined _WINDOWS64
static const int MAX_COMMANDBUFFER_ALLOCATIONS = 2047 * 1024 * 1024; // Changed to 2047. 4J had set to 512. static const int MAX_COMMANDBUFFER_ALLOCATIONS = 2047 * 1024 * 1024; // Changed to 2047. 4J had set to 512.
#elif defined _XBOX_ONE
static const int MAX_COMMANDBUFFER_ALLOCATIONS = 512 * 1024 * 1024; // 4J - added
#elif defined __ORBIS__ #elif defined __ORBIS__
static const int MAX_COMMANDBUFFER_ALLOCATIONS = 448 * 1024 * 1024; // 4J - added - hard limit is 512 so giving a lot of headroom here for fragmentation (have seen 16MB lost to fragmentation in multiplayer crash dump before) static const int MAX_COMMANDBUFFER_ALLOCATIONS = 448 * 1024 * 1024; // 4J - added - hard limit is 512 so giving a lot of headroom here for fragmentation (have seen 16MB lost to fragmentation in multiplayer crash dump before)
#elif defined __PS3__ #elif defined __PS3__
static const int MAX_COMMANDBUFFER_ALLOCATIONS = 110 * 1024 * 1024; // 4J - added static const int MAX_COMMANDBUFFER_ALLOCATIONS = 110 * 1024 * 1024; // 4J - added
#else #else
static const int MAX_COMMANDBUFFER_ALLOCATIONS = 55 * 1024 * 1024; // 4J - added static const int MAX_COMMANDBUFFER_ALLOCATIONS = 55 * 1024 * 1024; // 4J - added
#endif #endif
public: public:
LevelRenderer(Minecraft *mc, Textures *textures); LevelRenderer(Minecraft *mc, Textures *textures);
@@ -270,10 +272,10 @@ public:
bool dirtyChunkPresent; bool dirtyChunkPresent;
__int64 lastDirtyChunkFound; __int64 lastDirtyChunkFound;
static const int FORCE_DIRTY_CHUNK_CHECK_PERIOD_MS = 250; static const int FORCE_DIRTY_CHUNK_CHECK_PERIOD_MS = 125; // decreased from 250 to 125 - updated by detectiveren
#ifdef _LARGE_WORLDS #ifdef _LARGE_WORLDS
static const int MAX_CONCURRENT_CHUNK_REBUILDS = 4; static const int MAX_CONCURRENT_CHUNK_REBUILDS = 8; // increased from 4 to 8 - updated by detectiveren
static const int MAX_CHUNK_REBUILD_THREADS = MAX_CONCURRENT_CHUNK_REBUILDS - 1; static const int MAX_CHUNK_REBUILD_THREADS = MAX_CONCURRENT_CHUNK_REBUILDS - 1;
static Chunk permaChunk[MAX_CONCURRENT_CHUNK_REBUILDS]; static Chunk permaChunk[MAX_CONCURRENT_CHUNK_REBUILDS];
static C4JThread *rebuildThreads[MAX_CHUNK_REBUILD_THREADS]; static C4JThread *rebuildThreads[MAX_CHUNK_REBUILD_THREADS];

View File

@@ -1456,7 +1456,7 @@ void Minecraft::run_middle()
if (KMInput.ConsumeKeyPress('C')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_CRAFTING; if (KMInput.ConsumeKeyPress('C')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_CRAFTING;
if (KMInput.ConsumeKeyPress(VK_F5)) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON; if (KMInput.ConsumeKeyPress(VK_F5)) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON;
// In flying mode, Shift held = sneak/descend // In flying mode, Shift held = sneak/descend
if (localplayers[i]->abilities.flying && KMInput.IsKeyDown(VK_SHIFT)) if (localplayers[i]->abilities.flying && KMInput.IsKeyDown(VK_SHIFT) && !ui.GetMenuDisplayed(i))
localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE; localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE;
} }
#endif #endif
@@ -3618,8 +3618,6 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_RENDER_DEBUG)) ) if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_RENDER_DEBUG)) )
{ {
#ifndef _CONTENT_PACKAGE #ifndef _CONTENT_PACKAGE
options->renderDebug = !options->renderDebug;
#ifdef _XBOX #ifdef _XBOX
app.EnableDebugOverlay(options->renderDebug,iPad); app.EnableDebugOverlay(options->renderDebug,iPad);
#else #else
@@ -3629,13 +3627,11 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
#endif #endif
} }
if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_SPAWN_CREEPER)) && app.GetMobsDontAttackEnabled()) if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_SPAWN_CREEPER)))
{ {
//shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(Creeper::_class->newInstance( level )); #ifndef _CONTENT_PACKAGE
//shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(Wolf::_class->newInstance( level )); options->renderDebug = !options->renderDebug;
shared_ptr<Mob> mob = dynamic_pointer_cast<Mob>(shared_ptr<Spider>(new Spider( level ))); #endif
mob->moveTo(player->x+1, player->y, player->z+1, level->random->nextFloat() * 360, 0);
level->addEntity(mob);
} }
} }

View File

@@ -103,6 +103,7 @@ void KeyboardMouseInput::OnRawMouseInput(LPARAM lParam)
void KeyboardMouseInput::OnMouseButton(int button, bool down) void KeyboardMouseInput::OnMouseButton(int button, bool down)
{ {
if (ui.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad())) { return; }
if (button >= 0 && button < 3) if (button >= 0 && button < 3)
{ {
if (down && !m_mouseButtons[button]) m_mousePressedAccum[button] = true; if (down && !m_mouseButtons[button]) m_mousePressedAccum[button] = true;

View File

@@ -1,3 +1,6 @@
// Code implemented by LCEMP, credit if used on other repos
// https://github.com/LCEMP/LCEMP
#include "stdafx.h" #include "stdafx.h"
#ifdef _WINDOWS64 #ifdef _WINDOWS64
@@ -151,7 +154,7 @@ bool WinsockNetLayer::HostGame(int port)
LeaveCriticalSection(&s_freeSmallIdLock); LeaveCriticalSection(&s_freeSmallIdLock);
struct addrinfo hints = {}; struct addrinfo hints = {};
struct addrinfo *result = NULL; struct addrinfo* result = NULL;
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
@@ -177,7 +180,7 @@ bool WinsockNetLayer::HostGame(int port)
} }
int opt = 1; int opt = 1;
setsockopt(s_listenSocket, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt)); setsockopt(s_listenSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt));
iResult = ::bind(s_listenSocket, result->ai_addr, (int)result->ai_addrlen); iResult = ::bind(s_listenSocket, result->ai_addr, (int)result->ai_addrlen);
freeaddrinfo(result); freeaddrinfo(result);
@@ -207,15 +210,23 @@ bool WinsockNetLayer::HostGame(int port)
return true; return true;
} }
bool WinsockNetLayer::JoinGame(const char *ip, int port) bool WinsockNetLayer::JoinGame(const char* ip, int port)
{ {
if (!s_initialized && !Initialize()) return false; if (!s_initialized && !Initialize()) return false;
s_isHost = false; s_isHost = false;
s_hostSmallId = 0; s_hostSmallId = 0;
s_connected = false;
s_active = false;
if (s_hostConnectionSocket != INVALID_SOCKET)
{
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
}
struct addrinfo hints = {}; struct addrinfo hints = {};
struct addrinfo *result = NULL; struct addrinfo* result = NULL;
hints.ai_family = AF_INET; hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
@@ -231,37 +242,55 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
return false; return false;
} }
s_hostConnectionSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); bool connected = false;
if (s_hostConnectionSocket == INVALID_SOCKET) BYTE assignedSmallId = 0;
const int maxAttempts = 12;
for (int attempt = 0; attempt < maxAttempts; ++attempt)
{ {
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError()); s_hostConnectionSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
freeaddrinfo(result); if (s_hostConnectionSocket == INVALID_SOCKET)
return false; {
app.DebugPrintf("socket() failed: %d\n", WSAGetLastError());
break;
}
int noDelay = 1;
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&noDelay, sizeof(noDelay));
iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen);
if (iResult == SOCKET_ERROR)
{
int err = WSAGetLastError();
app.DebugPrintf("connect() to %s:%d failed (attempt %d/%d): %d\n", ip, port, attempt + 1, maxAttempts, err);
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
Sleep(200);
continue;
}
BYTE assignBuf[1];
int bytesRecv = recv(s_hostConnectionSocket, (char*)assignBuf, 1, 0);
if (bytesRecv != 1)
{
app.DebugPrintf("Failed to receive small ID assignment from host (attempt %d/%d)\n", attempt + 1, maxAttempts);
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
Sleep(200);
continue;
}
assignedSmallId = assignBuf[0];
connected = true;
break;
} }
int noDelay = 1;
setsockopt(s_hostConnectionSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay));
iResult = connect(s_hostConnectionSocket, result->ai_addr, (int)result->ai_addrlen);
freeaddrinfo(result); freeaddrinfo(result);
if (iResult == SOCKET_ERROR)
{
app.DebugPrintf("connect() to %s:%d failed: %d\n", ip, port, WSAGetLastError());
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
return false;
}
BYTE assignBuf[1]; if (!connected)
int bytesRecv = recv(s_hostConnectionSocket, (char *)assignBuf, 1, 0);
if (bytesRecv != 1)
{ {
app.DebugPrintf("Failed to receive small ID assignment from host\n");
closesocket(s_hostConnectionSocket);
s_hostConnectionSocket = INVALID_SOCKET;
return false; return false;
} }
s_localSmallId = assignBuf[0]; s_localSmallId = assignedSmallId;
app.DebugPrintf("Win64 LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId); app.DebugPrintf("Win64 LAN: Connected to %s:%d, assigned smallId=%d\n", ip, port, s_localSmallId);
@@ -273,7 +302,7 @@ bool WinsockNetLayer::JoinGame(const char *ip, int port)
return true; return true;
} }
bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void *data, int dataSize) bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void* data, int dataSize)
{ {
if (sock == INVALID_SOCKET || dataSize <= 0) return false; if (sock == INVALID_SOCKET || dataSize <= 0) return false;
@@ -289,7 +318,7 @@ bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void *data, int dataSize)
int toSend = 4; int toSend = 4;
while (totalSent < toSend) while (totalSent < toSend)
{ {
int sent = send(sock, (const char *)header + totalSent, toSend - totalSent, 0); int sent = send(sock, (const char*)header + totalSent, toSend - totalSent, 0);
if (sent == SOCKET_ERROR || sent == 0) if (sent == SOCKET_ERROR || sent == 0)
{ {
LeaveCriticalSection(&s_sendLock); LeaveCriticalSection(&s_sendLock);
@@ -301,7 +330,7 @@ bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void *data, int dataSize)
totalSent = 0; totalSent = 0;
while (totalSent < dataSize) while (totalSent < dataSize)
{ {
int sent = send(sock, (const char *)data + totalSent, dataSize - totalSent, 0); int sent = send(sock, (const char*)data + totalSent, dataSize - totalSent, 0);
if (sent == SOCKET_ERROR || sent == 0) if (sent == SOCKET_ERROR || sent == 0)
{ {
LeaveCriticalSection(&s_sendLock); LeaveCriticalSection(&s_sendLock);
@@ -314,7 +343,7 @@ bool WinsockNetLayer::SendOnSocket(SOCKET sock, const void *data, int dataSize)
return true; return true;
} }
bool WinsockNetLayer::SendToSmallId(BYTE targetSmallId, const void *data, int dataSize) bool WinsockNetLayer::SendToSmallId(BYTE targetSmallId, const void* data, int dataSize)
{ {
if (!s_active) return false; if (!s_active) return false;
@@ -346,34 +375,34 @@ SOCKET WinsockNetLayer::GetSocketForSmallId(BYTE smallId)
return INVALID_SOCKET; return INVALID_SOCKET;
} }
static bool RecvExact(SOCKET sock, BYTE *buf, int len) static bool RecvExact(SOCKET sock, BYTE* buf, int len)
{ {
int totalRecv = 0; int totalRecv = 0;
while (totalRecv < len) while (totalRecv < len)
{ {
int r = recv(sock, (char *)buf + totalRecv, len - totalRecv, 0); int r = recv(sock, (char*)buf + totalRecv, len - totalRecv, 0);
if (r <= 0) return false; if (r <= 0) return false;
totalRecv += r; totalRecv += r;
} }
return true; return true;
} }
void WinsockNetLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsigned char *data, unsigned int dataSize) void WinsockNetLayer::HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsigned char* data, unsigned int dataSize)
{ {
INetworkPlayer *pPlayerFrom = g_NetworkManager.GetPlayerBySmallId(fromSmallId); INetworkPlayer* pPlayerFrom = g_NetworkManager.GetPlayerBySmallId(fromSmallId);
INetworkPlayer *pPlayerTo = g_NetworkManager.GetPlayerBySmallId(toSmallId); INetworkPlayer* pPlayerTo = g_NetworkManager.GetPlayerBySmallId(toSmallId);
if (pPlayerFrom == NULL || pPlayerTo == NULL) return; if (pPlayerFrom == NULL || pPlayerTo == NULL) return;
if (s_isHost) if (s_isHost)
{ {
::Socket *pSocket = pPlayerFrom->GetSocket(); ::Socket* pSocket = pPlayerFrom->GetSocket();
if (pSocket != NULL) if (pSocket != NULL)
pSocket->pushDataToQueue(data, dataSize, false); pSocket->pushDataToQueue(data, dataSize, false);
} }
else else
{ {
::Socket *pSocket = pPlayerTo->GetSocket(); ::Socket* pSocket = pPlayerTo->GetSocket();
if (pSocket != NULL) if (pSocket != NULL)
pSocket->pushDataToQueue(data, dataSize, true); pSocket->pushDataToQueue(data, dataSize, true);
} }
@@ -392,7 +421,7 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
} }
int noDelay = 1; int noDelay = 1;
setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&noDelay, sizeof(noDelay)); setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (const char*)&noDelay, sizeof(noDelay));
extern QNET_STATE _iQNetStubState; extern QNET_STATE _iQNetStubState;
if (_iQNetStubState != QNET_STATE_GAME_PLAY) if (_iQNetStubState != QNET_STATE_GAME_PLAY)
@@ -423,7 +452,7 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
LeaveCriticalSection(&s_freeSmallIdLock); LeaveCriticalSection(&s_freeSmallIdLock);
BYTE assignBuf[1] = { assignedSmallId }; BYTE assignBuf[1] = { assignedSmallId };
int sent = send(clientSocket, (const char *)assignBuf, 1, 0); int sent = send(clientSocket, (const char*)assignBuf, 1, 0);
if (sent != 1) if (sent != 1)
{ {
app.DebugPrintf("Failed to send small ID to client\n"); app.DebugPrintf("Failed to send small ID to client\n");
@@ -444,15 +473,15 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
app.DebugPrintf("Win64 LAN: Client connected, assigned smallId=%d\n", assignedSmallId); app.DebugPrintf("Win64 LAN: Client connected, assigned smallId=%d\n", assignedSmallId);
IQNetPlayer *qnetPlayer = &IQNet::m_player[assignedSmallId]; IQNetPlayer* qnetPlayer = &IQNet::m_player[assignedSmallId];
extern void Win64_SetupRemoteQNetPlayer(IQNetPlayer *player, BYTE smallId, bool isHost, bool isLocal); extern void Win64_SetupRemoteQNetPlayer(IQNetPlayer * player, BYTE smallId, bool isHost, bool isLocal);
Win64_SetupRemoteQNetPlayer(qnetPlayer, assignedSmallId, false, false); Win64_SetupRemoteQNetPlayer(qnetPlayer, assignedSmallId, false, false);
extern CPlatformNetworkManagerStub *g_pPlatformNetworkManager; extern CPlatformNetworkManagerStub* g_pPlatformNetworkManager;
g_pPlatformNetworkManager->NotifyPlayerJoined(qnetPlayer); g_pPlatformNetworkManager->NotifyPlayerJoined(qnetPlayer);
DWORD *threadParam = new DWORD; DWORD* threadParam = new DWORD;
*threadParam = connIdx; *threadParam = connIdx;
HANDLE hThread = CreateThread(NULL, 0, RecvThreadProc, threadParam, 0, NULL); HANDLE hThread = CreateThread(NULL, 0, RecvThreadProc, threadParam, 0, NULL);
@@ -466,8 +495,8 @@ DWORD WINAPI WinsockNetLayer::AcceptThreadProc(LPVOID param)
DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param) DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param)
{ {
DWORD connIdx = *(DWORD *)param; DWORD connIdx = *(DWORD*)param;
delete (DWORD *)param; delete (DWORD*)param;
EnterCriticalSection(&s_connectionsLock); EnterCriticalSection(&s_connectionsLock);
if (connIdx >= (DWORD)s_connections.size()) if (connIdx >= (DWORD)s_connections.size())
@@ -479,7 +508,8 @@ DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param)
BYTE clientSmallId = s_connections[connIdx].smallId; BYTE clientSmallId = s_connections[connIdx].smallId;
LeaveCriticalSection(&s_connectionsLock); LeaveCriticalSection(&s_connectionsLock);
BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE]; std::vector<BYTE> recvBuf;
recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE);
while (s_active) while (s_active)
{ {
@@ -490,33 +520,47 @@ DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param)
break; break;
} }
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3]; int packetSize =
((uint32_t)header[0] << 24) |
((uint32_t)header[1] << 16) |
((uint32_t)header[2] << 8) |
((uint32_t)header[3]);
if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE) if (packetSize <= 0 || packetSize > WIN64_NET_MAX_PACKET_SIZE)
{ {
app.DebugPrintf("Win64 LAN: Invalid packet size %d from client smallId=%d\n", packetSize, clientSmallId); app.DebugPrintf("Win64 LAN: Invalid packet size %d from client smallId=%d (max=%d)\n",
packetSize,
clientSmallId,
(int)WIN64_NET_MAX_PACKET_SIZE);
break; break;
} }
if (!RecvExact(sock, recvBuf, packetSize)) if ((int)recvBuf.size() < packetSize)
{
recvBuf.resize(packetSize);
app.DebugPrintf("Win64 LAN: Resized host recv buffer to %d bytes for client smallId=%d\n", packetSize, clientSmallId);
}
if (!RecvExact(sock, &recvBuf[0], packetSize))
{ {
app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (body)\n", clientSmallId); app.DebugPrintf("Win64 LAN: Client smallId=%d disconnected (body)\n", clientSmallId);
break; break;
} }
HandleDataReceived(clientSmallId, s_hostSmallId, recvBuf, packetSize); HandleDataReceived(clientSmallId, s_hostSmallId, &recvBuf[0], packetSize);
} }
delete[] recvBuf;
EnterCriticalSection(&s_connectionsLock); EnterCriticalSection(&s_connectionsLock);
for (size_t i = 0; i < s_connections.size(); i++) for (size_t i = 0; i < s_connections.size(); i++)
{ {
if (s_connections[i].smallId == clientSmallId) if (s_connections[i].smallId == clientSmallId)
{ {
s_connections[i].active = false; s_connections[i].active = false;
closesocket(s_connections[i].tcpSocket); if (s_connections[i].tcpSocket != INVALID_SOCKET)
s_connections[i].tcpSocket = INVALID_SOCKET; {
closesocket(s_connections[i].tcpSocket);
s_connections[i].tcpSocket = INVALID_SOCKET;
}
break; break;
} }
} }
@@ -529,7 +573,7 @@ DWORD WINAPI WinsockNetLayer::RecvThreadProc(LPVOID param)
return 0; return 0;
} }
bool WinsockNetLayer::PopDisconnectedSmallId(BYTE *outSmallId) bool WinsockNetLayer::PopDisconnectedSmallId(BYTE* outSmallId)
{ {
bool found = false; bool found = false;
EnterCriticalSection(&s_disconnectLock); EnterCriticalSection(&s_disconnectLock);
@@ -550,9 +594,26 @@ void WinsockNetLayer::PushFreeSmallId(BYTE smallId)
LeaveCriticalSection(&s_freeSmallIdLock); LeaveCriticalSection(&s_freeSmallIdLock);
} }
void WinsockNetLayer::CloseConnectionBySmallId(BYTE smallId)
{
EnterCriticalSection(&s_connectionsLock);
for (size_t i = 0; i < s_connections.size(); i++)
{
if (s_connections[i].smallId == smallId && s_connections[i].active && s_connections[i].tcpSocket != INVALID_SOCKET)
{
closesocket(s_connections[i].tcpSocket);
s_connections[i].tcpSocket = INVALID_SOCKET;
app.DebugPrintf("Win64 LAN: Force-closed TCP connection for smallId=%d\n", smallId);
break;
}
}
LeaveCriticalSection(&s_connectionsLock);
}
DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param) DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
{ {
BYTE *recvBuf = new BYTE[WIN64_NET_RECV_BUFFER_SIZE]; std::vector<BYTE> recvBuf;
recvBuf.resize(WIN64_NET_RECV_BUFFER_SIZE);
while (s_active && s_hostConnectionSocket != INVALID_SOCKET) while (s_active && s_hostConnectionSocket != INVALID_SOCKET)
{ {
@@ -565,28 +626,34 @@ DWORD WINAPI WinsockNetLayer::ClientRecvThreadProc(LPVOID param)
int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3]; int packetSize = (header[0] << 24) | (header[1] << 16) | (header[2] << 8) | header[3];
if (packetSize <= 0 || packetSize > WIN64_NET_RECV_BUFFER_SIZE) if (packetSize <= 0 || packetSize > WIN64_NET_MAX_PACKET_SIZE)
{ {
app.DebugPrintf("Win64 LAN: Invalid packet size %d from host\n", packetSize); app.DebugPrintf("Win64 LAN: Invalid packet size %d from host (max=%d)\n",
packetSize,
(int)WIN64_NET_MAX_PACKET_SIZE);
break; break;
} }
if (!RecvExact(s_hostConnectionSocket, recvBuf, packetSize)) if ((int)recvBuf.size() < packetSize)
{
recvBuf.resize(packetSize);
app.DebugPrintf("Win64 LAN: Resized client recv buffer to %d bytes\n", packetSize);
}
if (!RecvExact(s_hostConnectionSocket, &recvBuf[0], packetSize))
{ {
app.DebugPrintf("Win64 LAN: Disconnected from host (body)\n"); app.DebugPrintf("Win64 LAN: Disconnected from host (body)\n");
break; break;
} }
HandleDataReceived(s_hostSmallId, s_localSmallId, recvBuf, packetSize); HandleDataReceived(s_hostSmallId, s_localSmallId, &recvBuf[0], packetSize);
} }
delete[] recvBuf;
s_connected = false; s_connected = false;
return 0; return 0;
} }
bool WinsockNetLayer::StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer) bool WinsockNetLayer::StartAdvertising(int gamePort, const wchar_t* hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer)
{ {
if (s_advertising) return true; if (s_advertising) return true;
if (!s_initialized) return false; if (!s_initialized) return false;
@@ -614,7 +681,7 @@ bool WinsockNetLayer::StartAdvertising(int gamePort, const wchar_t *hostName, un
} }
BOOL broadcast = TRUE; BOOL broadcast = TRUE;
setsockopt(s_advertiseSock, SOL_SOCKET, SO_BROADCAST, (const char *)&broadcast, sizeof(broadcast)); setsockopt(s_advertiseSock, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(broadcast));
s_advertising = true; s_advertising = true;
s_advertiseThread = CreateThread(NULL, 0, AdvertiseThreadProc, NULL, 0, NULL); s_advertiseThread = CreateThread(NULL, 0, AdvertiseThreadProc, NULL, 0, NULL);
@@ -669,8 +736,8 @@ DWORD WINAPI WinsockNetLayer::AdvertiseThreadProc(LPVOID param)
Win64LANBroadcast data = s_advertiseData; Win64LANBroadcast data = s_advertiseData;
LeaveCriticalSection(&s_advertiseLock); LeaveCriticalSection(&s_advertiseLock);
int sent = sendto(s_advertiseSock, (const char *)&data, sizeof(data), 0, int sent = sendto(s_advertiseSock, (const char*)&data, sizeof(data), 0,
(struct sockaddr *)&broadcastAddr, sizeof(broadcastAddr)); (struct sockaddr*)&broadcastAddr, sizeof(broadcastAddr));
if (sent == SOCKET_ERROR && s_advertising) if (sent == SOCKET_ERROR && s_advertising)
{ {
@@ -696,7 +763,7 @@ bool WinsockNetLayer::StartDiscovery()
} }
BOOL reuseAddr = TRUE; BOOL reuseAddr = TRUE;
setsockopt(s_discoverySock, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuseAddr, sizeof(reuseAddr)); setsockopt(s_discoverySock, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseAddr, sizeof(reuseAddr));
struct sockaddr_in bindAddr; struct sockaddr_in bindAddr;
memset(&bindAddr, 0, sizeof(bindAddr)); memset(&bindAddr, 0, sizeof(bindAddr));
@@ -704,7 +771,7 @@ bool WinsockNetLayer::StartDiscovery()
bindAddr.sin_port = htons(WIN64_LAN_DISCOVERY_PORT); bindAddr.sin_port = htons(WIN64_LAN_DISCOVERY_PORT);
bindAddr.sin_addr.s_addr = INADDR_ANY; bindAddr.sin_addr.s_addr = INADDR_ANY;
if (::bind(s_discoverySock, (struct sockaddr *)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR) if (::bind(s_discoverySock, (struct sockaddr*)&bindAddr, sizeof(bindAddr)) == SOCKET_ERROR)
{ {
app.DebugPrintf("Win64 LAN: Discovery bind failed: %d\n", WSAGetLastError()); app.DebugPrintf("Win64 LAN: Discovery bind failed: %d\n", WSAGetLastError());
closesocket(s_discoverySock); closesocket(s_discoverySock);
@@ -713,7 +780,7 @@ bool WinsockNetLayer::StartDiscovery()
} }
DWORD timeout = 500; DWORD timeout = 500;
setsockopt(s_discoverySock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout)); setsockopt(s_discoverySock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
s_discovering = true; s_discovering = true;
s_discoveryThread = CreateThread(NULL, 0, DiscoveryThreadProc, NULL, 0, NULL); s_discoveryThread = CreateThread(NULL, 0, DiscoveryThreadProc, NULL, 0, NULL);
@@ -763,7 +830,7 @@ DWORD WINAPI WinsockNetLayer::DiscoveryThreadProc(LPVOID param)
int senderLen = sizeof(senderAddr); int senderLen = sizeof(senderAddr);
int recvLen = recvfrom(s_discoverySock, recvBuf, sizeof(recvBuf), 0, int recvLen = recvfrom(s_discoverySock, recvBuf, sizeof(recvBuf), 0,
(struct sockaddr *)&senderAddr, &senderLen); (struct sockaddr*)&senderAddr, &senderLen);
if (recvLen == SOCKET_ERROR) if (recvLen == SOCKET_ERROR)
{ {
@@ -773,7 +840,7 @@ DWORD WINAPI WinsockNetLayer::DiscoveryThreadProc(LPVOID param)
if (recvLen < (int)sizeof(Win64LANBroadcast)) if (recvLen < (int)sizeof(Win64LANBroadcast))
continue; continue;
Win64LANBroadcast *broadcast = (Win64LANBroadcast *)recvBuf; Win64LANBroadcast* broadcast = (Win64LANBroadcast*)recvBuf;
if (broadcast->magic != WIN64_LAN_BROADCAST_MAGIC) if (broadcast->magic != WIN64_LAN_BROADCAST_MAGIC)
continue; continue;
@@ -841,4 +908,4 @@ DWORD WINAPI WinsockNetLayer::DiscoveryThreadProc(LPVOID param)
return 0; return 0;
} }
#endif #endif

View File

@@ -1,3 +1,5 @@
// Code implemented by LCEMP, credit if used on other repos
// https://github.com/LCEMP/LCEMP
#pragma once #pragma once
#ifdef _WINDOWS64 #ifdef _WINDOWS64
@@ -12,6 +14,7 @@
#define WIN64_NET_DEFAULT_PORT 25565 #define WIN64_NET_DEFAULT_PORT 25565
#define WIN64_NET_MAX_CLIENTS 7 #define WIN64_NET_MAX_CLIENTS 7
#define WIN64_NET_RECV_BUFFER_SIZE 65536 #define WIN64_NET_RECV_BUFFER_SIZE 65536
#define WIN64_NET_MAX_PACKET_SIZE (4 * 1024 * 1024)
#define WIN64_LAN_DISCOVERY_PORT 25566 #define WIN64_LAN_DISCOVERY_PORT 25566
#define WIN64_LAN_BROADCAST_MAGIC 0x4D434C4E #define WIN64_LAN_BROADCAST_MAGIC 0x4D434C4E
@@ -63,10 +66,10 @@ public:
static void Shutdown(); static void Shutdown();
static bool HostGame(int port); static bool HostGame(int port);
static bool JoinGame(const char *ip, int port); static bool JoinGame(const char* ip, int port);
static bool SendToSmallId(BYTE targetSmallId, const void *data, int dataSize); static bool SendToSmallId(BYTE targetSmallId, const void* data, int dataSize);
static bool SendOnSocket(SOCKET sock, const void *data, int dataSize); static bool SendOnSocket(SOCKET sock, const void* data, int dataSize);
static bool IsHosting() { return s_isHost; } static bool IsHosting() { return s_isHost; }
static bool IsConnected() { return s_connected; } static bool IsConnected() { return s_connected; }
@@ -77,12 +80,13 @@ public:
static SOCKET GetSocketForSmallId(BYTE smallId); static SOCKET GetSocketForSmallId(BYTE smallId);
static void HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsigned char *data, unsigned int dataSize); static void HandleDataReceived(BYTE fromSmallId, BYTE toSmallId, unsigned char* data, unsigned int dataSize);
static bool PopDisconnectedSmallId(BYTE *outSmallId); static bool PopDisconnectedSmallId(BYTE* outSmallId);
static void PushFreeSmallId(BYTE smallId); static void PushFreeSmallId(BYTE smallId);
static void CloseConnectionBySmallId(BYTE smallId);
static bool StartAdvertising(int gamePort, const wchar_t *hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer); static bool StartAdvertising(int gamePort, const wchar_t* hostName, unsigned int gameSettings, unsigned int texPackId, unsigned char subTexId, unsigned short netVer);
static void StopAdvertising(); static void StopAdvertising();
static void UpdateAdvertisePlayerCount(BYTE count); static void UpdateAdvertisePlayerCount(BYTE count);
static void UpdateAdvertiseJoinable(bool joinable); static void UpdateAdvertiseJoinable(bool joinable);

View File

@@ -10,46 +10,11 @@
#include "..\..\Minecraft.World\BiomeSource.h" #include "..\..\Minecraft.World\BiomeSource.h"
#include "..\..\Minecraft.World\LevelType.h" #include "..\..\Minecraft.World\LevelType.h"
wstring g_playerName;
CConsoleMinecraftApp app; CConsoleMinecraftApp app;
static void LoadPlayerName()
{
if (!g_playerName.empty()) return;
g_playerName = L"Windows";
char exePath[MAX_PATH] = {};
GetModuleFileNameA(NULL, exePath, MAX_PATH);
char *lastSlash = strrchr(exePath, '\\');
if (lastSlash) *(lastSlash + 1) = '\0';
char filePath[MAX_PATH] = {};
_snprintf_s(filePath, sizeof(filePath), _TRUNCATE, "%susername.txt", exePath);
FILE *f = NULL;
if (fopen_s(&f, filePath, "r") == 0 && f)
{
char buf[128] = {};
if (fgets(buf, sizeof(buf), f))
{
int len = (int)strlen(buf);
while (len > 0 && (buf[len-1] == '\n' || buf[len-1] == '\r' || buf[len-1] == ' '))
buf[--len] = '\0';
if (len > 0)
{
wchar_t wbuf[128] = {};
mbstowcs(wbuf, buf, 127);
g_playerName = wbuf;
}
}
fclose(f);
}
}
CConsoleMinecraftApp::CConsoleMinecraftApp() : CMinecraftApp() CConsoleMinecraftApp::CConsoleMinecraftApp() : CMinecraftApp()
{ {
m_bShutdown = false; m_bShutdown = false;
LoadPlayerName();
} }
void CConsoleMinecraftApp::SetRichPresenceContext(int iPad, int contextId) void CConsoleMinecraftApp::SetRichPresenceContext(int iPad, int contextId)
@@ -110,8 +75,8 @@ void CConsoleMinecraftApp::TemporaryCreateGameStart()
Minecraft *pMinecraft=Minecraft::GetInstance(); Minecraft *pMinecraft=Minecraft::GetInstance();
app.ReleaseSaveThumbnail(); app.ReleaseSaveThumbnail();
ProfileManager.SetLockedProfile(0); ProfileManager.SetLockedProfile(0);
LoadPlayerName(); extern wchar_t g_Win64UsernameW[17];
pMinecraft->user->name = g_playerName; pMinecraft->user->name = g_Win64UsernameW;
app.ApplyGameSettingsChanged(0); app.ApplyGameSettingsChanged(0);
////////////////////////////////////////////////////////////////////////////////////////////// From CScene_MultiGameJoinLoad::OnInit ////////////////////////////////////////////////////////////////////////////////////////////// From CScene_MultiGameJoinLoad::OnInit

View File

@@ -85,11 +85,12 @@ BOOL g_bWidescreen = TRUE;
int g_iScreenWidth = 1920; int g_iScreenWidth = 1920;
int g_iScreenHeight = 1080; int g_iScreenHeight = 1080;
char g_Win64Username[17] = { 0 };
wchar_t g_Win64UsernameW[17] = { 0 };
UINT g_ScreenWidth = 1920; UINT g_ScreenWidth = 1920;
UINT g_ScreenHeight = 1080; UINT g_ScreenHeight = 1080;
char g_Win64Username[17] = { 0 };
wchar_t g_Win64UsernameW[17] = { 0 };
// Fullscreen toggle state // Fullscreen toggle state
static bool g_isFullscreen = false; static bool g_isFullscreen = false;
static WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) }; static WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) };
@@ -765,36 +766,41 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
//g_iScreenHeight = 544; //g_iScreenHeight = 544;
} }
char cmdLineA[1024]; // Default username will be "Windows"
strncpy_s(cmdLineA, sizeof(cmdLineA), lpCmdLine, _TRUNCATE); strncpy_s(g_Win64Username, sizeof(g_Win64Username), "Windows", _TRUNCATE);
char* nameArg = strstr(cmdLineA, "-name "); char exePath[MAX_PATH] = {};
if (nameArg) GetModuleFileNameA(NULL, exePath, MAX_PATH);
char* lastSlash = strrchr(exePath, '\\');
if (lastSlash) *(lastSlash + 1) = '\0';
char filePath[MAX_PATH] = {};
_snprintf_s(filePath, sizeof(filePath), _TRUNCATE, "%susername.txt", exePath);
FILE* f = nullptr;
if (fopen_s(&f, filePath, "r") == 0 && f)
{ {
nameArg += 6; char buf[128] = {};
while (*nameArg == ' ') nameArg++; if (fgets(buf, sizeof(buf), f))
char nameBuf[17]; {
int n = 0; int len = (int)strlen(buf);
while (nameArg[n] && nameArg[n] != ' ' && n < 16) { nameBuf[n] = nameArg[n]; n++; } while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r' || buf[len - 1] == ' '))
nameBuf[n] = 0; buf[--len] = '\0';
strncpy_s(g_Win64Username, 17, nameBuf, _TRUNCATE);
if (len > 0)
{
strncpy_s(g_Win64Username, sizeof(g_Win64Username), buf, _TRUNCATE);
}
}
fclose(f);
} }
} }
if (g_Win64Username[0] == 0) if (g_Win64Username[0] == 0)
{ {
DWORD sz = 17; DWORD sz = 17;
static bool seeded = false; if (!GetUserNameA(g_Win64Username, &sz))
if (!seeded) strncpy_s(g_Win64Username, 17, "Player", _TRUNCATE);
{
seeded = true;
srand((unsigned int)time(NULL));
}
int r = rand() % 10000; // 0<>9999
snprintf(g_Win64Username, 17, "Player%04d", r);
g_Win64Username[16] = 0; g_Win64Username[16] = 0;
} }
@@ -1272,7 +1278,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
} }
} }
// F1 toggles the HUD, F3 toggles the debug console overlay, F11 toggles fullscreen // F1 toggles the HUD
if (KMInput.IsKeyPressed(VK_F1)) if (KMInput.IsKeyPressed(VK_F1))
{ {
int primaryPad = ProfileManager.GetPrimaryPad(); int primaryPad = ProfileManager.GetPrimaryPad();
@@ -1280,21 +1286,43 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
app.SetGameSettings(primaryPad, eGameSetting_DisplayHUD, displayHud ? 0 : 1); app.SetGameSettings(primaryPad, eGameSetting_DisplayHUD, displayHud ? 0 : 1);
app.SetGameSettings(primaryPad, eGameSetting_DisplayHand, displayHud ? 0 : 1); app.SetGameSettings(primaryPad, eGameSetting_DisplayHand, displayHud ? 0 : 1);
} }
// F3 toggles onscreen debug info
if (KMInput.IsKeyPressed(VK_F3)) if (KMInput.IsKeyPressed(VK_F3))
{ {
static bool s_debugConsole = false; if (Minecraft* pMinecraft = Minecraft::GetInstance())
s_debugConsole = !s_debugConsole; {
ui.ShowUIDebugConsole(s_debugConsole); if (pMinecraft->options)
{
pMinecraft->options->renderDebug = !pMinecraft->options->renderDebug;
}
}
} }
#ifdef _DEBUG_MENUS_ENABLED #ifdef _DEBUG_MENUS_ENABLED
if (KMInput.IsKeyPressed(VK_F4)) // F4 Open debug overlay
{ if (KMInput.IsKeyPressed(VK_F4))
ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_DebugOverlay, NULL, eUILayer_Debug); {
} if (Minecraft *pMinecraft = Minecraft::GetInstance())
{
if (pMinecraft->options &&
app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
{
ui.NavigateToScene(0, eUIScene_DebugOverlay, NULL, eUILayer_Debug);
}
}
}
// F6 Open debug console
if (KMInput.IsKeyPressed(VK_F6))
{
static bool s_debugConsole = false;
s_debugConsole = !s_debugConsole;
ui.ShowUIDebugConsole(s_debugConsole);
}
#endif #endif
// F11 Toggle fullscreen
if (KMInput.IsKeyPressed(VK_F11)) if (KMInput.IsKeyPressed(VK_F11))
{ {
ToggleFullscreen(); ToggleFullscreen();
@@ -1312,33 +1340,6 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
} }
} }
#ifdef _DEBUG_MENUS_ENABLED
// F3 toggles onscreen debug info
if (KMInput.IsKeyPressed(VK_F3))
{
if (Minecraft* pMinecraft = Minecraft::GetInstance())
{
if (pMinecraft->options && app.DebugSettingsOn())
{
pMinecraft->options->renderDebug = !pMinecraft->options->renderDebug;
}
}
}
// F4 opens debug overlay
if (KMInput.IsKeyPressed(VK_F4))
{
if (Minecraft* pMinecraft = Minecraft::GetInstance())
{
if (pMinecraft->options && app.DebugSettingsOn() &&
app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
{
ui.NavigateToScene(0, eUIScene_DebugOverlay, NULL, eUILayer_Debug);
}
}
}
#endif
#if 0 #if 0
// has the game defined profile data been changed (by a profile load) // has the game defined profile data been changed (by a profile load)
if(app.uiGameDefinedDataChangedBitmask!=0) if(app.uiGameDefinedDataChangedBitmask!=0)

View File

@@ -627,6 +627,7 @@ void Player::ride(shared_ptr<Entity> e)
return; return;
} }
this->abilities.flying = false;
LivingEntity::ride(e); LivingEntity::ride(e);
} }

View File

@@ -33,13 +33,7 @@ Basic LAN multiplayer is available on the Windows build
- Other players on the same LAN can discover the session from the in-game Join Game menu - Other players on the same LAN can discover the session from the in-game Join Game menu
- Game connections use TCP port `25565` by default - Game connections use TCP port `25565` by default
- LAN discovery uses UDP port `25566` - LAN discovery uses UDP port `25566`
- You can override your in-game username at launch with `-name` - You can override your in-game username at launch with `username.txt`
Example:
```powershell
Minecraft.Client.exe -name Steve
```
This feature is based on [LCEMP](https://github.com/LCEMP/LCEMP/) This feature is based on [LCEMP](https://github.com/LCEMP/LCEMP/)
@@ -51,7 +45,7 @@ This feature is based on [LCEMP](https://github.com/LCEMP/LCEMP/)
- **Sprint**: `Ctrl` (Hold) or Double-tap `W` - **Sprint**: `Ctrl` (Hold) or Double-tap `W`
- **Inventory**: `E` - **Inventory**: `E`
- **Drop Item**: `Q` - **Drop Item**: `Q`
- **Crafting**: `C` - **Crafting**: `C` Use `Q` and `E` to move through tabs (cycles Left/Right)
- **Toggle View (FPS/TPS)**: `F5` - **Toggle View (FPS/TPS)**: `F5`
- **Fullscreen**: `F11` - **Fullscreen**: `F11`
- **Pause Menu**: `Esc` - **Pause Menu**: `Esc`
@@ -64,6 +58,7 @@ This feature is based on [LCEMP](https://github.com/LCEMP/LCEMP/)
- **Toggle HUD**: `F1` - **Toggle HUD**: `F1`
- **Toggle Debug Info**: `F3` - **Toggle Debug Info**: `F3`
- **Open Debug Overlay**: `F4` - **Open Debug Overlay**: `F4`
- **Toggle Debug Console**: `F6`
## Build & Run ## Build & Run